mkv 什么都能装,webm 只认自家编码,avi 装得下但很浪费字节。 选容器其实是选「给谁看」,不是选技术优劣。
前四节各转一种格式,这一节横向比一遍。 比的时候要记住:四行的差异里,容器与编码各占一部分。
一、四个容器各转一遍
同一批帧,四个组合:
容器 编码 字节 耗时
mkv H.264 4517 0.04 秒 webm VP9 4173 0.10 秒 mov H.264 4643 0.04 秒 avi MPEG-4 16708 0.02 秒
webm 那一行最小,是因为 VP9 比 H.264 压得更狠,不是容器省了字节。 avi 那一行最大,是因为 MPEG-4 是上一代编码器。
耗时那一列只看量级:VP9 比 H.264 慢两倍多,其余三个在同一档, 小数点后一位随手一跑就会变。
所以这四行比的不只是容器,还有编码——要单独看容器的影响,得固定编码再比一次。 5.4.3 的 AVI 那一组就是这么做的,结论是 AVI 会额外多花一倍。
二、webm 只认自家编码
往 webm 里塞 H.264,会被直接拒:
目标 用 H.264 写
webm 被拒,报错点名 libx264 mkv 成功
这个报错是最友好的一类:它不说「格式不支持」,而是明确指出「这个盒子不装这个名字的编码」。 顺着这句话去查 webm 的白名单,一步就到位。
webm 的白名单就三样:视频 VP8/VP9/AV1,音频 Vorbis/Opus。 当初定这个标准就是为了「免专利」,所以把有专利的编码全挡在门外。
三、按「给谁看」来选
不是按技术优劣,是按对方能不能播:
要给谁看 选什么
浏览器、网页 mp4(H.264+AAC) 要开源、免专利 webm(VP9+Opus) 要装字幕、多音轨 mkv 要推流、随时接入 ts
mkv 排第三是因为它最好说话:几乎什么编码都能装,字幕与多音轨支持得最全。 所以做中间文件时用它,最后交付再转成对方要的那个。
这条「中间用 mkv、交付用 mp4」的习惯,能省掉大量「又要重转一遍」的时间。
四、动手 Demo:四个容器各转一遍,再故意往 webm 里塞 H.264
同一批帧分别写进 mkv、webm、mov、avi,比较字节与耗时。 最后往 webm 里塞 H.264,看报错怎么点名。
import av, os, time
def to(dst, fmt, codec, opts=None):
c1 = av.open(dst, u"w", format=fmt)
s1 = c1.add_stream(codec, rate=25)
s1.width, s1.height, s1.pix_fmt = 160, 90, u"yuv420p"
if opts:
s1.options = opts
c0 = av.open(u"s5.mp4")
t0 = time.time()
for f in c0.decode(video=0):
fr = f.reformat(width=160, height=90, format=u"yuv420p")
for o in s1.encode(fr):
c1.mux(o)
for o in s1.encode(None):
c1.mux(o)
c1.close()
c0.close()
return os.path.getsize(dst), time.time() - t0
for name, fmt, codec, opts in (
(u"mkv", u"matroska", u"libx264", {u"crf": u"26"}),
(u"webm", u"webm", u"libvpx-vp9", {u"crf": u"40", u"b": u"0"}),
(u"mov", u"mov", u"libx264", {u"crf": u"26"}),
(u"avi", u"avi", u"mpeg4", None)):
n, t = to(u"x.%s" % name, fmt, codec, opts)
print(u"%-5s %6d 字节 %.2f 秒" % (name, n, t))
try:
to(u"bad.webm", u"webm", u"libx264", {u"crf": u"26"})
except Exception as e:
print(u"webm 拒收:%s" % str(e)[:60])
实跑输出:
--------------------------------------------------------------------
5.4.5 其他格式之间互转
--------------------------------------------------------------------
**① 四个容器各转一遍**
容器 字节 包数 耗时
------------------------------------
mkv 4517 50 0.03 秒
webm 4173 50 0.10 秒
mov 4643 50 0.04 秒
avi 16708 50 0.02 秒
**四行里只有 webm 那一行小得离谱——因为它用的是 VP9,压缩率比 H.264 高一大截。**
**avi 那一行大,是因为 MPEG-4 是上一代编码器。所以这四行比的不只是容器,还有编码。**
**② webm 只认自家编码**
目标 用 H.264 写 结论
-----------------------------------------------------
webm 被拒(点名 libx264) 只认 VP8/VP9/AV1
mkv 成功 什么都能装
**第二行的报错会直接点名 `libx264`,这是最好的一类报错:**
**它不说「格式不支持」,而是明确指出「这个盒子不装这个名字的编码」。**
**③ 选容器的顺序**
要给谁看 选什么
-------------------------------------------
浏览器、网页 mp4(H.264+AAC)
要开源、免专利 webm(VP9+Opus)
要装字幕、多音轨 mkv
要推流、要能随时接入 ts
**mkv 排第三是因为它最好说话:几乎什么编码都能装,字幕与多音轨也支持得最全。**
**所以做中间文件时用它,最后交付再转成对方要的那个。**
VP9 要显式给 b=0,不然它按默认的两遍式码率跑,会很慢。
crf 在 VP9 里的取值范围是 0 到 63,和 x264 的 0 到 51 不一样。
四个文件的扩展名与格式名要对应上。
mov 与 mp4 其实是同一个家族,ffmpeg 里分别对应两个封装器名。
报错里那句「点名 libx264」非常有价值: 它说明失败点不在命令,而在「容器与编码的搭配」,方向一下就清楚了。
30 秒实验
- 命令行对照:
ffmpeg -i 片子.mp4 -c copy 出.mkv,mkv 几乎什么都收。 - 塞错编码:
-c copy 出.webm,看它怎么拒绝。 - 换 VP9:
-c:v libvpx-vp9 -crf 40 -b:v 0 出.webm,慢但小。
常见误区
- 以为 webm 是「开源版 mp4」。它的编码白名单很窄,H.264 根本进不去。
- 拿 avi 当通用交付格式。老、大、索引在末尾,三个短板都在。
- 转完不看对方能不能播。兼容性问题是转码里最常见的返工原因。
自测三问(点开对答案)
1. webm 能装哪几种视频编码? —— VP8、VP9、AV1。音频是 Vorbis 与 Opus。 2. 为什么 mkv 适合当中间文件? —— 几乎什么编码与字幕都能装,不挑食,转来转去不会因为容器被卡住。 3. 比较容器对体积的影响时要注意什么? —— 必须固定编码器与参数,否则比出来的是编码差异,不是容器差异。- ☐ 5.4 完,下一节 5.5.1 单声道与立体声互转