🎬 第四章 FFmpeg命令行实现音视频转封装
📄 一句话概括

同一份素材试五个盒子:四个成功,webm 一口回绝。 拒的理由是「装不进 libx264」,不是「你的命令写错了」。

📝 本节和前面几节的关系

4.3.1 与 4.3.2 是两个具体盒子,这一节把它们并排比一遍。 比完就能总结出一条判断顺序:先问接不接,再问转不转。

一、五个盒子,四种结果

同一份 H.264 加 AAC 的素材,转五个方向:

目标格式 结果 字节或原因


flv 成功 37807 matroska 成功 36531 mov 成功 38033 mpegts 成功 63920 webm 失败 装不进 libx264

同样内容,字节从 36531 到 63920,差了 75%——全差在盒子的记账方式上。 mkv 最省(索引紧凑),ts 最贵(每 188 字节就带一个包头)。

所以「换个格式能不能变小」这个问题,答案基本是「不会」: 包还是那些包,能省的只有目录;想真变小,只能重编码。

二、webm 为什么一口回绝

它拒的不是「H.264 这个编码不好」,而是「这个规范里根本没写它」:

webm 只接受 具体是


视频 VP8、VP9、AV1 音频 Vorbis、Opus

所以遇到这种拒绝,只有两条路:换成它认识的编码(重编码),或者换个盒子。 如果目的只是「给网页用」,mkv 与 mp4 都能达到,未必要 webm。

这也是「先想清楚目的」比「先记住格式对应关系」有用的地方: 要的是「浏览器能播」,不是「必须是 webm」——需求一变,路就宽了。

三、判断顺序:三个问题

拿到「A 转 B」这个需求,按顺序问三句:

先问什么 答「是」 答「否」


目标盒子接不接这种编码 转封装 转码 目标设备认不认这种编码 转封装 转码 时长与画质要不要改 转封装 转码

三个问题全答「是」才能只转封装;有一个「否」就得重编码。 先问再敲命令,比敲完看报错快得多——这是这一整章最实用的一条。

而且这三问的顺序不是随便排的:第一问最容易被忽略,也最容易导致失败。 很多人一上手就写 -c copy,撞了墙才回头看盒子认不认。

四、动手 Demo:五个盒子并排试,成功的报字节,失败的报原因

同一份素材依次转 flv、mkv、mov、ts、webm,把结果摆成一张表。 重点是失败那一行给出的是「装不进什么」,而不是一句含糊的「不支持」。

import av, os, re

TRY = [(u"flv", u"o.flv"), (u"matroska", u"o.mkv"),
       (u"mov", u"o.mov"), (u"mpegts", u"o.ts"),
       (u"webm", u"o.webm")]

for fmt, dst in TRY:
    try:
        c0 = av.open(u"m4.mp4")
        c1 = av.open(dst, u"w", format=fmt)
        mp = {s.index: c1.add_stream_from_template(s) for s in c0.streams}
        for pk in c0.demux():
            if not pk.size:
                continue
            pk.stream = mp[pk.stream.index]
            c1.mux(pk)
        c1.close()
        c0.close()
        print(u"%-9s 成功 %d" % (fmt, os.path.getsize(dst)))
    except Exception as e:
        m = re.search(u"does not support '([^']+)'", str(e))
        print(u"%-9s 失败 %s" % (fmt, m.group(1) if m else type(e).__name__))

实跑输出:

--------------------------------------------------------------------
4.3.3 其他格式转换——哪些能转、哪些一口回绝
--------------------------------------------------------------------

**① 同一份素材,试五个盒子**

  目标格式     结果     字节或原因
  ----------------------------------------
  flv          成功     37807
  matroska     成功     36531
  mov          成功     38033
  mpegts       成功     63920
  webm         失败     装不进 libx264

**② 失败那一行的原因值得读一遍**

**webm 只接受 VP8/VP9/AV1 视频和 Vorbis/Opus 音频,塞 H.264 进去必然被拒。**
**这不是 ffmpeg 在挑刺,是 webm 这个规范自己写死的——它本来就是给网页用的一族编码。**

**③ 转封装和转码的判断顺序**

  先问什么                   答「是」就走       答「否」就要
  --------------------------------------------------------------
  目标盒子接不接这种编码     转封装(copy)     转码
  目标设备认不认这种编码     转封装             转码
  时长与画质要不要改         转封装             转码

**三个问题全答「是」才能只转封装;有一个「否」就得重编码。**
**先问再敲命令,比敲完看报错快得多。**

webm 那一行报的是 libx264 这个名字:它说的是「这个编码我不接」。 这种报错比 InvalidData 友好得多——至少它点名指出了冲突的是什么。

注意每个格式都要重新开一对输入输出:上一个失败之后 c1 是坏的,不能复用。 这也是「批量转换脚本」必须逐个包 try 的原因。

t s 那一行 63920 字节,比 mp4 大 68%——多出来的全是每 188 字节一个的包头。 所以 TS 通常不拿来做存储,只拿来做传输。

30 秒实验

  1. 逐个试:ffmpeg -i 片子.mp4 -c copy 出.mkv,把扩展名换掉再试一遍。
  2. 试 webm:ffmpeg -i 片子.mp4 -c copy 出.webm,读那句 does not support。
  3. 必须转 webm 时:ffmpeg -i 片子.mp4 -c:v libvpx-vp9 -c:a libopus 出.webm,这就是重编码了。

常见误区

  1. 以为「换个格式就能变小」。包还是那些包,能省的只有目录。
  2. 看到 does not support 就去改命令。它说的是编码不匹配,改命令没用,要么换编码要么换盒子。
  3. 批量转换时不逐个抓异常。中间一个失败,后面的全跟着挂。
自测三问(点开对答案) 1. webm 拒绝 H.264 时,报错信息里通常会提到什么? —— 会点名那个编码(如 `libx264`),说明是「这个编码我不接」而不是「命令写错」。 2. 同样内容,为什么 ts 比 mkv 大那么多? —— 因为 TS 每 188 字节就带一个包头,mkv 的索引与块结构紧凑得多。 3. 「A 转 B」的三问是什么顺序? —— 先问盒子接不接这种编码,再问目标设备认不认,最后问时长画质要不要改;有否就要重编码。

相关笔记