FFmpeg 是一个非常受欢迎的、完备的、跨平台的、开源的用于处理多媒体内容(如音频、视频、字幕及其他相关元数据)的库和工具集。本篇介绍 FFmpeg 的相关概念和基本使用方法。所有命令以 Ubuntu 为例进行介绍,Windows 和 Mac 同样适用。

FFmpeg 安装

想要使用 FFmpeg (Linux中对应的程序为 ffmpeg),必须首先安装它。Ubuntu(Centos 安装 FFmpeg的方法参考我的另一篇:Centos安装ffmpeg。Ubuntu 切换镜像源的方法参考我的另一篇:ubuntu 更改镜像源) 安装 FFmpeg 非常方便,命令如下:

1
2
sudo apt update
sudo apt install ffmpeg

容器

在介绍 FFmpeg 处理视频之前,我们需要对视频有个了解。从计算上来说,视频文件是一个容器 (container),在该容器中包含了视频(图片序列,无声音)、音频、字幕等内容。

常见的视频容器有如下几种,常常以文件后缀名来反映其容器格式:

  • MP4:常用
  • MKV:更清晰
  • WebM:体积更小
  • AVI:较久远

FFmpeg 支持很多种容器,使用如下命令可查看它支持的格式有哪些:

1
ffmpeg -formats

特别说明:在 HTML5 中的 video 标签中支持三种视频格式:MP4,Webm,Ogg。如果网页出现没有视频画面的情况,可能是编码格式不正确。那三种视频格式分别支持的编码格式有:

  • MP4 = MPEG4 文件使用 H.264 视频编解码器和 AAC 音频编解码器;
  • WebM = WebM 文件使用 VP8 视频编解码器和 Vorbis 音频编解码器;
  • Ogg = Ogg 文件使用 Theora 视频编解码器和 Vorbis 音频编解码器。

编码格式

无论是视频还是音频都需要进行编码。不同的编码有不同的压缩率。编码可以将视频文件变得更小,但一定程度上会丢失信息,导致清晰度降低。

常用的视频编码格式:

  • H.265:mp4 中常用
  • H.264:mp4 中常用,更普遍
  • H.262
  • VP9:webm 中常用
  • VP8:webm 中常用
  • AV1
  • Theora: Ogg 中常用

常用的音频编码格式:

  • MP3
  • AAC:mp4 中常用
  • Vorbis: WebM、Ogg 中常用

使用如下命令,可以查看 FFmpeg 支持的编码格式(包括视频和音频):

1
ffmpeg -codecs

编解码器

有了编码方法,需要一些程序或软件来实现文件(视频或音频)的编解码,这就是编解码器。

FFmpeg 中内置的视频编编解码器:

  • libx264:最流行的开源的 H.264 编解码器
  • NVENC:基于 NVIDIA GPU 的 H.264 编解码器
  • libx265:开源的 HEVC (H.265MPEG-H Part 2) 编解码器
  • libvpx:谷歌的 VP8 和 VP9 编解码器
  • libaom:AV1 编解码器
  • libtheora: Theora 编解码器

FFmpeg 中内置的音频编解码器有:

  • aac:AAC 编解码器
  • vorbis:Vorbis 编解码器

ffmpeg 命令的使用

ffmpeg 命令的格式如下:

1
ffmpeg [全局参数] [输入文件参数] -i 输入文件 [输出文件参数] [输出文件]

常用的参数有

  • -c:指定编码器
  • -c copy:直接复制,不经过重新编码(这样比较快)
  • -c:v:指定视频编码器
  • -c:a:指定音频编码器
  • -i:指定输入文件
  • -an:去除音频流
  • -vn: 去除视频流
  • -preset:指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
  • -y:不经过确认,输出时直接覆盖同名文件。

查看视频元信息

1
2
3
4
5
6
7
ffmpeg -i input.mp4

# or
ffprobe input.mp4

# 不显示 ffmpeg 基本信息,只显示视频相关信息
ffmpeg -i input.mp4 -hide_banner

更改容器格式(扩展名改变)

1
2
3
4
5
6
7
8
9
10
11
# 把 avi 视频转换为 mp4 视频
ffmpeg -i input.avi output.mp4

# 把 webm 视频转换为 mp4 视频
ffmpeg -i input.webm output.mp4

# 把 mkv 视频转换为 mp4 视频
ffmpeg -i input.mkv output.mp4

# 维持源视频文件的质量,使用 -qscale 0 参数
ffmpeg -i input.webm -qscale 0 output.mp4

更改分辨率

改变视频分辨率(transsizing)

1
2
3
4
5
# 缩放视频到较小的显示设备上,例如平板电脑和手机
ffmpeg -i input.mp4 -filter:v scale=1280:720 -c:a copy output.mp4
ffmpeg -i input.mp4 -s 1280x720 -c:a copy output.mp4

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

压缩视频文件

1
2
# 减小视频文件的大小,将损失视频质量。如果 24 太有侵略性,可以降低 -crf 值到或更低值
ffmpeg -i input.mp4 -vf scale=1280:-1 -c:v libx264 -preset veryslow -crf 24 output.mp4

压缩音频文件

1
2
# 96kbps, 112kbps, 128kbps, 160kbps, 192kbps, 256kbps, 320kbps
ffmpeg -i input.mp3 -ab 128 output.mp3

更改编码格式(扩展名可不变)

1
2
3
4
5
# 把 H.265 更改为 H.264 编码,(这里以 MP4 容器输入文件 input.mp4 为例,其他容器格式也可以)
ffmpeg -i input.mp4 -c:v libx264 output.mp4

# 或如下音频不变,只转换视频格式
ffmpeg -i input.mp4 -acodec copy -vcodec libx264 output.mp4

提取音频

1
2
3
4
5
6
7
8
9
10
11
12
13
# -vn表示去掉视频,-c:a copy表示不改变音频编码,直接拷贝。
ffmpeg -i input.mp4 -vn -c:a copy output.aac

# 或者,以 mp4 格式保存音频
ffmpeg -i input.mp4 -vn -c:a copy output.mp4

# 音频转换编码
# -vn 表明我们已经在输出文件中禁用视频录制。
# -ar 设置输出文件的音频频率。通常使用的值是22050 Hz、44100 Hz、48000 Hz。
# -ac 设置音频通道的数目。
# -ab 表明音频比特率。
# -f 输出文件格式。在我们的实例中,它是 mp3 格式。
ffmpeg -i input.mp4 -vn -ar 44100 -ac 2 -ab 320 -f mp3 output.mp3

提取视频(没有声音)移除音频

1
2
# 速度较快
ffmpeg -i input.mp4 -an -c:v copy output.mp4

转换音频格式

1
2
# 网页播放视频需要aac音频编码。视频不转码,直接拷贝。
ffmpeg -i input.mp4 -acodec aac -vcodec copy output.mp4

添加音频(增加音轨)

1
ffmpeg -i input.aac -i input.mp4 output.mp4

多音轨只保留一个

有时候,有些电源有国语、粤语、英语等,但默认是英语,使得播放不方便(直接百度云或阿里云播放时,默认英文)。但想要直接用国语为默认播放语音,则可以如下:

1
2
3
4
5
6
# -map 0:0 表示视频,无声
# -map 0:2 表示第二个音轨
# -c copy 表示直接拷贝,不转变编码方式,这种方式较快
# -disposition:a:0 default 设置成默认音轨
# -y 不经过确认,输出时直接覆盖同名文件(如果有的话)
ffmpeg -i 魔法满屋-英语国语粤语.mp4 -map 0:0 -map 0:2 -c copy -disposition:a:0 default -y 魔法满屋-国语.mp4

调整码率

调整码率(transrating)指的是,改变编码的比特率,一般用来将视频文件的体积变小。下面的例子指定码率最小为964K,最大为3856K,缓冲区大小为 2000K。

1
ffmpeg -i input.mp4 -minrate 964K -maxrate 3856K -bufsize 2000K output.mp4

截图

从指定时间开始00:01:24,连续对1秒钟00:00:01的视频进行截图。

1
ffmpeg -i input.mp4 -ss 00:01:24 -t 00:00:01 output_%3d.jpg

如果只需要截一张图,可以指定只截取一帧。

1
2
3
# -vframes 1指定只截取一帧
# -q:v 2表示输出的图片质量,一般是1到5之间(1 为质量最高)
ffmpeg -ss 01:23:45 -i input -vframes 1 -q:v 2 output.jpg

每秒提取一张图片

1
2
3
# -r – 设置帧速度。即,每秒提取帧到图像的数字。默认值是 25
# -f – 表示输出格式,即,在我们的实例中是图像。
ffmpeg -i input.mp4 -r 1 -f image2 image-%2d.png
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 从视频提取图像的基本命令:把每一帧都保留下来,即使用默认帧率保存图像
ffmpeg -i input.mp4 %d.png # 1.png, 2.png
ffmpeg -i input.mp4 %06d.png # 000001.png, 000002.png

# 针对帧率,如下为当前视频帧率中只取1张图像保存,即每一秒提取一帧 -vf 表示 -filter:v
ffmpeg -i input.mp4 -vf fps=1 %06d.png
ffmpeg -i input.mp4 -vf fps=1/4 %06d.png # 每4秒提取一帧

# 提取指定时刻 00:00:04 开始到结尾的所有图像
ffmpeg -ss 00:00:04 -i input.mp4 %06d.png

# 从指定时刻 00:00:04 提取2秒的图像
ffmpeg -ss 00:00:04 -t 2 -i input.mp4 %06d.png

# 提取指定时刻 00:00:04 的一副图像
ffmpeg -ss 00:00:04 -i input.mp4 -frames:v 1 screenshot.png

# 提取后改变图像尺寸为固定尺寸
ffmpeg -i input.mp4 -s 640x480 %06d.png

# 提取后同比例缩放图像尺寸
ffmpeg -i input.mp4 -vf scale=640:-1 %06d.png

切分视频文件为多个部分

一些网站将仅允许上传具体指定大小的视频。此时需要切分大的视频文件到多个较小的部分

1
2
3
# -t 00:00:30 表示从视频的开始到视频的第 30 秒创建一部分视频
# -ss 00:00:30 为视频的下一部分显示开始时间戳。它意味着第 2 部分将从第 30 秒开始,并将持续到原始视频文件的结尾
ffmpeg -i input.mp4 -t 00:00:30 -c copy part1.mp4 -ss 00:00:30 -codec copy part2.mp4

截取视频的中间一部分

1
2
3
4
5
6
7
# -ss 表示从视频的第 00:01:00 时刻开始截取
# -t 表示截取时间段为 10 秒的视频段
# -c:v libx264 指定截取后的视频进行转码
# -c:a copy 指定音频不转码
# -strict -2 表示 opus in MP4 support is experimental, add '-strict -2' if you want to use it. (FFmpeg 4.3 and newer & the git master branch) no longer need
# -y 表示当前目录如果有 output.mp4 文件,则直接覆盖不提示
ffmpeg -ss 00:01:00 -t 10 -i input.webm -c:v libx264 -c:a copy -strict -2 -y output.mp4

接合或合并多个视频部分到一个

创建包含所有需要合并的视频路径的 join.txt 文件。所有的视频都应该是相同的格式(相同的编码格式)。所有文件的路径应该按顺序逐个列出:

1
2
3
file /home/sk/myvideos/part1.mp4
file /home/sk/myvideos/part2.mp4
file /home/sk/myvideos/part3.mp4
1
2
3
ffmpeg -f concat -i join.txt -c copy output.mp4
# 或 当提示 Unsafe file name,Operation not permitted,请使用下面方法
ffmpeg -f concat -safe 0 -i join.txt -c copy output.mp4

裁剪

裁剪(cutting)指的是,截取原始视频里面的一个片段,输出为一个新视频。可以指定开始时间(start)和持续时间(duration),也可以指定结束时间(end)。

1
2
3
# -t 表示总的持续时间
ffmpeg -ss [start] -i [input] -t [duration] -c copy [output]
ffmpeg -ss [start] -i [input] -to [end] -c copy [output]

选择范围裁剪

1
2
3
4
5
6
7
8
9
# -filter:v – 表示视频过滤器
# crop – 表示裁剪过滤器
# w – 我们想自源视频中裁剪的矩形的宽度
# h – 矩形的高度
# x – 我们想自源视频中裁剪的矩形的 x 坐标
# y – 矩形的 y 坐标
ffmpeg -i input.mp4 -filter:v "crop=w:h:x:y" output.mp4
# 想截取视频的位置 (200,150),且具有 640 像素宽度和 480 像素高度的视频
ffmpeg -i input.mp4 -filter:v "crop=640:480:200:150" output.mp4

转换视频的某一部分到其他格式

1
2
3
# 转换视频 input.mp4 文件的开始 10 秒到视频 .avi 格式
# 以 hh.mm.ss 格式具体说明时间也是可以的
ffmpeg -i input.mp4 -t 10 output.avi

设置视频的屏幕高宽比

1
2
3
# 常用宽高比:
# 16:9,4:3,16:10,5:4,2:21:1,2:35:1,2:39:1
ffmpeg -i input.mp4 -aspect 16:9 output.mp4

为音频添加封面

有些视频网站只允许上传视频文件。如果要上传音频文件,必须为音频添加封面,将其转为视频,然后上传。下面命令可以将音频文件,转为带封面的视频文件。

1
2
3
4
5
# cover.jpg 是封面图片
# input.mp3 是音频文件
# -loop 1 表示图片无限循环,
# -shortest 表示音频文件结束,输出视频就结束。
ffmpeg -loop 1 -i cover.jpg -i input.mp3 -c:v libx264 -c:a aac -b:a 192k -shortest output.mp4

添加字幕到一个视频文件

常见字幕格式

不同的字幕文件有不同的格式,常见的字幕格式有:

  • SRT(标准外挂字幕格式):只包含文字和时间码,没有样式,显示效果由播放器决定,不同的播放器显示出的效果可能差别很大;
  • ASS(高级外挂字幕格式):支持样式、字体、字幕定位、淡入淡出、简单的特效。如果不缺字体,不同的播放器显示效果基本一致;
  • XML+PNG序列:用来导入Premiere、FCP7、Edius、Vegas、AE,不支持FCPX;
  • Avid DS Cap字幕格式:AVID专用格式,导入后可以修改文字;
  • UTF(会声会影专用格式):可以直接导入会声会影使用;

字幕格式可以互相转换

1
2
ffmpeg -i subtitle.srt subtitle.vtt
ffmpeg -i subtitle.srt subtitle.ass

添加软字幕

软字幕也叫内挂字幕、封装字幕、内封字幕,字幕流等,就是把前面的外挂字幕的字幕文件嵌入到视频中作为流的一部分,如果一个视频有多个字幕流那么播放视频是还得选择对应的字幕流。外挂字幕是一个单独的外部字幕文件,格式类型一般有srt、vtt、ass等等。播放视频时,需要把外挂字幕和视频放在同一目录下,并在播放器中选择字幕文件才可以在视频中看到字幕。不管是外挂字幕还是软字幕,字幕要正常显示播放器必须要支持字幕的渲染。

1
2
3
4
5
6
7
ffmpeg -i input.mp4 -i subtitle.srt -map 0 -map 1 -c copy -c:v libx264 -crf 23 -preset veryfast output.mp4

# or
ffmpeg -i input.mp4 -i subtitle.srt -c copy -c:v libx264 -crf 23 -preset veryfast output.mp4

# or mp4 格式的视频需指定字幕编码方式 mov_text
ffmpeg -i input.mp4 -f srt -i subtitle.srt -c:v copy -c:a copy -c:s mov_text output.mp4

添加硬字幕

硬字幕就是嵌入到视频帧里面的字幕,它就像视频水印一样作为视频帧的一分部分了,不管再任何平台字幕看起来都是一样的,而且也不再要求播放器单独对字母进行渲染。

1
ffmpeg -i input.mp4 -vf subtitles=subtitle.srt output.mp4
1
2
ffplay video.mp4
ffplay audio.mp3

增加/减少视频播放速度

1
2
3
4
5
# 增加播放速度
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" output.mp4

# 降低播放速度
ffmpeg -i input.mp4 -vf "setpts=4.0*PTS" output.mp4

视频/图片到 gif

截取视频部分到 gif

1
2
3
4
5
6
7
8
9
10
11
# -ss : indicates the starting point of GIF
# -i : input file
# input.mp4 : My video file name
# -to : End position of the GIF file
# -r : frame rate. You can increase the value to get more quality GIF file
# -vf : filter graph. To scale the GIF image in the desired size

ffmpeg -ss 00:00:20 -i input.mp4 -to 10 -r 10 -vf scale=200:-1 output.gif

# 转高质量 GIF
ffmpeg -i small.mp4 -b 2048k small.gif

把图片序列合成gif

1
2
3
4
5
# -framerate 越小越慢
# image_%003d.jpg 图片序列格式,%003d表示3位整数,不足3位前面填充0
# -vf 视频格式化
# -loop -1 表示循环1次,播放2次; -2 一次递增;默认为-0 播放1次
ffmpeg -f image2 -framerate 9 -i image_%003d.jpg -vf scale=531x299,transpose=1,crop=299,431,0,100 -loop -1 out.gif

gif 转 视频

1
2
3
4
5
6
7
# 一般
ffmpeg -f gif -i animation.gif animation.mp4

# GIF 转出来的 MP4 播放不了?有些 GIF 转化出来的 MP4 不能被 Mac QuickTime Player.app 播放,需要添加 pixel formal 参数
ffmpeg -i input.gif -vf scale=420:-2,format=yuv420p out.mp4

ffmpeg -i guoying.gif -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" video.mp4

图片合成视频

1
ffmpeg -framerate 30 -pattern_type glob -i '*.png' -c:v libx264 -pix_fmt yuv420p out.mp4

也可以指定不同路径的图片,需要把各图片路径写的 input.txt 中,格式大概如下:

1
2
file '/home/jinzhongxu/a/b/c.png'
file '/home/jinzhongxu/d/f/g/k.png'

合成方法如下:

1
2
3
# -framerate 表示一副图一帧
# -r 表示合成后的视频帧率
ffmpeg -f concat -i input.txt -framerate 1 -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p output.mp4

ffprobe 命令的使用

ffprobe 一般和 ffmpeg 一起被安装,它是非常强大的视频分析工具,可非常方便的从多媒体视流(视频、音频等)中获取文件描述信息,并且可以指定的格式输出结果。

显示视频总帧数、宽、高等信息

1
ffprobe -show_streams xc.mp4

也可以屏蔽版本参数信息:

1
ffprobe -v quiet -show_streams xc.mp4

已 json 格式显示结果:

1
2
# 除 json 外,还可以指定 xml, csv, ini 等
ffprobe -v quiet -print_format json -show_streams xc.mp4

只看指定的信息

1
2
3
# 只显示视频帧率 r_frame_rate
# -select_streams: 参数可以是 a、v、s 分别表示只查看音频、视频、字幕
ffprobe -v quiet -select_streams v -show_entries stream=r_frame_rate xc.mp4

显示每一帧的信息

1
ffprobe -v quiet -print_format json -show_frames xc.mp4

显示包信息

1
ffprobe -v quiet -print_format json -show_packets xc.mp4

显示封装格式信息

1
ffprobe -v quiet -print_format json -show_format xc.mp4

更多是使用如下命令查看:

1
2
man ffprobe
ffprobe --help

文件名中含空格

如果文件名中含有空格,直接使用 ffmpeg 会报错,此时,需要把文件名用双引号括起来:

1
ffmpeg -i "input 2023.05.08.avi" -c:v libx264 "output 2023.05.08.mp4"

参考链接

  1. How to Install and Use FFmpeg on Ubuntu 18.04
  2. FFmpeg 视频处理入门教程
  3. 给新手的 20 多个 FFmpeg 命令示例
  4. ffmpeg-给视频添加字幕(二十四) - 简书
  5. centos8平台用ffprobe获取视频文件信息(ffmpeg4.2.2)
  6. 使用 ffmpeg 实现 MP4 与 GIF 的互转
  7. gvoze32/ffmpeg GIF to MP4.MD
  8. How to Extract Images from a Video Using FFmpeg