TL;DR 太长不看我想看官网
FFMpeg 使用已经有一段时间,这里对其作了一些整理,以备不时之需。
- FFMpeg 官方文档 Link
- FFMpeg linux pre-built binary Link
- Ubuntu 简易安装
1
| apt-get update && apt-get install ffmpeg
|
从源码编译
如果想用已经编译好的 binary,可以直接使用 apt-get 安装。
或者使用第三方已经编译好的库。
https://johnvansickle.com/ffmpeg/
如果希望自己编译的话可以参考这个链接
https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu
我的编译环境如下
1 2 3 4 5
| Ubuntu 18.04 CUDA 10.2 GNU Make 4.1 g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 cmake version 3.10.2
|
源码 & 依赖安装
首先从官网下载 ffmpeg 的源码,这里以 ffmpeg 4.4.3 为例(官方推荐使用 master 分支,请根据需求自行调整)
1 2 3
| wget https://ffmpeg.org/releases/ffmpeg-4.4.3.tar.xz
tar -xf ffmpeg-4.4.3.tar.xz
|
如果需要支持硬件编解码,我们还需安装/编译以下的包
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| git clone https://git.videolan.org/git/ffmpeg/nv-codec-headers.git
cd nv-codec-headers
⚠️ 由于cuda 版本会有不同的地方,请根据自己的情况决定到底应该使用哪个branch cat README git branch -a
git checkout -b sdk-10.0 remotes/origin/old/sdk/10.0
make sudo make install
|
安装一些第三方的依赖包,这部分需要根据具体的需求来,基本依赖和一些编码库是必须的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| apt-get install nasm yasm apt-get install libx264-dev apt-get install libx265-dev libnuma-dev apt-get install libfdk-aac-dev
apt-get install libharfbuzz-dev apt-get install libfreetype6-dev
apt-get install libopenexr-dev
apt-get install -y libx264-dev libx265-dev libnuma-dev libfdk-aac-dev libharfbuzz-dev \ libfreetype6-dev libopenexr-dev libtbb-dev
|
编译过程
紧接着我们写一个 compile_ffmpeg.sh。
大部分情况下这样编译可以满足大部分的需要。
如果需要额外的包或者功能,需要参考官网的说明来添加/安装对应的包。
https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #!/bin/bash set -e INSTALL_PREFIX="/path/to/your/ffmpeg_install_path"
cd ffmpeg-4.4.3 ./configure \ --prefix="${INSTALL_PREFIX}" \ --pkg-config-flags="--static" \ --extra-libs="-lpthread -lm" \ --ld="g++" \ --bindir="${INSTALL_PREFIX}/bin" \ --enable-libfreetype \ --enable-libharfbuzz \ --enable-shared \ --enable-gpl \ --enable-libx264 \ --enable-libx265 \ --enable-libfdk-aac \ --enable-ffnvcodec \ --enable-cuda-nvcc \ --enable-cuvid \ --enable-nvenc \ --extra-cflags=-I/usr/local/cuda/include \ --extra-ldflags=-L/usr/local/cuda/lib64 \ --nvccflags="-gencode arch=compute_70,code=sm_70 -O2" \ --enable-nonfree
make -j$(nproc) make install
exit 0
|
如果发现有 ERROR: failed checking for nvcc. 的错误
需要添加一条flag,这个需要根据具体的显卡型号决定
1 2 3
| --pkgconfigdir="/usr/local/lib/pkgconfig" --nvccflags="-gencode arch=compute_70,code=sm_70 -O2"
|
如果不需要硬件编解码,可以把下面这些选项去掉
1 2 3 4 5 6 7
| --enable-ffnvcodec \ --enable-cuda-nvcc \ --enable-cuvid \ --enable-nvenc \ --extra-cflags=-I/usr/local/cuda/include \ --extra-ldflags=-L/usr/local/cuda/lib64 \ --nvccflags="-gencode arch=compute_70,code=sm_70 -O2" \
|
补充说明
编译好以后的包会输出到指定的 --prefix
下,你可以使用 ldd 来确认具体引用了什么包。
ffmpeg 如果要支持硬件加速的话需要确认你的系统里有对应的 so 包,具体来说是以下这两个
1 2 3
| ll /usr/lib/x86_64-linux-gnu/ |grep nv
|
FFMpeg CLI 使用说明
这里是 ffmpeg 命令行的一些常用选项说明。
基本使用
1 2 3 4 5
| 使用 -i 参数 ffmpeg -i ${input} ${output}
使用 -y 参数可以默认跳过覆盖确认 ffmpeg -y -i ${input} ${output}
|
-vf 参数的简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| 添加 -vf 选项使其能够控制更多
ffmpeg -i ${input} -vf scale=1080:1920 ${output}
scale 控制分辨率
ffmpeg -i ${input} -vf transpose=1 ${output}
transpose 控制旋转和翻转 0-逆时针旋转90度,垂直翻转。这也是默认设置。 1-顺时针旋转90度。 2-逆时针旋转90度。 3-顺时针旋转90度,垂直翻转。
ffmpeg -i ${input} -vf reverse ${output}
reverse 视频倒放
... 还有一些其他的使用方式,这里列出一些其他 -vf 后的使用参数
pad={new_width}:{new_height}:{position_x}:{position_y}:{color} e.g. -vf pad=1920:1080:12:30:white 生成一个 1920x1080 的画布,将原视频贴在 x=12 y=30 的位置(对齐左上角),其它部分补白色
crop={width}:{height}:{x}:{y} e.g. -vf crop=500:400:210:220 以 x=210 y=220 为左上角点,裁出 500x400 的位置
多个 vf filter 可以按照处理的先后顺序相连,排列成一个进行处理
e.g. ffmpeg -i {input} \ -vf pad=1920:1080:12:30:white,crop=500:400:210:220,scale=300:300 \ {output}
先 padding,再裁切,最后 scale
|
编解码器控制
1 2 3 4 5 6 7 8
| -c:v / -vcodec -a:v / -acodec 视频编码、音频编码
如需视频硬解,则可以参考这个参数 -c:v h264_nvenc
ffmpeg -i ${input} -c:v h264 ${output}
|
清晰度设置
1 2 3 4 5 6 7 8 9 10 11 12
| 有一些编码器会带有编码清晰度设置 直接使用默认设置可能不够清晰
-crf 15 设定 crf,在 15 ~ 18 之间可以保证视觉无损 仅在使用 h264 或者 libx264 有效,h264_nvenc 无效
在使用 h264_nvenc 的时候可以考虑使用 preset,level,qp 等其它参数控制
-b:v 设定视频码率 1080p 4M ~ 8M 左右为合理区间 -b:a 设定音频码率 一般不作设置
ffmpeg -i ${input} -c:v h264 -crf 15 ${output}
|
色彩格式设置
1 2 3 4
| 更改视频的色彩空间需要指定 -pix_fmt bgr
ffmpeg -i ${input} -pix_fmt yuv420p ${output}
|
逐行扫描 / 隔行扫描
一般来说不会用到这个选项,
如果有出现需要从隔行转为逐行的情况的话,可以使用以下的选项。
1 2
| e.g. 1080i to 1080p ffmpeg -i <input> -deinterlace <output>
|
如果要查看视频是否已经是隔行或是逐行扫描了,则需要用到 mediainfo。
1
| mediainfo some_video.mp4
|
时间操作
1 2 3 4 5 6 7 8 9 10
| 截取时间段 -ss 起始时间 -t 持续时间 -to 到某一时间
比如截取 10 ~ 30 s 这段时间,以下写法均可
ffmpeg -i ${input} -ss 10 -to 30 ${output} ffmpeg -i ${input} -ss 10 -t 20 ${output} ffmpeg -i ${input} -ss 00:00:10 -to 00:00:30 ${output}
|
帧率控制
1 2
| 使用 -r 参数 ffmpeg -i ${input} -r 25 ${output}
|
倍速播放
1 2 3 4 5 6 7
| 设置 PTS 和 atempo 即可,不同的倍速要设置不同的倍率,下面是2倍速的例子
ffmpeg -i ${input} \ -filter_complex "[0:v]setpts=2*PTS[v];[0:a]atempo=0.5[a]" \ -map "[v]" -map "[a]" \ ${output}
|
音视频轨道的概念
除了特殊的视频以外,一般来说一个视频有一个音频轨道和一个视频轨道。
可以通过设定这些轨道达到一些比较复杂的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 使用 -map 参数可以控制对应的输入输出
将 第 0 个 文件的 视频轨道 映射到 第 0 个 输出文件上 -map 0:v:0
将 第 1 个 文件的 音频轨道 映射到 第 0 个 输出文件上 -map 1:a:0
提取视频 A 的视频和视频 B 的音频,输出 ffmpeg -i A.mp4 -i B.mp4 -map 0:v:0 -map 1:a:0 output.mp4
将 视频/音频 指定为空可以提取纯音频/视频 -vn 指定空视频 -an 指定空音频
ffmpeg -i A.mp4 -an output.mp4 ffmepg -i A.mp4 -vn output.wav
|
其它的补充操作
有时候我们需要查看 ffmpeg 的一些编解码器信息。
使用 grep 选取对应的编解码器以后可以判断是否支持 GPU 硬件加速。
同时,如果希望使用 GPU 加速,通用的做法是指定硬件加速和指定特定的编码/解码器。
1 2
| 在省略号处补充别的参数 ffmpeg -hwaccel cuvid -i ${input} ... -c:v nvenc_h264 ... ${output}
|
🌰 FFMpeg CLI 的例子
由于 ffmpeg 的功能比较复杂,不可能面面俱到,上述是一些简单的用法指南。
一些复杂的操作还需要使用 filter_complex
这个参数来设置。
如果一一介绍篇幅很长,比较建议去查看官方文档。
这里介绍一些我自己会用到的例子,大伙可以参考一下
合并 Alpha 通道
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| INPUT=$1 ALPHA=$2 COLOR=78FF78 SIZE=$3 OUTPUT=$4
ffmpeg -i ${INPUT} -i ${ALPHA} \ -filter_complex "color=s=${SIZE}:c=#${COLOR}[bg];[0:v][1:v]alphamerge[b1];[bg][b1]overlay=format=auto:shortest=1[b2]" \ -map [b2] \ -y \ -r 25 \ -c:v h264 \ -crf 15 \ -shortest \ ${OUTPUT}
|
如果合并以后希望用一张图片作为背景的话
1 2 3 4 5
| ffmpeg -i origin.mp4 -i alpha.mp4 \ -i path_to_img.png \ -filter_complex "[0:v][1:v]alphamerge[b1];[2:v][b1]overlay[b2]" \ -map [b2] -y -crf 15 -pix_fmt yuv420p \ output.mp4
|
拆分 Alpha 通道
1 2 3
| ffmpeg -i input.mov \ -vf "[0:v] format=rgba, split [T1], fifo, lutrgb=r=minval:g=minval:b=minval, [T2] overlay [out]; [T1] fifo, lutrgb=r=maxval:g=maxval:b=maxval [T2]" \ out.mov
|
如果发现黑色和白色颜色相反,可以使用另一个
1 2 3
| ffmpeg -i input.mov \ -vf "[0:v] format=rgba, split [T1], fifo, lutrgb=r=maxval:g=maxval:b=maxval, [T2] overlay [out]; [T1] fifo, lutrgb=r=minval:g=minval:b=minval [T2]" \ out.mov
|
从绿底视频中提取 alpha
使用 chroma key 可以比较轻松办到这点。注意 chromakey 后填写的具体数值。
如果边缘效果不佳,可以考虑增加颜色过滤相似度和模糊程度(下面例子中的 0.3 和 0.05)。
1 2 3 4 5 6
| INPUT=$1 OUTPUT=$2
ffmpeg -i ${INPUT} \ -vf "[0:v]chromakey=0x00FF00:0.3:0.05[ckout];[ckout]format=rgba, split [T1], fifo, lutrgb=r=maxval:g=maxval:b=maxval, [T2] overlay [out]; [T1] fifo, lutrgb=r=minval:g=minval:b=minval [T2]" \ ${OUTPUT}
|
时间尺度上合并两个视频
1 2 3 4 5 6 7
| ffmpeg -i a.mp4 -i b.mp4 \ -filter_complex '[0:0] [1:0] concat=n=2:v=1 [v]' \ -map '[v]' \ -crf 15 \ concat.mp4
|
生成纯色背景
1 2 3 4
| color=0x78FF78 size=1080x1920
ffmpeg -f lavfi -i color=${color}:${size} -frames:v 1 output.png
|
某些文件头的设置
1
| ffmpeg -i input.mp4 -movflags faststart -c copy output.mp4
|
转换 color_range
从 limited range 转换为 full range
1 2 3 4 5 6
| alpha_path=$1
ffmpeg -v error -stats -i ${alpha_path} \ -vf scale=in_range=limited:out_range=full \ -pix_fmt yuv420p -color_range tv -y \ -crf 15 convert_alpha.mp4
|