需严格按box header规则读取size字段:size为0则占剩余全部字节,为1则读8字节large_size,否则直接使用;跳过时fseek对应字节数,uuid需保留16字节uuid数据;递归解析moov子atom须以父atom总长度为边界;mdat中nalu前缀长度由avcc中lengthsizeminusone决定;大文件需依stco/co64 atom存在与否选择32/64位offset解析。

如何识别并跳过未知或非标准 Atom
MP4 文件中存在大量可选或厂商自定义 Atom(如 uuid、free、skip),解析器不能因遇到不认识的 type 就中断。关键在于严格按 Box Header 规则读取 size 字段:先读 4 字节 size,若为 0 表示该 Atom 占据文件剩余全部字节(极少见);若为 1,则必须紧接着读 8 字节 large_size 作为真实长度;否则直接用该 4 字节值。跳过时只需 fseek 或 std::istream::ignore 对应字节数,无需解析内容。
常见错误是把 size == 1 当作普通小 Box 处理,导致后续所有 offset 错位;或对 uuid Atom 忽略 16 字节 UUID 数据,实际它紧跟在 type 字段后、content 之前。
递归解析 moov 下嵌套 Atom 的边界控制
moov 是 container box,内部包含 mvhd、trak、udta 等子 Atom,而 trak 又含 mdia → minf → stbl → stco/co64 等多层嵌套。递归解析时必须用「当前 Atom 总长度」约束子解析范围,而非依赖文件 EOF 或盲目读到下一个 ftyp/moov —— 因为 Atom 可能紧邻排列,无填充。
实操建议:
- 每次进入新 Atom 前,记录起始 offset 和声明的 total size
- 子解析循环中,每读一个子 Atom,检查其 header offset + size 是否超出父 Atom 边界
- 遇到
stco(32-bit chunk offset)和co64(64-bit)必须根据 parent 的stsc(Sample-to-Chunk)表联动解析,不能孤立读取
mdat 数据块中 NALU 长度前缀的提取逻辑
H.264 视频在 MP4 中不使用 start code(00 00 00 01),而是用固定字节数的 length prefix(通常 4 字节,由 avcC 中的 lengthSizeMinusOne 字段决定:0→1B, 1→2B, 3→4B)。解析 mdat 时,必须先从 moov.trak.mdia.minf.stbl.stsd.avc1.avcC 提取该值,再按此长度切分 NALU。
容易踩的坑:
- 忽略
avcC中的configurationVersion和lengthSizeMinusOne,硬编码为 4 字节,导致 H.264 High Profile 或某些封装工具生成的文件解析失败 - 未校验 NALU length prefix 是否溢出
mdat总长度,造成越界读取 - 把
mdat当作连续字节流处理,而实际可能有多个mdatBox(尤其分片录制场景)
64 位大文件支持的关键点:co64 vs stco 和 size==1 判断
当视频很长或码率很高时,mdat 往往超过 4GB,此时其 size 字段必为 1,后跟 8 字节 large_size;同理,chunk offset 表若用 co64 替代 stco,每个 offset 就是 uint64_t 而非 uint32_t。这两者必须成对出现:若 stco 存在却尝试读 co64,会直接错位解包。
判断依据不在文件名或路径,而在 moov.trak.mdia.minf.stbl.stco 或 co64 Atom 本身是否存在。代码中需显式检查 Atom type,而非依赖文件大小猜测 —— 因为有些工具即使文件 co64 以保证兼容性。
真正复杂的地方不是语法解析,而是 offset、size、sample_index 三者在跨 Box 场景下的映射一致性:stsc 给 chunk 编号,stco/co64 给 chunk 起始位置,stsz 给每个 sample 大小,stts 给时间戳增量 —— 少一个环节对齐,整个时间轴就偏移。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











