ffmpeg是进行视频编解码的库,同时提供命了令行工具,对于大部分简单的视频编辑任务,比如转码、截取等,ffmpeg足以胜任。事实上,ffmpeg支持绝大部分的视频、音频和图片格式。本文介绍10个最常使用的ffmpeg命令,这些用法都可以从stackoverflow获取到答案,笔者通过亲测后汇集了完成每种任务最优的方案。有了它们,就没有必要再使用格式工厂、premiere等笨重的软件了。
视频格式小科普
在开始下面的教程之前有必要先简单科普一下视频格式的知识。
视频格式是一种非常不专业的叫法,事实上,视频有编码格式和容器格式两种。编码格式之于容器格式就像牛奶之于杯子一样。 常见的视频文件有mp4(mpeg4 part 14),mkv,flv等,这些是视频的容器格式/封装格式(Container format)。它们包含视频流和音频流,mkv支持多条音轨和字幕,因此是目前最受欢迎的容器格式。比如在播放mkv视频的时候,可以选择不同语言的音轨/字幕。 至于视频编码格式(Encoding format),则是这些容器所包含的视频流/音频流所采用的压缩方式,比如最常用的h.264/aac,mpeg4/mpeg3等。
安装ffmpeg
在mac os上安装ffmpeg:
brew install ffmpeg --with-fdk-aac --with-libass --with-sdl2
在linux上安装ffmpeg最简单的方式是使用官方提供的静态编译安装包,解压后即可使用。
ffmpeg命令通用格式
先来认识一下ffmpeg命令行工具的格式:
ffmpeg -global_options -input_1_options -i input_1 -input_2_options -i input_2 -output_1_options output_1 ...
需要注意的是: * 输入输出 * 至少有一个输入和输出 * 可以同时有多个输入和输出 * 输入、输出不一定是文件,可以是rtmp流的地址、摄像头对应的设备文件等 * 顺序很重要 * 所有的输入完了然后是输出 * 某个选项只对它后面的输入或输出起作用
1. 查看视频的信息
ffmpeg -hide_banner -i input.mkv
ffprobe -hide_banner input.mkv
通过ffmpeg可以查看一个视频文件的以下基本信息:
- 视频/音频的编码格式
- 分辨率(1080p or 1080i, Progressive Interlaced)
- 时长(duration)/码率(bitrate)/帧率(fps,frames per second)
- 音轨(Audio)/字幕(Subtitle)
2. 转码(transcode)
转码是指对流(视频、音频和字幕)进行解码然后再编码,这个过程非常耗CPU。输出的编码格式通过-codec指定,如果不指定,ffmpeg并不会直接copy,而是采用根据容器格式采用相应的默认编码格式进行重新编码。
为了简单起见,把转换容器格式也归为转码,ffmpeg会通过输出文件的后缀判断输出的容器格式,因此不需要指定(-f)。
视频
将mkv转换成mp4
有时候我们需要将mkv转换成mp4:
- 很多视频网站不支持上传mkv格式
- 大部分视频剪辑软件,比如premiere等不支持导入mkv格式的视频
下面的命令将mkv的视频和音频流重新封装成mp4文件,不进行重新编码(无损)
ffmpeg -i input.mkv -codec copy output.mp4
制作mkv
mkv格式能够封装多个音频、字幕轨,是目前最为流行的视频分发格式,通常使用mkvtoolnix工具来编辑制作mkv视频,通过ffmpeg也能完成一些简单的任务。
将mpeg4/mp3编码的视频重新编码为h.264/aac,并和字幕一起封装成mkv文件:
ffmpeg -i input.avi -i input.srt -map 0:0 -map 0:1 -map 1:0 -c:v libx264 -c:a aac -c:s srt output.mkv
音频
ffmpeg不仅能处理视频,音频文件也不在话下,因此,同样可以用ffmpeg转换音频格式。
将flac无损的音乐转换成高质量(High Quality,即320Kb)的mp3格式:
ffmpeg -i "Michael Jackson - Billie Jean.flac" -ab 320k "Michael Jackson - Billie Jean.mp3"
3. 截取(cut)
从视频中截取出精彩片段是我们最常用的功能。
从第2分钟开始,截取30秒。所有流都直接拷贝。
ffmpeg -ss 00:02:00.0 -i input.mkv -t 30 -c copy output.mkv
截取最大的问题是难以做到精确控制时间点,大部分的视频剪辑软件都存在这样的问题:
- 视频开头卡顿/不流畅,画面与声音不同步
- 时间误差甚至能达到秒级,比如截取10秒的片段,可能会得到12秒的输出
原因是ffmpeg会seek到指定时间点前的一个关键帧,如果是copy视频流,seek点和起点之间的额外部分将会被保留,因此就产生了误差。解决办法是将-ss作为输出选项或进行重新编码:
ffmpeg -i input.mkv -ss 00:02:00.0 -t 30 -c copy output.mkv
如果还是出现上述问题,使用下面的终极解决方案(使用两次seek):
ffmpeg -ss 00:01:30.0 -i input.mkv -ss 00:00:30.0 -t 30 output.mkv
4. 截图(screenshot)
截图就是将某个视频帧保存为图片,例如:
在指定时间点截图
ffmpeg -ss 00:30:14.435 -i input.mkv -vframes 1 out.png
结合fps视频滤镜,可以从视频中截取多张图片。例如:
每1分钟截一张图,在截图文件名中添加当前的时间
ffmpeg -i input.mkv -vf fps=1/60 -strftime 1 out_%Y%m%d%H%M%S.jpg
5. 压缩(compress)
一张蓝光原盘接近50G,而720p的电影可能只有2G,这是通过压缩实现的。在保证画质的前提下使用更小的文件存储,一直是压缩的目标。然而压缩并非那么简单,比如同样是720p的电影,有的只有2个G,有的却有5个G,然而从视觉上几乎看不出区别来。 这里只介绍压缩的一个简单用途:resize。
将1080p转成720p,宽度自适应
ffmpeg -i input.mkv -c copy -c:v libx264 -vf scale=-2:720 output.mkv
-vf
是-filter:v
的简写,-filter指定滤镜,:v是流选择器,表示对视频流应用滤镜。scale滤镜后面的参数是w:h,w和h可以包含一些变量,比如原始的宽高分别为iw和ih。当其中一个是负数时,假设为-n,ffmpeg自动使用另一个值按照原始的宽高比(aspect ratio)计算出该值,并且保证计算出来的值能被n整除。
因为scale滤镜是针对未编码的原始数据,所以视频流不能用copy,需要进行重新编码。-c copy -c:v libx264
表示视频流使用h.264重新编码,其他流直接copy,顺序不能颠倒。
6. 字幕(subtitle)
对于视频发布者,给视频添加字幕很有必要。如果是mkv,可以采用制作mkv的方法将字幕文件封装到mkv文件里。如果是mp4视频,则需要进行烧录(draw),即对视频重新编码的过程中将字幕融入视频流。
ffmpeg -i input.mkv -vf subtitles=input.srt output.mp4
如果是ass格式的字幕文件,则使用ass滤镜:
ffmpeg -i input.mkv -vf ass=input.ass output.mp4
另一种常见的方法是使用-c:s mov_text
将字幕流封装进mp4里,它不需要重新编码,但是目前大部分播放器对mp4的软字幕支持不好。
7. 提取(extract)
有时候我们需要从电影中提取插曲或从视频中提取背景音乐,通过ffmpeg可以很容易从视频文件中提取音频:
ffmpeg -i cut.mp4 -vn output.mp3
-vn
表示不输出视频流。
输出的mp3默认的码率是128kb,可以使用ab控制。结合截取中的-ss和-t还可以只提取一个部分的音频。
从mkv文件中提取字幕也是同样的方法。
8. 水印(watermark)
给视频添加水印是通过overlay滤镜实现的,overlay滤镜的作用是将一个视频覆盖另一个视频上面,它有两个输入,前一个是下层(main),后一个是上层(overlaid)。 overlay的参数x:y是上层左上角的坐标,0:0表示位于下层的左上角。它可以包含以下参数:
- W(w):下(上)层的宽
- H(h):下(上)层的高
将水印/logo添加到视频的右上角,并且和边缘保持5像素的距离:
ffmpeg -i input.mkv -i input.png -filter_complex "overlay=W-w-5:5" -c copy -c:v libx264 output.mkv
需要注意的是,视频需要重新编码,其他流(音频、字幕)则直接copy,顺序不能颠倒。
9. 混流(Muxing)
如果我们拍摄了一段视频,想给它添加背景音乐,最好还是借助视频编辑软件,它能对音乐的开头和结尾分别进行增强和减弱的处理,如果不在意这些细节,完全可以用ffmpeg来代替。
替换音频
ffmpeg -i input.mkv -i input.mp3 -map 0:v -map 1:a -c copy -shortest output.mp4
- -map 0:v – 从输入0(第1个输入,即input.mkv) 选择视频流
- -map 1:a – 从输入1(第2个输入,即input.mp3) 选择音频流
第1个map对应输出的第1个流,第2个map对应输出的第2个流,以此类推。
合并音频
另一个常见的形式是将两个音频合并成一个,需要使用amerge滤镜:
ffmpeg -i input.mkv -i output.aac -filter_complex "[0:a][1:a]amerge=inputs=2[a]" -map 0:v -map "[a]" -c:v copy -c:a aac -ac 2 -shortest output.mp4
10. 制作gif
结合前面讲到的截取和压缩,将输出文件的后缀改为gif就可以得到动态图
ffmpeg -ss 30 -t 5 -i input.mp4 -r 10 -vf scale=-1:144 -y output.gif
但是这种方式的效果很差,有一种粗糙的布料的感觉。 原因在于gif限制只能包含256种颜色,而原始视频可能包含数以百万的颜色,ffmpeg默认会使用一种通用的调色板(palettep),因此导致颜色失真。2015年,ffmpeg通过引入palettegen和paletteuse两个滤镜来改进这个问题,它通过扫描整个视频,输出一个最佳的调色板,然后再转换成gif的过程中应用这个调色板从而避免颜色失真。
下面的命令从input.mp4的第30秒开始截取5秒,生成高144像素的gif动态图:
palette="/tmp/palette.png"
filters="fps=10,scale=-1:144:flags=lanczos"
ffmpeg -ss 30 -t 5 -i input.mp4 -vf "$filters,palettegen" -y $palette
ffmpeg -ss 30 -t 5 -i input.mp4 -i $palette -filter_complex "$filters [x]; [x][1:v] paletteuse" -y output.gif
与前一个输出相比,质量提升了很多。
另一个有待研究的难题是如何控制输出gif的大小。在不影响画质的前提下,我们希望体积越小越好。比如网上有的gif图很清晰,却不超过1M。而一段500K的视频文件,使用上面的方法转成gif后输出的gif却有1.6M。
参考
- ffmpeg Documentation
- FFmpeg Commands: 31 Must-Haves for Beginners in 2022
- 视频格式那么多,MP4/RMVB/MKV/AVI 等,这些视频格式与编码压缩标准 mpeg4,H.264.H.265 等有什么关系?
- Using ffmpeg to cut up video
- wiki:Create a thumbnail image every X seconds of the video
- FFMPEG mkv to mp4 conversion loses subtitles
- Use ffmpeg to add text subtitles
- ffmpeg to extract audio from video
- How to add a new audio (not mixing) into a video using ffmpeg?
- Unknown encoder 'libfaac'
- How do I convert a video to GIF using ffmpeg, with reasonable quality?
- FFMPEG: high quality animated gif?
- How to add transparent watermark in center of a video with ffmpeg?