FFmpeg 是视频处理最常用的开源软件。功能强大,用途广泛,大量用于视频网站和商业软件(比如 Youtube 和 iTunes),也是许多音频和视频格式的标准编码/解码实现。

Windows 下日常少量使用时建议使用 小丸工具箱,一款 x264、ffmpeg 等命令行程序的图形界面,对于应用更加简单、轻松,主要功能(来自官网介绍):

  • 高质量的H264+AAC视频压制
  • ASS/SRT字幕内嵌到视频
  • AAC/WAV/FLAC/ALAC音频转换
  • MP4/MKV/FLV的无损抽取和封装

小丸工具箱只是一个 GUI,可以操作 x264、MP4Box、ffmpeg 等软件。不过其自带 taro 或 小7 编译的 x264 库,可直接用于压制视频。

一、FFmpeg 安装

Linux 下建议使用 Conda 进行安装,方便快捷,无需管理员权限、编译、配置、添加环境变量等操作。安装命令如下:

1
conda install ffmpeg -c conda-forge

二、FFmpeg 常用参数

2.1 基本参数

常用参数:

  • -i:指定输入文件名,也可以指定: 0.0(屏幕录制)或摄像头
  • -f:指定格式(音频或视频格式)
  • -ss:指定开始时间(s), [-]hh:mm:ss[.xxx]的格式也支持
  • -y:覆盖已有文件
  • -formats:输出所有可用格式
  • -t:记录时长为t
  • -dframes:设置要记录的帧数

2.2 视频参数

常用参数:

  • -b:指定比特率(bits/s)
  • -vb:指定视频比特率(bits/s)
  • -r:设置帧速率(fps),非标准桢率可能会导致音画不同步
  • -s:指定分辨率 (宽与高,如 1920x1080
  • -aspect:设置视频宽高比(4:3, 16:9 or 1.3333, 1.7777)
  • -vn:不处理视频(取消视频)
  • -vcodec:指定视频编解码器(’copy’ 表示复制视频流)

2.3 高级视频选项

常用参数:

  • -qscale:以<数值>质量为基础的VBR,取值0.01-255,越小质量越好

2.4 音频参数

常用参数:

  • -ab:设置单通道比特率(单位:bit/s),如果为双通道立体声,设置为 96k 时最后的音频比特率为 192 Kbps
  • -ar:设置音频采样率(单位:Hz)
  • -ac:设置声道数,1就是单声道,2就是立体声
  • -acodec:指定音频编码(’copy’ 表示复制音频流)
  • -an:不处理音频(取消音频)

三、常用应用

3.1 码率控制

码率:简单来说就是单位时间的文件体积,如 bpsbits per second (每秒的比特数)。一个视频的比特率(码率)可如下计算:
$$
比特率 = \frac{视频大小}{视频时长}
$$
对于一个 20 MB 时长为 1 分钟的视频文件:
$$
比特率 = \frac{20 \times 1024 \times 1024 \times 8}{60}\ \text{bps} = 2796203\ \text{bps} = 2731\ \text{Kbps}
$$
注意 1 Byte 和 1 bit 之间有个 8 的倍数关系,即 1 Byte = 8 bits。

一个视频文件的比特率又可分为视频比特率和音频比特率。音频比特率一般只有固定的几种,如 128 Kbps、256 Kbps 等。对于上述视频,如果音频比特率时 128 Kbps,那么视频比特率即为:2731 - 128 = 2603 Kbps。

码率控制常用参数:

  • -b:v-vb:指定视频比特率
  • -bufsize:设置码率控制缓冲器大小,减小视频整体的码率波动。
  • -minrate-maxrate:控制码率波动范围。
1
2
3
4
5
6
# 将高码率视频压缩至指定码率
ffmpeg -i input.mp4 -b:v 4000k output.mp4
# 设置码率控制缓冲器
ffmpeg -i input.mp4 -b:v 4000k -bufsize 4000k output.mp4
# 设置码率波动范围
ffmpeg -i input.mp4 -b:v 4000k -bufsize 4000k -maxrate 4500k output.mp4

3.2 视频尺寸(分辨率)修改

修改分辨率一般有 2 种方式

1、-s 参数直接指定:强制设置尺寸进行缩放

1
ffmpeg -i input.mp4 -s 1280x720 output.mp4

缺陷:如果原视频尺寸的比例与设置的尺寸比例不同,视频会发生变形。

2、-vf scale={} 参数指定长或宽,另一值设置为 -1,自动计算。

1
ffmpeg -i input.mp4 -vf scale=1280:-1 output.mp4 

如果期望与原视频比例相同(等比缩放),如上设置为 -1 另一边则会按照比例缩放,可保证视频画面不会变形。

3.3 视频压缩(x264 编码)

视频压缩是一个综合过程,可以通过很多方式实现,如:

  • 视频尺寸:减小视频分辨率,如将 1920x1080 的视频缩放到 1280x720
  • 视频编码:指定高压缩比的编码器:如将 -vcodec 指定为 libx264,甚至更新的 x265。
  • 音频编码-ab-b:a 降低音频编码比特率,通道数等,特殊情况下如不需要声音可以直接设置 -an 去掉音频。
  • 码率控制-vb-b:v 手动指定需要的码率。不过建议指定 crf 值控制码率,画质会更加均衡。

x264 编码器

一般在得到一个低压缩比的高码率视频时,主要需要靠 x264 编码器进行压缩。由于 x264 编码器的参数众多,各种参数间的配合复杂,一般建议直接使用 --preset 参数进行控制。

  • -preset: 编码器预设,主要控制编码的速度和质量间的平衡,包含的选项有:ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo 共 10 项,编码速度由快到慢,默认为 medium。
  • -crf:恒定速率因子模式,画质均衡但无法控制码率,适用于对画质有要求,文件大希奥没有要求的情况,范围为 0-51,默认值为23,数字越小质量越高。
  • -profile:v:指定编码器配置,一般不用设置。主要和压缩比有关(实时通信使用 baseline,流媒体使用 main,超清视频使用 high)
  • -level:v:编码器配置的限制,一般不用设置。一般情况下 1080P 及以下视频选用 4.1 即可

一种常用的操作为:

1
2
3
# -vcodec libx264 -preset slow -crf 24:x264 编码器设置及码率控制参数设置
# -vf "scale=1920:-1":指定输出分辨率,-1 表示等比缩放,自动计算
ffmpeg -i input.mp4 -vcodec libx264 -preset slow -crf 23 -vf "scale=1920:-1" output.mp4

一般来说,如果需要极大压缩比的视频,一味地增大 crf 到后面会极大地损失视频观感质量,还有一种简单有效地方法是减小视频画面地尺寸(减小分辨率)。当增大 crf 带来的体积压缩变得有限,进一步增大对视频影响质量较大时,往往减小分辨率带来的观感体验会好于继续增大 crf

因此,在需要极致压缩比视频时,可以灵活地调整 crf 和分辨率获得最好的视频压缩体验。一般来说,在其它参数固定的情况下,压缩视频时视频的宽度减小为以前的二分之一,那么视频文件的大小约为按原尺寸压缩的四分之一(等比缩放,按面积估算)。

3.4 视频关键帧提取

参考:Extracting the index of key frames from a video using ffmpeg

目前市场上主流的视频编码算法为 H264 编码,在 264 编码中把视频帧分为三种:

  • I 帧(Inter Frame):也叫关键帧,有完整的图像,其他两种帧没有完整的图像,都得依靠于 I 帧生成完成的图像。
  • P 帧(P-Frame)
  • B 帧(B-Frame)

在观看视频时,手动拉拽进度条,不一定就能定位到你定位的那一刻,因为那一帧并不是关键帧,会跑去离那一秒最近的一个关键帧。这在一些网络视频上会尤其明显,因为关键帧间隔设置比较大。

提取关键帧

在 ffmpeg 中可以通过指定 -vf select='eq(pict_type\,I)' 参数提取关键帧(I 帧)

  • -vf select='eq(pict_type\,I)':选择过滤器 select 会选择帧进行输出,{} 里的参数表示过滤图形的描述,包括过滤器常量 pict_type 和对应的类型 PICT_TYPE_I 表示I帧,即关键帧。
  • -vsync 2:阻止每个关键帧产生多余的拷贝
  • -f image2 key_%07d.jpeg-f 指定输出格式为 image2,后接保存图片的名字格式:%07d 表示从 1 开始编码,数字长度不足 7 位将从左侧补零补足 7 位。
1
ffmpeg -i input.mp4 -vf select='eq(pict_type\,I)' -vsync 2 -f image2 key_%07d.jpg

获取关键帧索引

1、使用 ffprobe 将关键帧输出重定向到 frame_indices.txt 文件:

1
ffprobe -select_streams v -show_frames -show_entries frame=pict_type -of csv bbb480.avi | grep -n I | cut -d ':' -f 1 > frame_indices.txt

frame_indices.txt 文件中保存的即为关键帧在视频中的帧索引位置。

2、将之前提取出来的关键帧列举并重定向到 keys.txt

1
ls -1 key_*.jpg > keys.txt

3、将两个文件拼在一起即可获得关键帧与在原视频中索引的对应关系。

1
paste keys.txt frame_indices.txt > combined.txt

总结

也可通过以下操作将上述操作合并:

1
2
3
4
5
ffmpeg -i input.mp4 \
-vf select="eq(pict_type\,PICT_TYPE_I)" \
-vsync 2 \
-f image2 key_%07d.jpg \
-loglevel debug 2>&1 | for /f "tokens=4,8,9 delims=. " %d in ('findstr "pict_type:I"') do echo %d %e.%f >> "keyframe_list.txt"

3.5 提取音频、视频

提取音频

主要参数:

  • -vn:去除视频

mp4 默认情况下的音频格式为 AAC,可直接复制(-acodec copy)音频流提取音频。

1
ffmpeg -i input.mp4 -acodec copy -vn output.aac

如果视频文件的音频编码不是 AAC 则会报错,因此也可以不管三七二十一对输入的音频进行重新编码为自己希望的格式:

1
2
3
4
# 转码为 AAC
ffmpeg -i input.mp4 -acodec aac -vn output.aac
# 转码为 MP3
ffmpeg -i input.mp4 -acodec libmp3lame -vn output.mp3

提取视频

主要参数:

  • -an:去除音频
1
ffmpeg -i input.mp4 -vcodec copy -an output.mp4

直接复制视频流并去除音频即可。