音视频修炼之容器与协议(一):MP4和MOV的box剖析

MP4 / MOV box 结构剖析

MP4 是音视频容器之王。理解 box 结构,就能理解为什么 MP4 既能流式播放,又能精确 seek、跳转章节、承载多语言字幕和元数据。


本文速览

章节 阅读重点 一句话结论
0. MP4 vs MOV 区分 QuickTime MOV 和 ISO MP4 的关系。 MP4 基本可以理解为 MOV 的标准化演进版本。
1. box 基础结构 看每个 box 如何用 size/type/payload 组织数据。 MP4 本质是一棵 box 嵌套树。
2. MP4 顶级结构 看 ftyp、moov、mdat 的分工。 moov 是目录,mdat 是内容。
3. ftyp 文件类型 看播放器如何判断兼容品牌。 ftyp 决定"这是不是我能处理的 MP4"。
4. moov 元数据中心 看影片级、轨道级元数据如何组织。 没有 moov,只有裸媒体数据,播放器很难开播。
5. stbl sample 表 理解时间、关键帧、chunk 偏移、sample 大小如何查表。 MP4 的 seek 能力主要靠 stbl。
6. mdat 实际数据 看真实 H.264 NAL / AAC frame 放在哪里。 mdat 存数据,但解释数据要靠 moov/stbl。
7. moov 在前还是在后 理解 faststart。 HTTP 流式播放必须让 moov 前置。
8. fMP4 理解 DASH / HLS 为什么用 moof + mdat 分片。 fMP4 把一次性索引拆成每段独立索引。
9. udta 元数据 看作者、标题、章节等信息放在哪里。 udta 负责非解码必需的描述信息。
10. 解析工具 学会用工具看 box 树。 mp4dump / ffprobe 是排查 MP4 的入口。
11. 常见坑 识别 moov 太大、时基混用、stsd 多 entry 等坑。 大多数 MP4 播放问题都能在 box 表里定位。
12. 为什么 MP4 是容器之王 从流式、seek、多轨、兼容性解释 MP4 成功原因。 MP4 复杂,但功能完整、生态最强。
13. 总结 汇总实战要点。 搞懂 stsd/stts/stsc/stsz/stco/stss,就懂 MP4 一半。

0. MP4 vs MOV

格式 来源 / 标准 关系 常见差异
MOV Apple QuickTime 格式。 更早出现,是 QuickTime 生态的容器。 可能包含一些 QuickTime 私有 box 或历史字段。
MP4 ISO/IEC 14496-14,基于 ISO Base Media File Format。 可以理解为 MOV 思路的标准化版本。 更强调跨平台、流媒体和标准兼容。
结论 说明
box 结构基本一致 二者都使用 size + type + payload 的 box 嵌套结构。
兼容性很高 大量播放器和工具对 MOV / MP4 的解析逻辑可以复用。
区别多在细节 MOV 可能多一些 Apple / QuickTime 私有 box,MP4 更标准化。

1. box 基础结构

常见 box 字段布局先看图。图里列了常见 box 的字段、字节数和作用:

1.1 通用 Box Header

字段 字节数 含义 注意事项
size 4 当前 box 总大小,包含 size 和 type 本身。 普通 box 用 32-bit size。
type 4 4 字符 ASCII,例如 ftyp、moov、mdat。 是解析分支的核心依据。
large_size 8 当 size == 1 时出现,用 64-bit 表示 box 大小。 大文件或超大 mdat 常见。
payload N box 负载。 如果是容器型 box,payload 又是一串子 box。

1.2 size 特殊值

size 值 后续结构 含义 常见场景
普通大于 1 size + type + payload box 大小就是 32-bit size。 大多数 box。
1 后面追加 8 字节 large_size。 box 使用 64-bit size。 超大文件、超大媒体数据。
0 没有显式结束位置。 box 延伸到文件末尾。 mdat 常见。

1.3 box 嵌套

box 类型 payload 内容 例子
叶子 box 具体字段和数据。 ftyp、mvhd、stts、stsz。
容器 box 一系列子 box。 moov、trak、mdia、minf、stbl。
媒体数据 box 连续媒体 payload。 mdat。

2. MP4 顶级结构

顶级 box 作用 关键点
ftyp 文件类型和兼容品牌。 播放器用它判断是否支持这个文件。
moov 元数据中心。 保存时长、轨道、codec 配置、sample 索引表。
mdat 实际媒体数据。 H.264 NAL、AAC frame 等通常在这里。
其他 box 扩展信息。 例如 free、skip、uuid 等。

核心 :moov 是"目录",mdat 是"内容"。没有 moov,播放器就不知道 mdat 里哪段数据是什么时间、什么大小、是不是关键帧。


3. ftyp ------ 文件类型

ftyp 用于声明文件品牌和兼容能力。

字段 字节数 示例 作用
size 4 00 00 00 18 box 总大小,示例为 24 字节。
type 4 66 74 79 70 = ftyp 标识这是文件类型 box。
major_brand 4 6D 70 34 32 = mp42 主品牌。
minor_version 4 00 00 00 00 次版本号。
compatible_brands 4 × N mp42、isom 等 兼容品牌列表。

常见 brand 可以这样理解:

brand 含义 常见用途
mp42 MP4 v2。 常见 MP4 文件。
isom ISO Base Media。 ISO BMFF 兼容标记。
M4A Apple 音频。 .m4a 音频文件。
qt QuickTime。 MOV / QuickTime 生态。
3gp4 3GPP。 移动通信视频格式。
dash DASH。 DASH / fMP4 场景。

4. moov ------ 元数据中心

moov 是 MP4 的导航目录,里面包含影片级信息和每条轨道的信息。

子 box 层级 作用
mvhd moov/mvhd 影片级头信息,例如全局时基、总时长。
trak moov/trak 一条媒体轨道,例如视频、音频、字幕。
udta moov/udta 用户数据和元数据,例如标题、作者、章节。

4.1 mvhd

字段 字节数 作用
version + flags 4 FullBox 公共头。
creation_time 4 / 8 创建时间,v0 为 32-bit,v1 为 64-bit。
modification_time 4 / 8 修改时间,v0 为 32-bit,v1 为 64-bit。
timescale 4 整个 MP4 的全局时基,常见 1000 表示毫秒。
duration 4 / 8 按 timescale 计数的总时长。
rate 4 默认播放速率,0x00010000 表示 1.0。
volume 2 默认音量。
matrix 等 variable 显示矩阵、预定义字段、next track id 等。
计算 公式 示例
总时长秒数 duration / timescale duration=60000、timescale=1000 表示 60 秒。

4.2 trak ------ 一条流

子 box 作用 说明
tkhd track 头。 轨道 ID、宽高、持续时间等。
mdia media 信息。 包含媒体时基、handler、媒体信息。
mdhd media header。 轨道自己的 timescale 和 duration。
hdlr handler。 标识视频 / 音频 / 字幕轨。
minf media information。 媒体类型相关信息。
stbl sample table。 MP4 seek 和解码定位的核心表。

5. stbl ------ sample 表(核心中的核心)

stbl 里的一堆表共同回答 5 个问题:

问题 由谁回答 作用
这个 sample 用什么 codec 解? stsd 找到 avc1/hev1/mp4a 等 codec entry 和配置。
这个 sample 什么时候显示? stts / ctts 计算 PTS / DTS 和显示顺序。
哪些 sample 是关键帧? stss seek 时找最近同步点。
sample 属于哪个 chunk? stsc 建立 sample 到 chunk 的映射。
chunk 在文件哪个字节偏移? stco / co64 找到 mdat 里的实际位置。
sample 自己多大? stsz 在 chunk 内继续定位到具体 sample。

5.1 stsd(codec 信息)

字段 / entry 字节数 作用 常见内容
version + flags 4 FullBox 公共头。 通常为 0。
entry_count 4 codec entry 数量。 多数文件为 1。
avc1 / avc3 variable H.264 视频 sample entry。 宽高、像素信息、avcC。
hev1 / hvc1 variable H.265 视频 sample entry。 hvcC。
mp4a variable AAC 音频 sample entry。 sample rate、channel、esds。
tx3g variable mov_text 字幕。 字幕样式和文本相关配置。
avcC / hvcC / esds variable codec config。 SPS/PPS、VPS/SPS/PPS、AAC config。

关键点 :H.264 解码器需要的 SPS/PPS 通常在 avcC 里;没有这些配置,decoder 不知道 profile、level、分辨率、NAL 长度前缀等信息。

5.2 stts(时长表)

字段 字节数 含义 示例
version + flags 4 FullBox 公共头。 通常为 0。
entry_count 4 后面有多少组 (sample_count, sample_delta)。 1。
sample_count 4 × N 连续多少个 sample 使用同一个时长。 1800。
sample_delta 4 × N 每个 sample 的时长,单位是 track timescale。 33。
例子 含义
[1800, 33],timescale=1000 1800 个 sample,每个 33ms,约等于 30fps。

5.3 stss(关键帧)

字段 字节数 含义 注意事项
version + flags 4 FullBox 公共头。 通常为 0。
entry_count 4 关键帧数量。 例如 60。
sample_number 4 × N 关键帧 sample index,1-based。 例如 1, 31, 61, 91...。
情况 解释
存在 stss seek 时找不超过目标时间的最近关键帧。
不存在 stss 通常表示所有 sample 都是同步 sample,类似 MJPEG 这类帧内编码场景。

5.4 stsc(sample → chunk 映射)

字段 字节数 含义 示例
version + flags 4 FullBox 公共头。 通常为 0。
entry_count 4 映射规则条数。 1。
first_chunk 4 × N 从哪个 chunk 开始使用这条规则。 1。
samples_per_chunk 4 × N 每个 chunk 有多少 sample。 1。
sample_description_idx 4 × N 使用 stsd 的第几个 entry。 1。
场景 映射特点
简单场景 一个 chunk 一个 sample,1:1 映射。
复杂场景 一个 chunk 多个 sample,或者不同区间使用不同 stsd entry。

5.5 stco / co64(chunk 偏移)

box 偏移字段字节数 作用 适用场景
stco 4 记录每个 chunk 在文件中的 32-bit 偏移。 小于 4GB 偏移范围的文件。
co64 8 记录每个 chunk 在文件中的 64-bit 偏移。 大文件,尤其超过 4GB 时。
字段 字节数 含义
version + flags 4 FullBox 公共头。
entry_count 4 chunk 偏移数量。
chunk_offset[] 4 × N 或 8 × N 每个 chunk 的文件偏移。

这就是 MP4 能精确 seek 的关键 :先查 stss 找关键帧,再查 stsc/stco/stsz 得到字节位置,最后跳到 mdat 对应偏移读取。

5.6 stsz(sample 大小)

字段 字节数 含义 说明
version + flags 4 FullBox 公共头。 通常为 0。
sample_size 4 如果非 0,表示所有 sample 等大。 PCM 音频可能使用。
sample_count 4 sample 总数。 例如 1800。
entry_size[] 4 × N 当 sample_size == 0 时,逐个记录 sample 大小。 视频最常见,因为 I/P/B 帧大小不同。
情况 解释
sample_size == 0 每个 sample 大小不同,必须读取 entry_size[]。
sample_size != 0 所有 sample 一样大,可以省掉逐 sample 大小表。

6. mdat ------ 实际数据

项 说明
payload 内容 一堆 H.264 NAL、H.265 NAL、AAC frame、字幕 sample 等媒体数据。
排列方式 通常按 sample / chunk 顺序连续拼接。
如何定位 通过 stco/co64 找 chunk 起点,通过 stsz 和 stsc 定位 sample。
自身限制 mdat 通常只存数据,不告诉你时间、关键帧、codec 配置。

关键点 :没有 stbl,播放器就不知道 mdat 里哪段是哪个 sample,也不知道该从哪里 seek。


7. moov 在前还是在后

方式 文件顺序 播放体验 适用场景
moov 在前 ftyp → moov → mdat 拉到 moov 后就能开始播放。 HTTP 点播、渐进式下载、faststart。
moov 在后 ftyp → mdat → moov 必须先拿到文件尾部 moov 才能知道索引。 本地录制完成后再播放,或播放器支持 range 回源。
faststart 把 moov 移到 mdat 前。 改善起播速度。 Web 视频分发必备。

HTTP 流式 MP4 必须 faststart ,否则用户可能要等到文件尾部的 moov 下载完成后才能开始播。


8. fragmented MP4(fMP4)

DASH / HLS 常使用 fMP4。它把一个大 MP4 拆成初始化段和媒体分片。

段 / box 作用 内容
ftyp 文件类型。 声明 fMP4 / DASH 等兼容品牌。
moov init segment。 主要包含 codec 信息和轨道信息,不包含完整 sample 表。
moof movie fragment。 当前分片的 sample 表和索引。
mdat 当前分片媒体数据。 当前分片的 H.264 / AAC 等 sample。
后续 moof + mdat 后续分片。 直播或点播按段持续追加。
优势 说明
可分片传输 每段都有自己的 fragment 索引,适合 HTTP 分段。
可实时生成 直播时不用等完整 moov,可以持续产出 moof + mdat。
适配 DASH / HLS 现代 HLS / DASH 大量使用 fMP4 segment。

9. udta ------ 元数据(作者 / 标题)

子项 作用 常见内容
标题 展示媒体标题。 title / name。
作者 展示作者或制作方。 artist / author。
章节 支持章节跳转。 chapter track 或相关 metadata。
封面 / 扩展信息 展示专辑封面、应用私有数据等。 cover art、uuid、自定义字段。

10. 解析工具

工具 命令 适合看什么
mp4info mp4info video.mp4 快速查看 MP4 概要和 box 树。
mp4dump mp4dump video.mp4 详细查看 box 内容。
ffprobe ffprobe -v debug video.mp4 2>&1 | grep "Box" 看 FFmpeg 内部解析过程。
Bento4 mp4dump video.mp4 MP4 结构分析常用工具。
GPAC / MP4Box MP4Box -info video.mp4 查看 MP4 信息、封装和修复。

常用命令保留如下,方便复制:

bash 复制代码
mp4info video.mp4
mp4dump video.mp4
ffprobe -v debug video.mp4 2>&1 | grep "Box"
MP4Box -info video.mp4

11. 常见坑

11.1 moov 太大 → 起播慢

原因 表现 处理方式
长视频 / 多轨 / 大量 sample 表 4K 长视频 moov 可能达到 MB 级。 即使 faststart,也要先下载完整 moov 才能开播。
元数据和索引过多 起播前等待时间变长。 可考虑分片方案,如 HLS / DASH / fMP4。

11.2 sample 大小变化

情况 stsz 表现 说明
视频 sample 大小不同 sample_size == 0,必须有 entry_size[]。 I 帧大、P/B 帧小,1800 个 sample 就要记录 1800 个大小。
所有 sample 等大 sample_size != 0,可省略逐个大小。 PCM 音频这类固定大小 sample 可能使用。

11.3 时基不一致

时基 所在位置 含义 常见坑
全局 timescale moov/mvhd 整个文件的影片级时基。 常见 1000,表示毫秒。
轨道 timescale trak/mdia/mdhd 单条视频 / 音频 track 自己的时基。 视频可能是 30000、90000 等。
计算规则 各用各的 timescale。 不要把 mvhd 和 mdhd 的 timescale 混用。 混用会导致时长、PTS、seek 计算错误。

11.4 stsd 多 entry

场景 表现 影响
中途 codec 配置变化 stsd 有多个 entry。 sample 通过 stsc.sample_description_idx 标记使用哪条 entry。
不同质量 / 不同配置切换 某些特殊文件可能出现。 解码器初始化和切换要读对 entry。

12. 为什么 MP4 是音视频容器之王

优势 依赖能力 说明
流式播放友好 faststart / range request。 moov 前置后,HTTP 渐进式播放体验好。
精确 seek stco/co64、stsz、stts、stss。 可以从时间点快速换算到文件字节偏移。
多轨道支持 多个 trak。 视频、音频、字幕、多语言音轨都能放。
章节 / 字幕 / 元数据 chap、udta、字幕 track。 支持复杂媒体产品需求。
兼容性极好 浏览器、系统播放器、移动设备长期支持。 Web、移动端、桌面端生态都成熟。
适配 HLS / DASH fMP4。 现代流媒体分片协议大量使用 MP4 分片。
大厂推动 Apple / Microsoft / Google 等。 标准、工具链和平台支持稳定。
不足 说明 缓解方式
头部和索引较复杂 相比 TS / FLV,MP4 元数据表更多。 工具链成熟,问题可定位。
传统 MP4 不适合边生成边播 完整 moov 常在写完文件后生成。 用 faststart 或 fMP4。
实时直播历史上不如 TS / FLV 简单 单文件 MP4 需要完整索引。 fMP4 已解决很多直播分片问题。

13. 总结

MP4 = box 嵌套结构:

实战要点如下:

要点 作用 记忆方式
faststart moov 前置,HTTP 流式播放必备。 起播先找目录。
大文件用 co64 64-bit chunk offset,避免超过 4GB 偏移限制。 大文件别只看 stco。
关键帧靠 stss seek 要先跳到同步点。 没 stss 通常表示全关键帧。
fMP4 用于 DASH / HLS moof + mdat 分片,适合流媒体。 每段有自己的小索引。
stbl 是核心 时间、大小、偏移、关键帧、codec 配置都在这里。 弄懂 stsd/stts/stsc/stsz/stco/stss,就懂 MP4 一半。

金句 :MP4 看着复杂,但所有关键能力都藏在 stbl 那一堆表里。弄懂 stsd/stts/stsc/stsz/stco/stss 这 6 个表,就懂 MP4 一半。

相关推荐
暴雨课堂1 小时前
tp5 tp6被攻击篡改后恢复
linux·服务器·php
音草1 小时前
AVL 树详解:从概念到 C++ 实现
c++
djjjx.1 小时前
Linux进程篇(四):内核托底与生死交错 ,深度硬核剖析“僵尸”与“孤儿”进程
linux·运维·服务器
凉茶钱2 小时前
list:哨兵节点,const_iterator 和 const iterator的区别与迭代器失效
数据结构·c++·list
智能直播2 小时前
RK3576 + NDI 框架:HX2 编码输出与 HX2/FULL介绍
音视频·实时音视频·视频编解码
为思念酝酿的痛2 小时前
Reactor反应堆模式
linux·服务器·网络
沫璃染墨2 小时前
从零入门计算机网络系列(六):TCP套接字编程实战——从listen监听到客户端与服务器通信
linux·服务器·c++·tcp/ip·计算机网络·tcp
2401_872418782 小时前
把 Ubuntu 服务器变成 AI Agent 终端:用自然语言或语音管理 Linux,任何命令都先审批(附完整 Python 源码)
linux·服务器·ubuntu·agent
coderSong25682 小时前
【Ubuntu】ctrl+shift+f 繁体中文切换、VScode全集搜索
linux·vscode·ubuntu