FFmpeg命令行高效转码 - 第4节

4. 转码流程:解码-滤镜-编码完整流水线

转码这事儿,说白了就是三件事:把压缩的视频解开,中间做点处理,再重新压回去。听起来简单,但真正跑起来,坑多得很。

我记得刚入行那会儿,接手一个批量转码任务,脚本写好了,一跑就是十几个小时。我当时觉得是编码器太慢,后来才发现——解码器根本没跑满。CPU 在等磁盘,磁盘在等内存,整个流水线断断续续的。嗯,从那以后,我每次搭转码流程都会先画一张流水线图。

核心流水线: 输入文件 → 解复用 → 解码 → 滤镜处理 → 编码 → 复用 → 输出文件

下面这张图,是我个人习惯用的转码流程框架。你一看就明白。

FFmpeg 转码流水线 输入文件 解复用 解码 滤镜 编码 复用 各阶段说明: • 输入文件:支持本地文件、管道、网络流(RTMP/HLS) • 解复用:将封装格式拆解为原始音视频流(如 MP4 → H.264 + AAC) • 解码:将压缩数据还原为 YUV/PCM 原始帧 • 滤镜:缩放、裁剪、叠加、变速等处理 • 编码:将原始帧重新压缩为目标格式 • 复用:将编码后的音视频打包为输出封装格式

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 如何定位瓶颈

我个人习惯用三步法定位瓶颈:

  1. 看 CPU 占用:top 或 htop,如果单核跑满但整体不高,说明是串行瓶颈
  2. 看磁盘 I/O:iostat -x 1,如果 %util 接近 100%,磁盘是瓶颈
  3. 看帧率日志:加 -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。

好了,这一章的内容就到这里。记住一句话:没有银弹,只有权衡。根据你的场景,选对工具,比什么都重要。