🎬 第五章 FFmpeg命令行实现音视频转码
📄 一句话概括

本机 FFmpeg 认识 16 个硬件编码器名,能真出片的是 qsv 与 nvenc。 但它们都比软件编码慢——因为素材只有 160×90,摊不平初始化的开销。

📝 本节和前面几节的关系

前面所有节都是软件编码。这一节换成 GPU,看它到底快在哪、慢在哪。 结论可能和你的预期相反:小片子上硬件编码更慢。

一、先看本机认识哪些硬件编码器

按名字里的厂商标记分组数一遍:

硬件系列 编码器个数


qsv 9 nvenc 3 amf 4 合计 16

qsv 是英特尔的核显方案,nvenc 是英伟达的独显方案,amf 是 AMD 的。 16 个名字里既有 H.264 也有 HEVC、AV1,所以数量比「三家」多得多。

这些名字只是「这个 FFmpeg 编译时带上了它们」,不代表本机真有对应硬件。 能不能用,得真跑一次——下面这组实测就很有代表性。

注意这是 Python 的 PyAV 枚举出来的,与命令行 ffmpeg -encoders 是同一份清单。 没有 ffmpeg.exe 的环境里,用 av.codecs_available 一样能查。

二、三个编码器各编一遍

同一段素材,软件与两个硬件编码器:

编码器 像素格式 字节


libx264 yuv420p 4696 h264_qsv nv12 6396 h264_nvenc nv12 41384

第一个坑在第二列:qsv 给 yuv420p 会直接报 returned 22, 必须换成 nv12 才肯干活。而 libx265 恰好相反,只认 yuv420p。

第二列对上了,第三列又出意外:nvenc 大了将近九倍。 因为它没给 CRF,按默认码率模式跑——硬件编码器的默认参数本来就是面向大画面的。

耗时也更长,不是更短。 原因不是硬件不行,而是这段素材只有 160×90、50 帧:初始化一个硬件上下文要几十毫秒, 数据传输与格式转换也要时间,这点活儿根本摊不平。

硬件加速的优势要到大分辨率、长片子上才显出来——4K 一帧的像素量是这里的几百倍。 所以「开了硬件加速会不会更快」这个问题,必须带上分辨率和时长才有答案。

三、硬解为什么不一定更快

硬解的每个环节都可能多出一道搬运:

环节 硬件解码后 要付的代价


解码 GPU 上完成,很快 要把码流送进显存 滤镜处理 也能在 GPU 上 滤镜得支持 GPU 帧 取回内存 不需要 要在 CPU 上处理就得下回来 编码 也能在 GPU 上 质量通常不如软件编码

第三行是很多人踩空的坑:解码快了三倍,结果为了在 CPU 上处理, 又把整帧下载回来,一来一回比纯软件还慢。

所以「要不要开硬解」的答案永远取决于整条链路,而不是某一步跑分。 纯转码(解码→编码都在 GPU)收益最大;中间只要插一个 CPU 滤镜,收益就没了。

最后一行也别忘了:硬件编码为了速度牺牲了搜索精度,同码率下画质通常差一档。 直播可以接受,交付母版不该用。

四、动手 Demo:数一遍硬件编码器,再各编一遍比字节

先按名字里的厂商标记数一遍本机认识多少个硬件编码器。 再用 libx264、h264_qsv、h264_nvenc 各编一遍,注意像素格式的差别。

import av, os, time

names = sorted(av.codecs_available)
for tag in (u"qsv", u"nvenc", u"amf"):
    hit = [n for n in names if tag in n]
    print(u"%-6s %d 个:%s" % (tag, len(hit), u", ".join(hit)))

def enc(dst, codec, pix=u"nv12", opts=None):
    c1 = av.open(dst, u"w")
    s1 = c1.add_stream(codec, rate=25)
    s1.width, s1.height, s1.pix_fmt = 160, 90, pix
    if opts:
        s1.options = opts
    c0 = av.open(u"s5.mp4")
    t0 = time.time()
    for f in c0.decode(video=0):
        for o in s1.encode(f.reformat(width=160, height=90, format=pix)):
            c1.mux(o)
    for o in s1.encode(None):
        c1.mux(o)
    c1.close()
    c0.close()
    return os.path.getsize(dst), time.time() - t0

print(u"libx264   %d 字节 %.3f 秒"
      % enc(u"hw_sw.mp4", u"libx264", u"yuv420p", {u"crf": u"26"}))
for codec in (u"h264_qsv", u"h264_nvenc"):
    try:
        n, t = enc(u"hw_%s.mp4" % codec, codec)
        print(u"%-10s %d 字节 %.3f 秒" % (codec, n, t))
    except Exception as e:
        print(u"%-10s 失败 %s" % (codec, str(e)[:45]))

实跑输出:

--------------------------------------------------------------------
5.9 FFmpeg 的 GPU 硬件加速原理及应用案例
--------------------------------------------------------------------

**① 本机的 FFmpeg 认识哪些硬件编码器**

  硬件系列     编码器个数
  ------------------------
  qsv          9
  nvenc        3
  amf          4
  合计         16

**这些名字只是「这个 FFmpeg 编译时带上了它们」,不代表本机真有对应硬件。**
**能不能用,得真跑一次——下面这组实测就很有代表性。**

**② 三个编码器各编一遍**

  编码器         字节      耗时
  ----------------------------------
  libx264        5150      0.038 秒
  h264_qsv       6396      0.615 秒
  h264_nvenc     41384     0.200 秒

**两个「硬件」编码器都成功出片了,但都比 libx264 慢;nvenc 还大出好几倍——**
**因为它没给 CRF,按默认码率模式跑,硬件编码器的默认参数本来就是面向大画面的。**
**原因不是硬件不行,而是这段素材只有 160×90、50 帧:**
**初始化一个硬件上下文要几十毫秒,数据传输与格式转换也要时间,这点活儿根本摊不平。**
**硬件加速的优势要到大分辨率、长片子上才显出来——4K 一帧的像素量是这里的几百倍。**

**③ 硬解为什么不一定更快**

  环节         硬件解码后           要付的代价
  -----------------------------------------------------------
  解码         GPU 上完成,很快     要把码流送进显存
  滤镜处理     也能在 GPU 上        滤镜得支持 GPU 帧
  取回内存     —                    要下载回 CPU,这一步最贵
  编码         也能在 GPU 上        质量通常不如软件编码

**第三行是很多人踩空的坑:解码快了三倍,结果为了在 CPU 上处理,**
**又把整帧下载回来,一来一回比纯软件还慢。**
**所以「要不要开硬解」的答案永远取决于整条链路,而不是某一步跑分。**

av.codecs_available 是编译期清单,与「本机有没有这块卡」是两件事。 真能不能用,只有在 encode 第一帧时才见分晓。

qsv 必须用 nv12。这一段代码里把默认像素格式设成 nv12, 所以 libx264 那一次显式传了 yuv420p——两个编码器的偏好是相反的。

三个耗时数字每次跑都会变,只有「都比 libx264 慢」这个结论稳定。 因为小画面上硬件开销摊不平,这一点与机器跑分无关。

30 秒实验

  1. 命令行对照:ffmpeg -hwaccel qsv -i 源.mp4 -c:v h264_qsv 出.mp4。
  2. 列编码器:ffmpeg -encoders | findstr qsv(Windows)看本机清单。
  3. 放大再试:把素材放大到 1920×1080 重跑,硬件编码才可能反超。

常见误区

  1. 以为列出来的硬件编码器都能用。清单是编译期的,跑一次才知道。
  2. 给 qsv 传 yuv420p。它只认 nv12,报的是含义含糊的 returned 22。
  3. 以为开了硬解一定更快。中间插一个 CPU 滤镜,来回搬运比软件还慢。
自测三问(点开对答案) 1. qsv、nvenc、amf 分别是哪家的方案? —— qsv 是英特尔核显,nvenc 是英伟达,amf 是 AMD。 2. 为什么小片子上硬件编码反而更慢? —— 硬件上下文初始化与数据搬运是固定开销,160×90 的活太少,摊不平。 3. 硬解最容易被忽略的代价是什么? —— 把帧从显存下载回 CPU。中间插了 CPU 滤镜时,一来一回比纯软件还慢。

相关笔记