「支持多少种格式」这句话没有意义,除非说清是哪一层。 容器层认得、编码层解得开,是两个独立的清单——少任何一个,表现都是打不开。
上一节讲了 VLC 是什么,这一节把它号称的能力拆开数一遍。 数出来的数比宣传页有用:宣传页说「支持几乎所有格式」, 而你手上这台机器实际能解的只有那么多。 这一节的方法可以套到任何播放器上——包括你自己写的那个。
一、能力分三层,别混着说
一个播放器的「支持」分三层,每层的判断依据完全不同。
| 层 | 管什么 | 怎么判断 | 缺了的表现 |
|---|---|---|---|
| 协议层 | 地址能不能打开 | 看能不能建连接 | 直接报错打不开 |
| 容器层 | 能不能拆出包 | 看格式注册表 | 能连上但没画面 |
| 编码层 | 能不能解成帧 | 看解码器注册表 | 有包但黑屏 |
这三层的报错长得完全不一样,这是排查的关键: 协议层缺 → 立刻失败,连不上; 容器层缺 → 连上了,读到一堆字节,但说「不认识的格式」; 编码层缺 → 包拆出来了,解码器报「找不到 decoder」。 知道卡在哪一层,就知道该装什么、该换什么。
二、数一遍本机有多少
D20 数出来的结果:414 个格式名目、557 个编解码器。 其中能当输入用的 368 个,能当输出用的 182 个。
这三个数要这么读:
| 数 | 含义 | 为什么不是最大 |
|---|---|---|
| 414 | 注册表里的全部名目 | 含只用一次的别名 |
| 368 | 能读的 | 有些只用来写 |
| 182 | 能写的 | 能读的比能写的多得多 |
「能读 368 而能写只有 182」这个差距不是 bug:现实里格式的变体极多,解析一个别人的文件容易, 生成一个别人认的文件难。 写要比读严格得多——读的时候可以宽容,写的时候一点不合规就没人认。
三、监控这门里,哪几个名字必须认得
D20 挑的十个名字,正好覆盖监控链路的每一环:
| 名字 | 属于哪层 | 什么时候用 |
|---|---|---|
| rtsp | 协议 | 连摄像机,最常见 |
| rtp | 协议 | 裸 RTP 流,抓包分析时 |
| sdp | 协议 | RTSP 里带的那段描述 |
| mpegts | 容器 | GB/T 28181 用的就是它 |
| flv | 容器 | 网页直播 |
| h264 | 编码 | 主流摄像机 |
| hevc | 编码 | 4K 与新设备 |
| mjpeg | 编码 | 老式网络头 |
| rawvideo | 编码 | 不压缩,调试用 |
| rtmp | 协议 | 推流到直播平台 |
本机这十个里 rtmp 是「无」,这点值得单独说:RTMP 需要 librtmp 或新版 FFmpeg 内置的 rtmp 支持, 不是所有构建都带。 这就是「同一份代码换台机器就跑不了」的典型原因——不是代码错,是那份二进制没编进去。
四、功能清单里最容易被忽略的三项
宣传页只讲格式,不讲这三件事,但它们决定能不能用在项目里:
| 能力 | 为什么重要 | 怎么验 |
|---|---|---|
| 多路并发 | 几十路上限差很多 | 同时开十路看 CPU |
| 硬解 | 能省一大半 CPU | 看有没有 d3d11va/cuvid |
| 码流切换 | 主码流卡了切子码流 | 看能不能双流并存 |
第二项在监控里是硬需求:几十路 1080p 用软解,一台机器撑不了几路;硬解能把 CPU 从满载压到三成。 但硬解不是白给的——它对像素格式、分辨率上限、并发数都有额外限制,调不通时表现是「能解但花屏」。
五、动手 Demo:数一遍本机的格式与解码器
不查资料、不背清单,直接问 FFmpeg 库:你认识多少个名字? 这些数字就是你手上这台机器真实的天花板,和宣传页无关。
import av
from av.format import ContainerFormat
n_fmt = len(list(av.formats_available))
n_codec = len(list(av.codecs_available))
n_in = n_out = 0
for nm in av.formats_available:
cf = ContainerFormat(nm)
n_in += bool(cf.is_input)
n_out += bool(cf.is_output)
T([u"格式", u"%d" % n_fmt, u"能读 %d" % n_in,
u"能写 %d" % n_out], [0, 0, 0, 0])
T([u"编解码器", u"%d" % n_codec], [0, 0])
实跑输出:
--------------------------------------------------------------------
功能清单不靠背,数一遍本机支持多少
--------------------------------------------------------------------
**VLC 的卖点是「什么都能放」,这个「什么」到底是多少?** 不看宣传页,
直接数本机 FFmpeg 库的注册表。
FFmpeg 库版本:62.12.102
能力 本机数量 怎么数出来的
-------------------------------------------------------------
容器/协议格式 414 av.formats_available 总量
其中能读 368 is_input 为真
其中能写 182 is_output 为真
编解码器 557 av.codecs_available 总量
两项都不占 0 构造失败,跳过
**挑几个和监控直接相关的,看本机认不认:**
名字 在不在 用途
---------------------------------------------------
rtsp 有 RTSP 协议(监控最常用)
rtp 有 RTP 裸包
sdp 有 会话描述
rtmp 无 直播推流
h264 有 H.264 解码
hevc 有 H.265 解码
mjpeg 有 JPEG 序列(很多 IP 头)
mpegts 有 TS 流(GB28181 常用)
flv 有 FLV 封装
rawvideo 有 裸像素
**这张表能解释一件常被搞混的事:**「支持 XX 格式」分两层——**容器层认得**和**编码层解得开**。
rtsp 属于容器/协议层,h264 属于编码层。两个都认,才放得出来;少任何一个,表现都是「打不开」。
VLC 之所以「什么都能放」,是因为它**自己也带了一套解码器**,不全靠系统装的。
所以在同一台机器上,VLC 能放而浏览器放不了,一点都不奇怪——它们手里的解码器清单不一样长。
414 和 557 是这台机器上的实数,换台机器装不同版本的 FFmpeg 就变。 所以「支持多少种」这种问法本身没意义——得说「这台机器上」。
那张十个名字的表里,rtmp 报「无」。这不是代码写错,是这个构建没带 RTMP 支持。 这类差异是最难查的一类故障:同一份程序在 A 机器能用、B 机器不能,日志里没有任何报错, 只有「打不开」。
所以部署前先跑一遍这种「注册表点名」,把项目要用的几个名字逐个确认——比出问题再翻日志快得多。
30 秒实验
- 把
names列表换成你项目实际用到的格式,跑一遍看有没有「无」。 - 把你平时用的播放器(不是 VLC)也装上,用同样的地址试, 看它缺哪一层——这能解释很多「为什么这个软件放不了」。
- 查一下
av.formats_available里有没有d3d11va、cuda这类硬件加速名字, 有就说明这台机器能硬解。
常见误区
- 以为「支持 H.264」就意味着能放所有 H.264。 同一个 H.264,高档位(High 10、 4:2:2)很多解码器不认;要看到 profile 级别,不是看到编码名。
- 以为格式越多越好。 实际项目只用五六个,多出来的注册项只会让「探测格式」这一步变慢。
- 以为能读写对称。 能读 368 而能写只有 182,生成一个合规文件比解析一个别人的文件难得多。
自测三问(点开对答案)
1. 「打不开」和「黑屏」分别卡在哪一层? —— 打不开多半卡在协议层或容器层(连不上、认不出格式); 黑屏是包拆出来了但解码器解不出帧,卡在编码层。 2. 为什么能读的格式比能写的多? —— 读可以宽容,遇到不规范的地方能猜;写必须严格,一个字段不合规,别人就打不开。 所以解析器总是比生成器多。 3. 同一份程序在两台机器上一台能跑一台不能,怎么快速定位? —— 先数两台机器的格式与解码器注册表,逐个点名项目用到的格式。 缺哪个立刻就知道了——这比翻日志快得多。下一节让 VLC 真连一次:在这一节的能力清单基础上,看它握手时到底发了什么、收回了什么。
- ☐ (本节完,下一节 02.01.03 VLC播放网络串流)