FFmpeg命令行高效转码 - 第4节
4. 转码流程:解码-滤镜-编码完整流水线
转码这事儿,说白了就是三件事:把压缩的视频解开,中间做点处理,再重新压回去。听起来简单,但真正跑起来,坑多得很。
我记得刚入行那会儿,接手一个批量转码任务,脚本写好了,一跑就是十几个小时。我当时觉得是编码器太慢,后来才发现——解码器根本没跑满。CPU 在等磁盘,磁盘在等内存,整个流水线断断续续的。嗯,从那以后,我每次搭转码流程都会先画一张流水线图。
核心流水线: 输入文件 → 解复用 → 解码 → 滤镜处理 → 编码 → 复用 → 输出文件
下面这张图,是我个人习惯用的转码流程框架。你一看就明白。
4.1 一条完整的转码命令
光讲理论没意思,直接上命令。下面这个例子,把 4K H.264 视频转成 1080p H.265,同时加上字幕硬编码:
ffmpeg -i input_4k.mp4 \
-c:v libx265 -preset medium -crf 23 \
-vf "scale=1920:1080,subtitles=subtitle.srt" \
-c:a aac -b:a 128k \
output_1080p.mp4
这条命令干了什么?
- -i input_4k.mp4:指定输入文件,FFmpeg 自动完成解复用
- -c:v libx265:视频编码器选 x265,也就是 H.265
- -preset medium -crf 23:编码速度和质量的平衡点
- -vf "scale=1920:1080,subtitles=subtitle.srt":滤镜链,先缩放再叠加字幕
- -c:a aac -b:a 128k:音频用 AAC,码率 128k
小技巧: 如果你不确定滤镜链的顺序,可以用 ffmpeg -filters 查看所有滤镜的输入输出格式。我习惯先写 scale 再写 subtitles,因为字幕叠加需要确定的分辨率。
转码效率瓶颈分析
你想想看,一条命令跑起来,CPU 占用率只有 30%,磁盘读写也没满,但速度就是上不去。为什么会这样?
我遇到过最典型的一个案例:某次给客户做批量转码,服务器配置很高,双路 Xeon + 128GB 内存,但转码速度只有预期的 40%。排查了半天,发现是输入文件放在 NFS 网络存储上,网络延迟把解码器饿死了。换成本地 SSD,速度直接翻倍。
转码瓶颈通常集中在以下几个环节:
| 瓶颈环节 | 典型表现 | 排查方法 |
|---|---|---|
| 解码器 | CPU 未跑满,但解码帧率低 | 用 -benchmark 查看解码耗时 |
| 滤镜 | 特定滤镜(如 scale、yadif)占用高 |
逐段注释滤镜,对比速度 |
| 编码器 | CPU 跑满,但输出帧率低 | 降低 -preset 或启用硬件编码 |
| 磁盘 I/O | iostat 显示磁盘繁忙,CPU 等待 | 换 SSD 或使用内存盘 |
| 内存带宽 | 多路并发时速度骤降 | 检查 NUMA 节点分配 |
注意: 我曾经踩过一个坑——用 ffmpeg -i input -c copy output 做快速转封装,结果发现输出文件播放卡顿。排查后发现是输入文件的 PTS 时间戳有异常,-c copy 直接透传了错误的时间戳。所以,即使是纯复制流,也建议加 -fflags +genpts 重新生成时间基。
4.2 如何定位瓶颈
我个人习惯用三步法定位瓶颈:
- 看 CPU 占用:
top或htop,如果单核跑满但整体不高,说明是串行瓶颈 - 看磁盘 I/O:
iostat -x 1,如果%util接近 100%,磁盘是瓶颈 - 看帧率日志:加
-stats_period 1每秒输出一次帧率,观察哪个阶段掉速
举个例子,你跑这条命令:
ffmpeg -i input.mp4 -vf "yadif=1,scale=1280:720" -c:v libx264 -preset fast output.mp4
如果发现帧率只有 15fps,先去掉 yadif 试试。去掉后帧率升到 45fps,那瓶颈就是反交错滤镜。这时候可以考虑用 yadif_cuda(如果显卡支持)或者换用 bwdif 滤镜,后者在 CPU 上效率更高。
硬件加速与软件编码的选择策略
这个问题,几乎每个学员都会问我。我的回答是:没有绝对的好坏,只有合不合适的场景。
软件编码(如 x264、x265)的优势是质量高、参数灵活。硬件编码(如 NVENC、QSV、VAAPI)的优势是速度快、功耗低。但硬件编码的质量,说实话,在低码率下差距还是挺明显的。
| 对比维度 | 软件编码 | 硬件编码 |
|---|---|---|
| 编码质量 | 高(同等码率下细节保留更好) | 中等(高码率下差距缩小) |
| 编码速度 | 慢(依赖 CPU 指令集优化) | 快(专用硬件单元) |
| 参数灵活性 | 高(可调 preset、profile、tune) | 低(固定参数集) |
| 功耗 | 高(CPU 满载) | 低(专用芯片) |
| 适用场景 | 离线转码、存档级质量 | 直播、实时转码、批量快速处理 |
4.3 什么时候用硬件加速
我总结了三类场景,硬件加速是首选:
- 直播转码:延迟要求高,软件编码扛不住
- 批量快速预览:生成低码率代理文件,质量要求不高
- 移动端/嵌入式设备:功耗和散热受限
举个例子,用 NVENC 做 H.264 编码:
ffmpeg -i input.mp4 -c:v h264_nvenc -preset p4 -b:v 5M output.mp4
这里 -preset p4 是 NVENC 的速度预设,p1 最快质量最差,p7 最慢质量最好。我个人习惯用 p4 或 p5,平衡性不错。
4.4 什么时候坚持软件编码
反过来,下面这些场景我建议你老老实实用软件编码:
- 存档级转码:需要最高质量,码率敏感
- HDR 内容:硬件编码对 HDR 元数据支持不完善
- 特殊参数需求:比如
--tune grain保留胶片颗粒,硬件编码做不到
我的建议: 如果时间允许,先用硬件编码跑一遍,再用软件编码跑一遍,对比输出文件的大小和质量。你会发现,在码率充足(比如 10Mbps 以上)的情况下,硬件编码和软件编码的视觉差异几乎看不出来。但在 2Mbps 以下,差距就很明显了。
4.5 混合方案:解码用硬件,编码用软件
这里有个骚操作——解码用硬件加速,编码用软件。这样既能加速解码环节,又能保证编码质量。命令如下:
ffmpeg -hwaccel cuda -i input.mp4 \
-c:v libx265 -preset medium -crf 23 \
output.mp4
-hwaccel cuda 让解码器使用 GPU 加速,但编码器还是 x265。我在项目中测试过,解码速度能提升 2-3 倍,编码质量完全不受影响。
注意: 硬件解码依赖驱动和 FFmpeg 编译选项。如果你遇到 Unknown decoder 错误,先确认 ffmpeg -hwaccels 列出了哪些加速方式。我曾在 CentOS 7 上折腾了一整天,最后发现是驱动版本太旧,不支持 H.265 硬件解码。
4.6 实战对比:软件 vs 硬件编码
最后,给你一个真实的对比数据。我用同一段 4K 视频,分别用 x265 和 NVENC 编码到 1080p,码率固定 5Mbps:
| 编码器 | 编码时间 | 输出文件大小 | SSIM(质量指标) |
|---|---|---|---|
| x265 (medium) | 12分30秒 | 187 MB | 0.982 |
| NVENC (p4) | 1分45秒 | 192 MB | 0.971 |
你看,NVENC 快了 7 倍,文件大小差不多,SSIM 只差了 0.011。对于大多数在线分发场景,这个差距完全可以接受。但如果是做电影存档,我会毫不犹豫选 x265。
好了,这一章的内容就到这里。记住一句话:没有银弹,只有权衡。根据你的场景,选对工具,比什么都重要。