视界原理之2D视频(二):视频文件里有什么

2D 视频文件里有什么

一个 MP4 文件不是"很多图片顺序塞在一起"。它更像一个带索引的媒体数据库:轨道、样本、时间戳、编码参数、同步点和显示元数据都被组织在里面。


先看文件内部结构

MP4 是容器,不是编码。H.264 / H.265 / AV1 负责压缩画面,MP4 / MOV / MKV 负责把压缩数据、时间信息和轨道关系组织起来。


1. 容器、轨道、样本三层要分清

层级 典型对象 工程含义
container MP4 / MOV / MKV 负责文件结构、索引、轨道组织
track video / audio / subtitle 每种媒体一条或多条轨道
sample / packet 一帧或一段编码数据 demuxer 读出来交给 decoder 的单位
codec bitstream NAL / OBU / slice decoder 真正解析的压缩语法

播放器打开文件时,先读容器,再选择轨道,再把 sample 转成 packet,最后 decoder 才开始理解 codec bitstream。


2. MP4 里哪些 box 最关键

不同容器细节不一样,但以 MP4 为例,工程上常见关键结构如下:

Box 作用 出问题的表现
ftyp 标识文件品牌和兼容性 兼容性判断失败
moov 元数据总入口 文件无法打开或索引缺失
mdat 真实媒体数据 packet 数据读取失败
trak 单条媒体轨道 找不到视频/音频轨
mdhd track 时间尺度和 duration 时长、同步异常
stsd sample description / codec config decoder 初始化失败
stts decoding time to sample DTS / duration 错误
ctts composition time offset B 帧 PTS 错误
stss sync sample / keyframe index seek 后花屏或失败
stsz sample size packet 边界错误
stco / co64 sample 文件偏移 读取错位、花屏

一个文件"ffprobe 看得到信息"不代表它的 sample table 一定完全正确。seek、变速、截断文件恢复这些场景会更容易暴露封装问题。


3. 编码参数到底保存在哪里

解码器启动前必须拿到 codec config。不同编码的名字不同,但作用相似。

编码 关键配置 用途
H.264 / AVC SPS、PPS、avcC 宽高、profile、level、参考帧、熵编码模式等
H.265 / HEVC VPS、SPS、PPS、hvcC 多层级、CTU、profile、tier、level 等
AV1 sequence header、av1C profile、level、bit depth、operating point 等
VP9 codec private / container fields profile、bit depth、color 等

参数集可以在码流里反复出现,也可以集中放在 extradata 里。移动端硬解尤其依赖初始化参数,如果 extradata 缺失、格式不对,可能表现为软解能播、硬解打不开。


4. 时间信息不只是 PTS

播放器同步靠时间信息,而不是靠"读到第几个 packet"。

时间字段 作用 常见坑
time scale / time base 把整数时间换成秒 单位换算错误导致快慢异常
DTS packet 应该进入 decoder 的时间顺序 B 帧场景必须单调
PTS frame 应该显示的时间 显示调度核心依据
duration sample 持续时间 VFR 视频必须逐帧看 duration
edit list 轨道起始偏移和裁剪 开头黑帧、音画偏移
start time 媒体流起点 多轨同步要统一基准

固定帧率视频可以看起来很简单;可变帧率、B 帧、edit list、音频 priming delay 混在一起时,时间线才是真正的复杂点。


5. 显示元数据决定"解出来以后怎么画"

decoder 主要关心码流语法,但 renderer 还需要显示相关信息。

信息 典型来源 显示阶段用途
rotation matrix container metadata 竖屏视频转正
clean aperture / crop container 或 codec 去掉编码填充边界
SAR / pixel aspect ratio codec VUI / container 计算 DAR,避免比例变形
color primaries VUI / container 判断 BT.709 / BT.2020 等色域
transfer characteristics VUI / HDR metadata 判断 SDR / PQ / HLG
matrix coefficients VUI 选择 YUV→RGB 矩阵
mastering display metadata HDR SEI / container HDR tone mapping
content light level HDR metadata 峰值亮度策略

很多"解码没错但看着不对"的问题,其实是显示元数据没有被正确传到渲染链路。


6. 解码时用什么,显示时用什么

信息 demuxer decoder renderer / display
track index 选择轨道 不关心 不关心
sample offset / size 读 packet 不关心 不关心
codec type 选择 decoder 初始化 decoder 可能用于能力策略
codec extradata 提取并传递 必须使用 通常不直接用
DTS 排 packet 决定输入顺序 间接影响队列
PTS 传递时间戳 输出 frame metadata 决定显示时刻
color metadata 传递 有时使用 必须使用
rotation / crop 传递 通常不用 必须使用
keyframe index seek flush / restart 间接影响首帧

这张表是排查播放器问题的分界线:先问"这个信息在哪一层被消费",再问"它有没有正确传过去"。


7. 文件异常怎么定位

现象 优先检查 典型工具方向
文件打不开 moov、track、codec config 容器解析、ffprobe
只有声音没画面 video track、decoder init codec id、extradata、profile
seek 后花屏 stss、IDR、参数集 keyframe index、packet 边界
时长不对 mdhd、duration、edit list time scale、start time
变速或卡顿 DTS / PTS / duration VFR、B 帧、time base
颜色异常 VUI、container color tags matrix、range、transfer
横竖屏错误 rotation matrix display matrix 传递链路

一句话总结

视频文件的价值不只是保存压缩码流,而是保存"decoder 如何解、renderer 如何画、播放器如何按时间组织"的全部上下文。

相关推荐
可乐鸡翅yeah_1 小时前
hls.js 切换多个视频源,新手开发常见踩坑
开发语言·前端·javascript·ios·ffmpeg·音视频·safari
Chen—LSN1 小时前
C语言——⽂件操作(1)
c语言·开发语言·c++·经验分享·笔记·算法·链表
传奇开心果编程1 小时前
【Flutter入门练中学】第8课:动画与过渡
android·学习·flutter·ui·ios
辛苦才能1 小时前
C++ map/set 深度解析:从关联式容器的本质到 operator[] 的三重身份
开发语言·c++
Chen—LSN2 小时前
C语言——文件操作(2)
c语言·开发语言·c++·经验分享·笔记·算法·c#
纪念 2292 小时前
C++类和对象(最终篇)
开发语言·c++
镭封2 小时前
从人工到AI:短视频配音方式正在发生哪些变化
人工智能·音视频·语音识别·媒体
LuminousCPP2 小时前
从零开始学 C++(三):类和对象入门|从 struct 到 class,理解封装、对象与 this 指针
c++·笔记·学习·类和对象