ffmpeg 转码心得

我菜,我紫菜

目录

前言

请注意,本文创建于 2019 年,其中涉及的 h264 和 h265 的兼容性的问题可能已经不再符合如今的实际情况。

本菜鸡用 ffmpeg 也有一段时间了,平时都是用来压制冻鳗、演唱会或者视频录像,试来试去也踩了不少坑…于是决定水一篇

常用选项

-c:a copy

这是我常用参数之一,-c:a copy 表示不会对音频进行重新编码

为啥?

首先音频轨道的体积相对于整个文件来说是比较小的,一般来说,对音频重新压缩体积小不了多少,但是音质会有明显的降低,是得不偿失的

其次,就算音频轨道是 FLAC 96000kHz 24bit,无损音频它不香吗?

-c:v h264

H264 大概是我最常用的视频编码方式了

平常所说的 .avi .mp4 .mkv 都是视频格式,是一种容器,容器里包含了一个或多个视频/音频轨道,每一个视频轨道的编码方式称之为视频编码,常见的视频编码格式有 h264 h265 vp9 mpeg4 等等…

为什么用 h264?

就目前情况来看,h264 是压缩率比较高,支持设备比较多的一种格式

支持设备多意味着能够被硬解码,硬解意味着能够调用 GPU 而不是 CPU 更加流畅、省电地播放视频

h265 可以说是 h264 的进化版本,相同视频质量下,体积可以减少40%左右,一般用于高清视频的压制

市面上大多数新出的设备都能硬解 h265,但还有更多的老设备在播放 h265 仍然只能软解,cpu 占用 100%,风扇呼呼响,却只能看个 ppt

然后我要吐槽一下 Apple

因为 Copyright 问题,苹果硬解 h264 会有许多麻烦,百元安卓机可以 youtube 4k 60fps,而上千的 iphone 打死只能开到1080p

还有那蜜汁 macbook 的硬解,视频是能放,但风扇响不响就是另一个问题了,就像库克所说的 It just works ……

吐槽完了回到正题

ffmpeg 的 h264 编码默认采用 vbr 码率控制方式,VBR 会根据视频内容动态调整码率,视频变化多的时候分配高码率,视频画面静止的时候分配低码率,优点是能保证视频质量,缺点是无法预测视频大小,如果用于直播,可能会出现卡顿。

除此之外,还可以用 crf 值来指定 VBR 的码率,crf 的取值范围介于 0-51,一般来说,18-28 是一个合理的范围,默认值为 23,18 被认为是视觉无损,因此如果觉得 vbr 码率偏高或偏低,可以适当调整 crf。

若 Crf 值加 6,输出码率大概减少一半;若 Crf 值减 6,输出码率翻倍(在 8bit 的前提下)。

-preset medium

使用预设,预设是一系列参数的集合,不同的预设对应不同的编码速度和压缩率,编码速度越慢,压缩率越高。

假如你很有耐心,通常的建议是使用较慢的预设,目前所有的预设按照编码速度降序排列

  1. ultrafast
  2. superfast
  3. veryfast
  4. faster
  5. fast
  6. medium
  7. slow
  8. slower
  9. veryslow
  10. placebo

默认值是 medium,请不要使用 placebo,因为它以极高的编码时间为代价,仅仅提升了 1% 左右的压缩率,这是一种收益递减准则,veryslow 与 slower 相比提升了 3%;slower 与 slow 相比提升了 5%;slow 与 medium 相比提升了5%~10%。你可以使用 --preset 来查看预设列表,也可以通过 x264 --fullhelp 来查看预设所采用的参数配置

在测试中,用不同的预设重现编码动画测试片段

ffmpeg -i test.mp4 -c:a copy -c:v libx264 -preset [preset] test_[preset].mp4

文件大小结果如下(test.mp4是源文件)

文件大小结果

如果说 medium 的编码速度为 4x,大致来说每个等级之间相差 1x,到 veryslow 时甚至慢到0.5x

而 superfast 速度飙到 15x,utralfast 更是快到了 20x

-tune animation

-tune 的参数主要配合视频类型和视觉优化的参数,或特别的情况。如果视频的内容符合其中一个可用的调整值又或者有其中需要,则可以使用此选项,否则建议不使用(如 tune grain 是为高比特率的编码而设计的)。

tune 的值有:

再来测一波-tune(test.mp4 是源文件,normal 是不加 -tune 参数的结果)(再说一遍,用的测试文件动画片段)

ffmpeg -i test.mp4 -c:a copy -c:v libx264 -tune [tune] test_[tune].mp4

测试结果

不出所料,animation 对动画的编码效果是最好的

关于显卡加速

一般不推荐使用,大部分情况下显卡编码效果都没有CPU编码好

但是,它快啊,快到离谱

市面上大部分新的 intel CPU 都有 QSV 芯片模块,用于加速视频的编码解码

查看 ffmpeg 支持的 qsv 编码器,在 windows 下是 findstr,在 linux 下是 grep

ffmpeg -decoders | findstr qsv

然后瞎用就是了

ffmpeg -i test.mp4 -c:v h264_qsv -c:a copy output.mp4

详情参考 ffmpeg 使用QSV 硬件加速视频转码 或自行问 Google

又快又好 - 分布式转码

原理很简单,主机用 ffmpeg 将原视频无损切片(切片速度很快,跟复制差不多),将切好的视频片段分发到多个 Worker 中,多个 Worker 同时开始转码视频片段,转码完成后发送回主机,主机再将所有视频片段拼接

有人用 hadoop 实现了,我觉着就是切香蕉用杀猪刀了

python 写百来行我觉着就够用(不考虑 Worker 宕机,假设网络稳定)(挖坑预定)

切片

ffmpeg -i input.mp4 -acodec copy -vcodec copy \
-f segment -segment_time 20 -reset_timestamps 1 -map 0:0 -map 0:1 %d.mp4

转码

ffmpeg -i input.mp4 -vcodec libx264 -s 1280x720 output.mp4

合并

ffmpeg -f concat -i filelist.txt -c copy output.mp4

参考 分布式转码(三)实现