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. [C#] C# 知识回顾 - 你真的懂异常(Exception)吗?

    你真的懂异常(Exception)吗? 目录 异常介绍 异常的特点 怎样使用异常 处理异常的 try-catch-finally 捕获异常的 Catch 块 释放资源的 Finally 块 一.异常介 ...

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

    “三次握手,四次挥手”你真的懂吗?  mp.weixin.qq.com 来源:码农桃花源 解读:“拼多多”被薅的问题出在哪儿?损失将如何买单? 之前有推过一篇不错的干货<TCP之三次握手四次挥手 ...

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

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

  4. 嵌入式 H264—MP4格式及在MP4文件中提取H264的SPS、PPS及码流

    一.MP4格式基本概念 MP4格式对应标准MPEG-4标准(ISO/IEC14496) 二.MP4封装格式核心概念 1  MP4封装格式对应标准为 ISO/IEC 14496-12(信息技术 视听对象 ...

  5. 动态获取爱奇艺上传视频mp4格式url地址

    有时候,在工作中有些客户需要用到视频,我们大家都知道视频是非常的耗费流量的,因此,如果因为项目要求客户单独买台视频服务器是非常划不来的.那么将视频上传到优酷,爱奇艺等视频网站来托管那是一件很好的解决方 ...

  6. 【转】was mutated while being enumerated 你是不是以为你真的懂For...in... ??

    原文网址:http://www.jianshu.com/p/ad80d9443a92 支持原创,如需转载, 请注明出处你是不是以为你真的懂For...in... ??哈哈哈哈, 我也碰到了这个报错 . ...

  7. Video标签播放视频?谷歌浏览器?safari?? 谷歌浏览器播放不了mp4格式的视频的原因

    webm格式和mp4格式,判断了浏览器能否支持的视频类型后,给了一个if判断,如果是支持mp4格式,就返回视频后缀mp4,如果是webm,就返回后缀webm.结果,在谷歌浏览器中播放不了,为什么我指定 ...

  8. javascript的语法作用域你真的懂了吗

    原文:javascript的语法作用域你真的懂了吗 有段时间没有更新了,思绪一下子有点转不过来.正应了一句古话“一天不读书,无人看得出:一周不读书,开始会爆粗:一月不读书,智商输给猪.”.再加上周五晚 ...

  9. 你真的懂ajax吗?

    前言 总括: 本文讲解了ajax的历史,工作原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便日常开始使用. damonare的ajax库: ...

随机推荐

  1. 搭建tdh平台

    1.卸载tdh平台(见tdh集群卸载文件夹) 在manager节点执行chmod +x uninstall.sh (非root用户执行sudo chmod +x uninstall.sh)开始卸载TD ...

  2. Educational Codeforces Round 30

    Educational Codeforces Round 30  A. Chores 把最大的换掉 view code #pragma GCC optimize("O3") #pr ...

  3. Color Changing Sofa Gym - 101962B、Renan and Cirque du Soleil Gym - 101962C、Hat-Xor Gym - 101962E 、Rei do Cangaço Gym - 101962K 、Sorting Machine Gym - 101962M

    Color Changing Sofa Gym - 101962B 题意:给你一个由字母构成的字符串a,再给你一个由0.1构成的字符串b.你需要在a字符串中找到一个可以放下b的位置,要保证b字符串中0 ...

  4. Codeforces Round #691 (Div. 2) C. Row GCD (数学)

    题意:给你两个数组\(a\)和\(b\),对于\(j=1,...,m\),找出\(a_1+b_j,...,a_n+b_j\)的\(gcd\). 题解:我们很容易的得出\(gcd\)的一个性质:\(gc ...

  5. AtCoder Beginner Contest 182 D - Wandering (前缀和)

    题意:在\(x\)轴上,你刚开始在\(0\)的位置,第\(i\)次操作需要走\(A_1,...,A_i\)个单位,如果\(A_i\)为正向右走,否则向左走,求你所能走到的最大坐标. 题解:我们一步一步 ...

  6. 使用eclipse搭建第一个java web应用

    一. 首先是eclipse得下载,你要下载Eclipse IDE for Java EE这种类型的,我之前下载的Eclipse IDE for Enterprise Java Developers是官 ...

  7. C#Assembly、程序集、装配件、命名空间以及类型的关系

    Assembly = 程序集 = 装配件 命名空间是类的逻辑组织形式,程序集是类的物理组织形式. 程序集其实和命名空间没有什么必然的联系. 程序集1: namespace1{ public class ...

  8. 03、xpath及css的用法

    1.xpath语法 2.css语法

  9. Bing壁纸-20200416

  10. Kubernets二进制安装(9)之部署主控节点控制器controller-manager

    kube-controller-manager运行控制器,它们是处理集群中常规任务的后台线程 Controller Manager就是集群内部的管理控制中心,由负责不同资源的多个Controller构 ...