如今较为常见的视频封装格式有 mp4 和 mkv 等, 内部的视频编码格式从前几年盛行的 H.264/x264
逐渐开始向新一代的 HEVC/x265
( High Efficiency Video Coding 高效视频编码)过渡,而常见的音频编码格式无非 AC3、DTS 或者 AAC 等。无论是借助带有 GUI 的编码软件,还是使用命令行,FFmpeg 是最为广泛使用的工具,理论上 FFmpeg 支持各个平台,包括 Windows、macOS、iOS 以及 Android 等,这里只介绍在 macOS 下的使用。通过简单的命令,你可以大致了解 FFmpeg 在视频转换上的强大之处,视频编码部分也集中在 x264、x265,以及如何压制 macOS High Sierra 和 iOS 11 可以正确识别并生成缩略图的 HEVC 10bit 视频。最后会用一个较为复杂的例子,应用 -filter_complex
进行视频帧率的插值运算、嵌入 pgs 图形字幕,以及最后输出 HEVC 编码进行说明。
如果有看过我以前文章的朋友,可能会注意到使用 Homebrew 编译 mpv 的一个重要依赖就是 FFmpeg。不过,如果将其用作视频转码,默认编译的 FFmpeg 会缺少一部分组件,因此这里可能需要重新安装 FFmpeg。以我个人编译版本为例,使用 --HEAD
来配合最新的 mpv,在 Terminal 中输入如下命令:
brew install ffmpeg --HEAD --with-fdk-aac --with-sdl2 --with-freetype --with-libass --with-libbluray --with-libvorbis --with-libvpx --with-opus --with-webp --with-x265
等待安装结束即可。
ffmpeg -i input.mp4 -c:a libfdk_aac -c:v libx264 -crf 20 -preset slow output.mp4
使用 FFmpeg 编码的基本规则, -i
之后的文件为输入的视频文件,即 input.mp4 ,支持的格式众多,例如 mkv、flv、vob 等等,文件可以包含目录,使用 macOS 的文件拖拽功能很方便。output.mp4 即为输出文件,文件名可自定义,视频封装格式建议对应编码格式,不应将 mpeg-2 或者 vp8 编码的视频也封装为 mp4。-c:a
之后表示输出文件的音频编码器,一般 mp4 常用的音频编码为 AAC-LC,按照官方 Wiki 指南,建议使用编码器 libfdk_aac
而不是 aac
,libfdk_aac
音质更好,这也是为什么在前文中编译 FFmpeg 增加 --with-fdk-aac
的原因。-c:v
之后代表输出文件的视频编码器,使用 libx264
即可压制 x264 编码的视频流。-crf 20
代表视频编码的码率系数,数字越大,压制的效果越差,建议选择范围在 16 - 28
,压制高质量的视频建议取值 20 以下。-preset slow
代表一组控制压缩时间和文件大小的参数选择,一般常选 fast
、medium
和 slow
。
以上都是基于 one-pass 压制,如果需要严格控制码率则需要使用 two-pass,更详细的介绍,可以参考 Encode / H.264。
其实 FFmpeg 很早就开始支持 HEVC (x265) 的视频转码,只是一直改动较大,而最近的版本也终于支持编码 macOS High Sierra 下 Quicktime 可以播放,并且在系统中能够正确预览并生成缩略图的视频文件。编码命令的改动很小,添加一个 format tag
参数即可,如下:
ffmpeg -i input.mp4 \
-c:v libx265 -preset medium -crf 18 -pix_fmt yuv420p10le \
-c:a libfdk_aac -b:a 256k \
-tag:v hvc1 \
output_10bit.mp4
和压制 x264 视频非常类似,主要的不同点在于 -c:v
视频编码器需换为 libx265
,并且压制 10bit 需要指定色彩空间,添加 -pix_fmt yuv420p10le
。在音频编码参数中,如何增加的 -b:a
,可以控制音频文件的码率,按需使用。最后,非常重要的一点,必须添加参数 tag:v hvc1
,这样输出的 Video Stream 会被标记为 hvc1
,可以被 macOS 以及 iOS 11 原生支持播放,否则默认会被标记为 hev1
,不被原生支持,第三方播放器播放倒没什么问题。
假如原视频的分辨率为 1920x1080,为了降低文件大小,最简单的办法是将其转压成一个分辨率较低的版本,例如 720p,即 1280x720,那么我们可以使用 scale
视频滤镜来缩放视频:
ffmpeg -i input.mp4 -vf scale=-2:720 -c:v libx264 -crf 20 -preset slow -c:a copy output.mp4
-vf scale=-2:720
会自动计算对应的横向分辨率(需为 2 的倍数,因此为 -2 ),源文件音频编码保持不变,因此设为 copy
即可。特殊情况下,遇到源文件视频比例错误,除了修改分辨率数值,还需要设置 dar
参数,例如:
ffmpeg -i input.avi -vf scale=722x406,setdar=16/9 -c:v libx264 -c:a libfdk_aac -preset slow -crf 20 output.mp4
另外,绝对不建议增大分辨率,因为毫无意义,受限于原视频的视频质量,增大分辨率除了体积增大,画质只会更差。
偶尔我会遇到一些早期使用 VCD/DVD 时代编码的视频,其中一个重要的特点就是隔行扫描,而直接转码的结果就是视频中快速运动的物体都能看到非常明显的扫描线。解决办法同样需要应用 vf
视频滤镜中的 yadif
来进行反交错,如下:
ffmpeg -i input.vob -vf yadif -c:v libx264 -preset slow -crf 20 -c:a libfdk_aac -b:a 256k output.mp4
如果压制出来的效果不佳(还是有扫描线),可以尝试将 vf
的部分改为 -vf yadif=1:-1:0,mcdeint=2:1:10
。
需要将原视频进行旋转,同样可以应用视频滤镜来达到目的,如下:
ffmpeg -i input.mov -vf "transpose=1" -c:a copy output.mov
其中,
0 = 90 Counter Clockwise and Vertical Flip (default)
1 = 90 Clockwise
2 = 90 Counter Clockwise
3 = 90 Clockwise and Vertical Flip
如果想要 180 度翻转视频,则需要改为 -vf "transpose=2,transpose=2"
。值得注意的是,旋转视频意味着对视频进行重编码,输出质量会稍微受到影响,可以添加 crf
参数控制视频输出质量,音频部分可以使用 copy
。
最后的这个例子,是我最近遇到的一个视频,简要的编码信息如下:
Input #0, matroska,webm, from 'Input.mkv':
Duration: 00:23:55.97, start: 0.000000, bitrate: 16372 kb/s
Stream #0:0: Video: hevc (Main 10), yuv420p10le(tv, bt709), 1920x1080, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn, 59.94 tbc (default)
Stream #0:1(jpn): Audio: flac, 48000 Hz, stereo, s32 (24 bit) (default)
Stream #0:2(jpn): Audio: flac, 48000 Hz, stereo, s32 (24 bit)
Stream #0:3(chi): Subtitle: hdmv_pgs_subtitle (default)
Stream #0:4(chi): Subtitle: hdmv_pgs_subtitle
可以看到,这是一个 HEVC 10bit 编码,分辨率 1080p,帧率 59.94 fps 的视频文件,带有两条 flac 编码的音轨,另有两条是 pgs 格式的图形字幕。我自己的 Macbook Pro 已经无法完全流畅地播放这个视频了,除了 HEVC 带来的巨大计算量,高帧率也是一个麻烦,可惜网上没有其它好的片源,因此,我只有自己尝试压缩。目标:维持分辨率但帧率减半,即降为 29. 97 fps,音轨只需要第一条,并且重编码为 AAC-LC,原片为日语,因此必须带有字幕,图形字幕直接嵌入视频,最后以 HEVC 10bit 重编码,少许降低码率。
改变帧率普遍会使用 -vf fps=fps=29.97
这类的参数,但自己尝试后发现一个问题,视频观看的感觉有跳跃性,不流畅,很像是丢帧的感觉。因为将帧率减半,意味着有一半的信息都丢弃了,而普通降低帧率的算法只有简单的插值运算甚至完全没有,造成了视频不连贯的效果。因此,改变帧率正确的做法是进行运动插值运算( Motion Interpolation ),此法既可用在提高帧率上,也可以用于降低帧率,最终的结果都是提高视频播放的流畅度。这里会使用 -filter_complex
代替 vf
,联合应用 minterpolate
、overlay
以及 map
来解决帧率、嵌入视频,和保留一条音轨的问题。压制命令如下:
ffmpeg -i input.mkv \
-filter_complex "[0:v]minterpolate='fps=29.97:mi_mode=mci:me_mode=bidir:mc_mode=aobmc:vsbmc=1'[bg],[bg][0:s:0]overlay[v]" -map "[v]" -map 0:a:0 \
-c:v libx265 -preset medium -crf 18 -pix_fmt yuv420p10le \
-c:a libfdk_aac -b:a 256k \
-tag:v hvc1 \
output_10bit.mp4
这里看起来会很复杂,实际上 -filter_complex
的工作模式就像是 pipe,[0:v]
表示输入文件的视频流,对应 Stream #0:0。从 minterpolate
到 vsbmc=1
都是插补滤镜的设置参数,具体的作用可以查看官方文档。[bg]
代表该滤镜输出后的视频流,并传递给下一个滤镜 overlay
。[0:s:0]
表示输入文件的第一个字幕通,对应 Stream #0:3,所以如果是 [0:s:1]
则对应 Stream #0:4。 overlay
就会将该图形字幕嵌入到视频中,然后输出为 [v]
,进行 mapping。视频取处理后的 [v]
,音频取原输入文件的第一个音频通道,[0:a:0]
即代表 Stream #0:1。最后和此前压制视频的参数就一模一样了,压制为 HEVC 10bit 编码的视频文件。
需要注意的是,运动插值运算非常耗时,CPU 占用确不高,应该是 minterpolate
滤镜只能调用单核的缘故。在我的电脑上, 此 23 分钟左右的视频压制一次耗时约 20 小时,请谨慎使用。
补充一条用来自动切黑边的脚本吧,因为有时候碰到比较懒的小组发的片源,连黑边都不切,这样外挂字幕就跑到黑边去了,我很不喜欢....... 保存代码为 crop-border.sh 并修改权限,用法:./crop-border.sh input.mp4 output.mp4
#!/bin/bash
# autodetect crop size
crop=`ffmpeg -i $1 -t 1 -vf cropdetect -f null - 2>&1 | awk '/crop/ { print $NF }' | tail -1`
echo "detected crop fromat: $crop"
echo "input: $1"
echo "output: $2"
date ; read -t 5 -p "Hit ENTER or wait five seconds" ; date
ffmpeg -i $1 -c:a copy -c:v libx265 -preset medium -crf 18 -pix_fmt yuv420p10le -tag:v hvc1 -vf $crop -y $2
压制的参数 -c:a 和 -c:v 部分还需调整
1
expy 2018-02-24 22:13:02 +08:00 via Android
预处理多可以考虑 vapoursynth.
|
2
Pudge1337 2018-02-24 23:28:06 +08:00 via Android
一串代码就可以对视频转码,感觉不错!
|
3
likuku 2018-02-24 23:55:31 +08:00
ffmpeg v3.4 目前不建议用,编码完成后的打包时,遇到多次无法完成打包而进入死循环 /假死。
|
4
likuku 2018-02-24 23:56:55 +08:00
3# 的状况,目前只在 macOS 上见到,多次复现。
|
5
mrcotter2013 OP @likuku #3 查看了一下 FFmpeg 目前通过 brew 安装的稳定版是 3.4.2 ( commit 6a97ba5 ),情况是否改善?
我在教程中使用的是 --HEAD 版本( commit 28924f4 ),自己平时也经常使用,不过没碰到过你说的死循环情况。 |
6
ashfinal 2018-02-25 00:30:26 +08:00
好文先马再看。
|
7
zhang1215 2018-02-25 00:33:37 +08:00
win 下一直用 ffmpeg,来学习学习
|
8
Cavolo 2018-02-25 01:13:06 +08:00 via iPhone
不建议笔记本,煎鸡蛋
|
9
xxx027 2018-02-25 02:08:37 +08:00
如果帧率减少了,那音频也要相应减速吧?不然会音画不同步。
|
11
wwqgtxx 2018-02-25 06:37:41 +08:00 via iPhone
很多情况下如果通过-x265-programs 设置设置 x265 的参数还能优化优化压制速度
|
12
ech0x 2018-02-25 07:58:39 +08:00 via iPhone
有没有类似对各种编码,封装详细解释的文章资料啊,求推荐。
|
13
mrcotter2013 OP @expy #1 嗯,很早就知道,不过一直没用过......猜测在字幕组压视频用 vapoursynth 比较多
|
14
mrcotter2013 OP @Cavolo #8 ffmpeg -threads 了解一下,另外 brew info cputhrottle 也可以了解一下
Ubuntu 等 Linux 系统有 cpulimit 可以用来限制进程对 CPU 的占用率 |
15
FindHao 2018-02-25 09:06:38 +08:00
|
16
mrcotter2013 OP @xxx027 #9 当你改变了视频速率,用到了 setpts,就需要对音频进行重采样,记得是用 atempo
|
17
mrcotter2013 OP @wwqgtxx #11 太细致了,有特殊需求才会用到......
|
18
mrcotter2013 OP @ech0x #12 这个话题大概可以写一本书了.....不同的封装格式有一定的限制,支持的音视频格式也不同。
比如标准 mp4 常见视频格式 H.264/x264、x265,但也可以是 vp8、vp9,音频格式只支持 AAC ;如果要封装 AC-3 音轨,macOS 和 iOS 需要使用 m4v 封装; DTS 就需要换成 mkv 了。 |
19
yuzenan888 2018-02-25 09:34:44 +08:00 via iPhone
谢谢,已收藏。不过用 MacBook Pro 编码效率实在是低的可怜。
|
20
tony1016 2018-02-25 10:10:33 +08:00
非常不错
|
21
liwufan 2018-02-25 10:26:21 +08:00 via iPhone
写的挺全的,有点想看用 ffmpeg 切割合并封装之类的操作,笔记本上面视频转码太烫了
|
22
Cavolo 2018-02-25 15:13:50 +08:00
@mrcotter2013 thanks
|
23
WindowPain 2018-02-25 16:34:26 +08:00 via iPhone
一直想入门一下 ffmpeg,现在懂了点皮毛,感谢。
|
24
likuku 2018-02-25 17:21:34 +08:00
@yuzenan888 追求效率,那么 Mac 上就用 videotoolbox GPU 加速编码器,
速度感人,12 寸 macbook 都可以飞速编码。 |
25
yuzenan888 2018-02-25 17:37:00 +08:00
@likuku HEVC 10bit 可以 GPU 加速么?
|
26
mrcotter2013 OP @likuku #24 如果硬件支持,Video Toolbox 确实支持 HEVC 硬件编码和解码,不过 Mac 上有什么工具可以用?
|
27
mrcotter2013 OP @liwufan #21 参考官方指南 Concatenate: https://trac.ffmpeg.org/wiki/Concatenate
另外,我补充一个切黑边的脚本。至于按时间分割,搜索参数 -ss |
28
likuku 2018-02-25 19:52:45 +08:00
@yuzenan888
@mrcotter2013 目前 videotoolbox 的确只支持 h264 编码。N 卡在 Ubuntu 16.04 上 ffmpeg 可以用 nvenc 编 hevc/h265 |
29
likuku 2018-02-25 19:56:01 +08:00
补充:NVENC 在笔记本电脑上对显卡要求特别高,我自己试验时,只有 N 家的专业线显卡在笔记本上可以用。
台式机,就没那么多限制了,普通 GTX 的 N 卡 就可以玩 NVENC 追求画质的,请忽略这些,目前 GPU 加速编码的视频画质还逃不脱挑剔的视频编码大佬的鄙视。 |
30
mrcotter2013 OP @likuku #29 GPU 硬件编码得到的画质较差是共识,这么多年都这样..... 直播类型、需要实时传输的视频不追求高画质,HEVC 又能极大地缩小体积,更倾向于用硬件编码
|
31
JerryCha 2018-02-25 21:08:18 +08:00
gui 用户路过
|
32
njwangchuan 2018-04-24 10:52:23 +08:00
@mrcotter2013 请教楼主一个问题,我有一个需求,从 mp4 文件中抽取音频,视频只有 15fps,直接抽取音频的话,时长跟原视频不一样,调研了一下是音频和容器的帧率不一样导致。
ffmpeg -i iput.mp4 -vn -acodec copy output.aac 原视频信息: Duration: 01:51:19.68, start: 0.000000, bitrate: 332 kb/s Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 640x272 [SAR 1:1 DAR 40:17], 263 kb/s, 15 fps, 15 tbr, 16k tbn, 30 tbc (default) Metadata: handler_name : VideoHandler Stream #0:1(und): Audio: aac (HE-AAC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 63 kb/s (default) Metadata: handler_name : SoundHandler 抽取后的音频: Duration: 01:27:37.50, bitrate: 82 kb/s Stream #0:0: Audio: aac (HE-AAC), 44100 Hz, stereo, fltp, 82 kb/s 音频码率和时长都发生了变化,重新编码录音有比较耗时,请问有什么方法能快速解决这个问题,谢谢! |
33
mrcotter2013 OP 我倒没遇到过这种,所以源视频中两者的帧率就不一样?用 -map 试试呢?
ffmpeg -i input.mp4 -map 0:1 -c:a copy output.aac 如果仍然会变,那就必须重编码 ffmpeg -i input.mp4 -map 0:1 -c:a libfdk_aac output.aac |
34
mgcnrx11 2019-02-08 10:17:32 +08:00
brew 上关于 ffmpeg 的编译选项都被移除了,尝试找了一个别人维护的 formula
https://github.com/justinmayer/homebrew-tap/blob/master/Formula/ffmpeg.rb tag 完后,执行编译安装的选项可能略有不同 brew install justinmayer/tap/ffmpeg --with-fdk-aac --with-libass --with-libbluray --with-webp |
35
thelderfrog 2019-03-05 12:05:06 +08:00
https://uploader.shimo.im/f/A6zlKDoviNYGNj9B.zip?attname=BilibiliEncoder.dmg.zip
做了一个 GUI,libx264 参数可调,支持 VideoToolbox 硬件加速 ![1.png]( https://i.loli.net/2019/03/05/5c7df4a3a4ef0.png) ![2.png]( https://i.loli.net/2019/03/05/5c7df4a3aaca7.png) |
36
dxppp 2022-06-20 17:51:27 +08:00
现在我为了压制 h265 会这么用
ffmpeg -i input.mp4 -c:v hevc_videotoolbox -crf 20 -preset slow -c:a libfdk_aac -tag:v hvc1 output.mp4 |