同一份素材试五个盒子:四个成功,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 秒实验
- 逐个试:
ffmpeg -i 片子.mp4 -c copy 出.mkv,把扩展名换掉再试一遍。 - 试 webm:
ffmpeg -i 片子.mp4 -c copy 出.webm,读那句does not support。 - 必须转 webm 时:
ffmpeg -i 片子.mp4 -c:v libvpx-vp9 -c:a libopus 出.webm,这就是重编码了。
常见误区
- 以为「换个格式就能变小」。包还是那些包,能省的只有目录。
- 看到
does not support就去改命令。它说的是编码不匹配,改命令没用,要么换编码要么换盒子。 - 批量转换时不逐个抓异常。中间一个失败,后面的全跟着挂。
自测三问(点开对答案)
1. webm 拒绝 H.264 时,报错信息里通常会提到什么? —— 会点名那个编码(如 `libx264`),说明是「这个编码我不接」而不是「命令写错」。 2. 同样内容,为什么 ts 比 mkv 大那么多? —— 因为 TS 每 188 字节就带一个包头,mkv 的索引与块结构紧凑得多。 3. 「A 转 B」的三问是什么顺序? —— 先问盒子接不接这种编码,再问目标设备认不认,最后问时长画质要不要改;有否就要重编码。- ☐ (本节完,下一节 4.3.4 AVI/FLV/TS 格式简介)