MP4 文件格式又被称为 MPEG-4 Part 14,出自 MPEG-4 标准第 14 部分 。它是一种多媒体格式容器,广泛用于包装视频和音频数据流、海报、字幕和元数据等。(顺便一提,目前流行的视频编码格式 AVC/H264 定义在 MPEG-4 Part 10)。MP4 文件格式基于 Apple 公司的 QuickTime 格式,因此,QuickTime File Format Specification 也可以作为我们研究 MP4 的重要参考。

作者:张武星
审核:泰一

Overview

MP4 文件由 box 组成,每个 box 分为 Header 和 Data。其中 Header 部分包含了 box 的类型和大小,Data 包含了子 box 或者数据,box 可以嵌套子 box。

下图是一个典型 MP4 文件的基本结构:

图中看到 MP4 文件有几个主要组成部分:

fytp

File Type Box,一般在文件的开始位置,描述的文件的版本、兼容协议等。

moov

Movie Box,包含本文件中所有媒体数据的宏观描述信息以及每路媒体轨道的具体信息。一般位于 ftyp 之后,也有的视频放在文件末尾。注意,当改变 moov 位置时,内部一些值需要重新计算。

mdat

Media Data Box,存放具体的媒体数据。

Moov Insider

MP4 的媒体数据信息主要存放在 Moov Box 中,是我们需要分析的重点。moov 的主要组成部分如下:

mvhd

Movie Header Box,记录整个媒体文件的描述信息,如创建时间、修改时间、时间度量标尺、可播放时长等。

下图示例中,可以获取文件信息如时长为 3.637 秒。

udta

User Data Box,自定义数据。

track

Track Box,记录媒体流信息,文件中可以存在一个或多个 track,它们之间是相互独立的。每个 track 包含以下几个组成部分:

tkhd

Track Header Box,包含关于媒体流的头信息。

下图示例中,可以看到流信息如视频流宽度 720,长度 1280。

mdia

Media Box,这是一个包含 track 媒体数据信息的 container box。子 box 包括:

  • mdhd:Media Header Box,存放视频流创建时间,长度等信息。
  • hdlr:Handler Reference Box,媒体的播放过程信息。
  • minf:Media Information Box,解释 track 媒体数据的 handler-specific 信息。minf 同样是个 container box,其内部需要关注的内容是 stbl,这也是 moov 中最复杂的部分。

stbl 包含了媒体流每一个 sample 在文件中的 offset,pts,duration 等信息。想要播放一个 MP4 文件,必须根据 stbl 正确找到每个 sample 并送给解码器。

mdia 展开如下图所示:

Stbl Insider

Sample Table Box,上文提到 mdia 中最主要的部分是存放文件中每个 Sample 信息的 stbl。在解析 stbl 前,我们需要区分 Chunk 和 Sample 这两个概念。

在 MP4 文件中,Sample 是一个媒体流的基本单元,例如视频流的一个 Sample 代表实际的 nal 数据。Chunk 是数据存储的基本单位,它是一系列 Sample 数据的集合,一个 Chunk 中可以包含一个或多的 Sample。

stbl 用来描述每个 Sample 的信息,包含以下几个主要的子 box:

stsd

Sample Description Box,存放解码必须的描述信息。

下图示例中,对于 h264 的视频流,其具体类型为 avc1,extensions 中存放有 sps,pps 等解码必要信息。

stts

Time-to-Sample Box,定义每个 Sample 时长。Time To Sample 的 table entry 布局如下:

  • Sample count:sample 个数
  • Sample duration:sample 持续时间

持续时间相同的连续的 Sample 可以放到一个 entry 里面,以达到节省空间的目的。

下图示例中,第 1 个 Sample 时间为 33362 微秒,第 2-11 个 Sample 时间为 33363 微秒:

stss

Sync Sample Box,同步 Sample 表,存放关键帧列表,关键帧是为了支持随机访问。
stss 的 table entry 布局如下:

下图示例中,该视频 track 只有一个关键帧即第 1 帧:

stsc

Sample-To-Chunk Box,Sample-Chunk 映射表。上文提到 MP4 通常把 Sample 封装到 Chunk 中,一个 Chunk 可能会包含一个或者几个 Sample。Sample-To-Chunk Atom 的 table entry 布局如下图所示:

  • First chunk:使用该表项的第一个 chunk 序号。
  • Samples per chunk:使用该表项的 chunk 中包含有几个 sample。
  • Sample description ID:使用该表项的 chunk 参考的 stsd 表项序号。

下图示例中,可以看到该视频 track 一共有两个 stsc 表项,Chunk 序列 1-108,每个 Chunk 包含一个 sample,Chunk 序列 109 开始,每个 Chunk 包含两个 Sample。

stsz

Sample Size Box,指定了每个 Sample 的 size。Sample Size Atom 包含两 Sample 总数和一张包含了每个 Sample Size 的表。

Sample Size 表的 entry 布局如下图:

下图示例中,该视频流一共有 110 个 Sample,第 1 个 Sample 大小为 42072 字节,第 2 个 Sample 大小为 7354 个字节。

stco

Chunk Offset Box,指定了每个 Chunk 在文件中的位置,这个表是确定每个 Sample 在文件中位置的关键。该表包含了 Chunk 个数和一个包含每个 Chunk 在文件中偏移位置的表。每个表项的内存布局如下:

需要注意,这里 stco 只是指定的每个 Chunk 在文件中的偏移位置,并没有给出每个 Sample 在文件中的偏移。想要获得每个 Sample 的偏移位置,需要结合 Sample Size box 和 Sample-To-Chunk 计算后取得。

下图示例中,该视频流第 1 个 Chunk 在文件中的偏移为 4750,第 1 个 Chunk 在文件中的偏移为 47007。

如何计算 Sample 偏移位置

上文提到通过 stco 并不能直接获取某个 Sample 的偏移位置,下面举例说明如何获取某一个 pts 对应的 Sample 在文件中的位置。大体需要以下步骤:

  1. 将 pts 转换到媒体对应的时间坐标系。
  2. 根据 stts 计算某个 pts 对应的 Sample 序号。
  3. 根据 stsc 计算 Sample 序号存放在哪个 Chunk 中。
  4. 根据 stco 获取对应 Chunk 在文件中的偏移位置。
  5. 根据 stsz 获取 Sample 在 Chunk 内的偏移位置并加上第 4 步获取的偏移,计算出 Sample 在文件中的偏移。

例如,想要获取 3.64 秒视频 Sample 数据在文件中的位置:

  1. 根据 time scale 参数,将 3.64 秒转换为视频时间轴对应的 3640000。
  2. 遍历累加下表所示 stts 所有项目,计算得到 3640000 位于第 110 个 Sample。
type    stts
size    224
flags   0
version 0
sample_counts   1,10,1,1,11,1,1,2,1,25,1,1,1,17,1,10,1,1,1,7,1,1,1,1,10,1
sample_deltas   33362,33363,33362,33364,33363,33362,33364,33363,33362,33363,33362,33364,33362,33363,33362,33363,33362,33364,33362,33363,33362,33364,33363,33362,33363,0
  1. 查询下表所示 stsc 所有项目,计算得到第 110 个 Sample 位于第 109 个 Chunk,并且在该 Chunk 中位于第 2 个 Sample。
type    stsc
size    40
flags   0
version 0
first_chunk 1,109
samples_per_chunk   1,2
sample_description_index    1,1
  1. 查询下表所示 stco 所有项目,得到第 109 个 Chunk 在文件中偏移位置为 1710064。
Property name   Property value
type    stco
size    452
flags   0
version 0
chunk_offsets   4750,47007,54865,61967,75519,88424,105222,117892,133730,149529,165568,182034,194595,210776,225470,240756,255358,270711,285459,300135,315217,330899,347372,363196,376409,394509,407767,424615,438037,455603,469784,487287,505197,519638,536714,553893,567187,584744,599907,615298,630669,645918,662605,678655,693510,708980,724061,738946,754170,771520,787233,800847,816997,832490,847814,862559,877929,898379,911054,925810,943883,956497,974403,991527,1009478,1025198,1041806,1062609,1078401,1091360,1105142,1118748,1132815,1145281,1156966,1171871,1186742,1202760,1218235,1236688,1249330,1263163,1280880,1297903,1313162,1332885,1345726,1359017,1376283,1391401,1405512,1419550,1433644,1452103,1475241,1492689,1511291,1522606,1535368,1559413,1575331,1588853,1609829,1626623,1642798,1658640,1674160,1693972,1710064
  1. 查询下表所示 stsz 所有项目,得到第 109 个 Sample 的 size 为 14808。计算得到 3.64 秒视频 Sample 数据在文件中:

offset:1710064 + 14808 = 1724872
size:17930

type    stsz
size    460
flags   0
version 0
sample_sizes    42072,7354,6858,13110,12684,16416,12490,15497,15630,15865,16116,12387,15775,14519,14929,14433,15181,14390,14496,14717,15507,16101,15643,12843,17911,13070,16455,13221,17186,14002,17139,17737,14251,16708,16999,12911,17356,14801,15213,15016,15062,16505,15689,14657,15053,14907,14527,15048,17161,15308,13432,15777,15307,14971,14568,14987,20264,12494,14382,17873,12235,17718,16770,17766,15366,16420,20623,15403,12761,13394,13390,13714,12295,11505,14541,14689,15635,15291,18091,12458,13645,17346,16847,14902,19530,12446,13105,16872,14937,13944,13657,13908,18092,22959,17080,18421,11129,12400,23844,15564,13340,20603,16609,15984,15474,15339,19451,15719,14808,17930
sample_size 0
sample_count    110
  • 验证:用编辑器打开 MP4 文件,定位到文件偏移 offset = 1724872 的位置,前 4 字节值为 0x00004606。在 avcc 中一个 Sample 的前 4 个字节代表这个包的大小,转换为十进制是 17926,该值正好等于 size = 17930 减去表示长度的四个字节。

参考资料

在线 MP4 解析工具
QuickTime File Format Specification

「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

你真的懂 MP4 格式吗?相关推荐

  1. Pr软件导出mp4格式总是渲染错误,但avi格式等可以成功导出

    作为一个pr使用者,真的因为mp4格式的转出而苦恼不宜.本文使用的是2022版本的pr 如果H264格式导出时总是渲染失败,如下所示 首先,请观看b站解说晓强的"PR渲染失败.报错.弹窗.一 ...

  2. flv视频怎么转换成mp4格式?

    现在的短视频发展真的是越来越完善,很多人都靠刷视频来打发时间,小编也是这样的,没事刷一刷视频中的影视剧,那些带有讲解的视频,会让我快速看懂内容,比起自己去思考,感觉省了好多事,并且很有深度.这些讲解的 ...

  3. “三次握手,四次挥手”你真的懂吗?

    来源:码农桃花源 解读:"拼多多"被薅的问题出在哪儿?损失将如何买单? 之前有推过一篇不错的干货<TCP之三次握手四次挥手>,前几天有兄弟投稿,开始还以为是同一篇,后经 ...

  4. 【原创】“三次握手,四次挥手”你真的懂吗?

    记得刚毕业找工作面试的时候,经常会被问到:你知道"3次握手,4次挥手"吗?这时候我会"胸有成竹"地"背诵"前期准备好的"答案&qu ...

  5. 你真的懂TensorFlow吗?Tensor是神马?为什么还会Flow?

    本文的ipynb 格式见CSDN下载. 0维张量/标量 标量是一个数字 1维张量/向量 1维张量称为"向量". 2维张量 2维张量称为矩阵 3维张量 公用数据存储在张量 时间序列数 ...

  6. 关于Spring底层原理面试的那些问题,你是不是真的懂Spring?

    转载自  关于Spring底层原理面试的那些问题,你是不是真的懂Spring? 1.什么是 Spring 框架?Spring 框架有哪些主要模块? Spring 框架是一个为 Java 应用程序的开发 ...

  7. 你真的懂Redis的5种基本数据结构吗?

    摘要: 你真的懂Redis的5种基本数据结构吗?这些知识点或许你还需要看看. 本文分享自华为云社区<你真的懂Redis的5种基本数据结构吗?这些知识点或许你还需要看看>,作者:李子捌. 一 ...

  8. dicom格式怎么转换_qsv怎么转换mp4格式?qsv转mp4的首选工具

    原标题:qsv怎么转换mp4格式?qsv转mp4的首选工具 以前,电脑里安装有各大平台的PC端软件,还就真的没有注意到兼容不兼容的问题,直到这一次,从爱奇艺平台下载了视频放到手机里,这才发现,原来没有 ...

  9. 迅速处理多个ts转mp4格式 - 无需安装

    2020 最完善最快方法和教程把ts转去mp4 FFmpeg + Medlexo = 无敌搭配 开始教程 FFmpeg + Medlexo = 无敌搭配 要ts转mp4原因像比如下载下来后缀为ts的视 ...

最新文章

  1. android handler作用,Android中Handler的作用
  2. 如何通过深度学习,完成计算机视觉中的所有工作?
  3. 关于grep的引号使用问题
  4. MySQL—增删改查,分组,连表,limit,union,alter,排序,去重
  5. Android照片墙完整版,完美结合 内存方案 LruCache 和 硬盘方案 DiskLruCache
  6. 鸽主姓名查询成绩_鸽主姓名
  7. 鸿蒙轻内核定时器Swtmr:不受硬件和数量限制,满足用户需求
  8. POJ 3694Network(Tarjan边双联通分量 + 缩点 + LCA并查集维护)
  9. 领英:经济图谱在中国,为人才就业勾画新版图
  10. 51nod 1067 Bash游戏 V2 博弈
  11. linux系统时间与网络时间不同步
  12. 微信公众号平台服务器配置请求url超时,绑定微信公众平台提示请求URL超时怎么办...
  13. 使用visDrone数据集训练yolov5检测器
  14. 摩尔纹的原理与产生条件
  15. iOS 获取当前的UIViewController
  16. 日常 --- watch的使用
  17. dlopen和dlsym
  18. 10个预训练模型开始你的深度学习(计算机视觉部分)
  19. saiku的安装教程
  20. SVN(服务端)使用教程

热门文章

  1. 初学古琴怎么学?古琴入门基础知识
  2. wireshark使用及过滤器介绍
  3. 【xgboost】xgboost模型的保存与加载
  4. 尚硅谷mycat2.0安装和配置
  5. C/C++ CGI处理文件上传
  6. 关于“‘c‘ argument has 1 elements, which is not acceptable for use with ‘x‘ with size 300“的解决办法
  7. 互联网公司招聘--奇虎360--技术类--2014年笔试题
  8. 自己做项目时整理的上传Excel表格
  9. java中关于死锁的概念和实例操作
  10. MacOS swift 首页导航栏 不显示标题问题