基本介绍

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

预览

mp4文件由 box 组成,每个 box 分为 Header 和 Data。其中 Header 部分包含了 box 的类型和大小,Data 包含了子 box 或者数据,box 可以嵌套 box。
下图是一个典型 mp4文件的基本结构:

image.png

mp4文件的基本组成单元是 box,也就是说 mp4文件是由各种 box 组成,有 parent box,还有 childrenbox。因此,这些 boxes 之间存在一定的层次关系,总结如下表所示,标中标记出了各个 box 必选或可选特征。

ftyp file type and compatibility
文件类型和兼容性
pdin progressive download information
moov container for all the metadata
所有元数据的容器
mvhd movie header, overall declarations
电影头,整体声明
trak container for an individual track or stream
单个音轨流的容器
tkhd track header, overall infomation about the tracker
轨的头部,关于该轨的概括信息,比如视频宽高
tref track reference container
edts edit list container
elst an edit list
mdia container for the media information in a track
轨媒体信息的容器
mdhd media header, overall infomation about the media
媒体头,关于媒体的总体信息
hdlr handler, declares the media
媒体的播放过程信息
minf media information container
媒体信息容器
vmhd video media header, overall information
(video track only)
smhd sound media header, overall information
(sound track only)
hmhd hint media header, overall infomation
(hint track only)
nmhd Null media header, overall information
(some tracks only)
dinf data information box, container
数据信息 box, 容器
dref data reference box, declares source (s) of media data in track
如何定位媒体信息
stbl sample table box, container for the time/space map
包含了 track 中的 sample 的所有时间和位置信息,一级 sample 的编解码等信息。利用这个表可以解析 sample 的时序、类型、大小及在各自存储容器中的位置。
stsd sample descriptions (codec types, initialization etc)
如果是视频,包含:编码类型、宽高、长度等信息;
如果是音频,包含:声道、采样率等信息;
stts (decoding)time-to-sample
描述了 sample 时序的映射方法,我们可以通过它找到任何时间的 sample
ctts (composition)time to sample
stsc sample-to-chunk, partial data-offset information
用 chunk 组织 sample 可以方便优化数据获取,一个 chunk 包含一个或多个 sample。
stsz sample sizes (framing)
每个 sample 的大小。虽然这里没有打勾,但是对于mp4很重要
stz2 compact sample sizes (framing)
stco chunk offset, partial data-offset information
定义每个 chunk 在媒体流中的偏移位置
co64 64bit chunk offset
stss shadow sync sample table
stsh sample padding bits
padb sample degtadation priority
stdp sample degradation priority
sdtp independent and disposable samples
sbgp sample-to-group
sgpd sample group description
subs sub-sample information
mvex movie extends box
mehd movie extends header box
trex track extends defaults
ipmc IPMP Control Box
moof movie fragment
mfhd movie fragment header
traf track fragment
tfhd track fragment header
trun track fragment run
sdtp independent and disposable samples
sbgp sample-to-group
subs sub-sample information
mfra movie fragment random access
tfra track fragment random access
mfro movie fragment random access offset
mdat media data container
free free space
skip free space
udta user-data
cprt copyright etc
meta metadata
hdlr handler, declares the metadata (handler) type
dinf data information box, container
dref data reference box, declares source (s) of metadata items
ipmc IPMP Control Box
iloc item location
ipro item protection
sinf protection scheme information box
frma original format box
imif IPMP Information box
schm scheme type box
schi scheme information box
iinf item information
xml XML container
bxml binary XML container
pitm primary item reference
fiin file delivery item information
paen partition entry
fpar file partition
fecr FEC reservoir
segr file delivery session group
gitn group id to name
tsel track selection
meco additional metadata container
mere metabox relation

具体分析

fype

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

image.png

moov

Movie Box 包含了本为难中所有媒体数据的宏观描述信息以及每路媒体轨道的具体信息。一般位于放在文件末尾,但如果为了支持 http 边下载边播放则需要将 moov 提前。注意:当改变 moov 位置时,内部一些值需要重新计算。

image.png

moov 里面的 box 才是需要主要分析的 box

image.png

mdat

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

image.png

Moov Insider

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

mvhd

Movie Header Box 记录整个媒体文件的描述信息,如创建时间,修改时间,时间度量标尺、可播放时长等。
在下面这个例子中,可以获取文件信息如时长 Duration:5016ms。

image.png

udta

User Data Box,自定义数据。

track

Track Box 记录媒流信息,文件中可以存在一个或多个 track,他们之间时互相独立的。

tkhd

Track Header Box 包含关于媒体流的头信息。
在下面的示例中,可以看到流信息如视频流宽度720,长度1280.

image.png
image.png

音频的 tkhd 比如 duration、volume 等。

image.png
image.png

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 并送给解码器。

image.png
image.png

image.png

mdhd

Media Header Box 存放视频流创建时间,长度等信息。
视频的 mdhd,Time scale,Duration 等信息。

image.png

音频的 mdhd 和视频类似,但是要注意 Time scale,我们在计算时间戳的时候都要使用该 Time scale,对应我们流里面的 AVStream->time_base。

image.png

hdlr

Handler Reference Box 媒体的播放过程信息。
视频的 hdlr,重点 Component subtype:

image.png

音频的 hdlr,Component subtype:soun,如果我们多个音轨的时候,Component name:粤语。

image.png

我们分析文件另一路音轨。

image.png

minf

Media Information Box,解释 track 媒体数据的 handler- specific 信息。minf 同样是一个 container box,其内部需要关注的内容是 stbl,这也是 moov 中最复杂的部分。stbl 包含了媒体流每一个 sample 在文件中的 offset,pts,duration 等信息。想要播放一个 mp4文件,必须根据 stbl 正确找到每个 sample 并送给解码器。
而且需要注意的是,minf 里面的子容器,音频和视频轨是有区别的,比如视频轨:vmhd,音频轨 smhd。

vmhd:
image.png

smhd:
image.png

Stbl Insider

Sample Table Box,上文提到 media 中最主要的部分是存放文件中每个 sample 信息的 stbl。在解析 stbl 钱,我们需要区分 chunk 和 sample 这两个概念。
在 mp4文件中,sample 时一个媒体流的基本单元,例如视频流的一个 sample 代表实际的 nal 数据。chunk 时数据存储的基本单位,他是一系列 sample 数据的集合,一个 chunk 中可以包含一个或多个 sample。

image.png

一个 chunk 包含一个或多个 sample

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

stsd

Sample Description Box,存放解码必须的描述信息。
下面的示例中,对于 h264的视频流,其具体类型为 avcl,extensions 中其中存放有 sps,pps 等解码必要的信息。

视频的 stsd

image.png

里面包含了 avc1,avc1里包含了 avcC 和 pasp。

image.png

  • avc1:包含了视频 Width、Height;
  • avcC:包含了视频编码器相关的信息,包括 sps、pps 等信息。

image.png

image.png

image.png

image.png

image.png

音频的 stsd

包含了音频相关信息,比如采样率,通道数量等。

image.png

stts

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

image.png

stts table entry 布局

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

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

这里先给出来的是视频的 stts,Number of entries,这个参数需要注意的并不是 sample 的个数,sample 的实际数量需要将每个 entry 的 sample count 进行累加才是真正的 sample 个数。
下面的示例中,第一个 sample 时间为3720,单位用 mdhd 的 time scale 进行换算,比如视频的是90000,此时换算成秒为3720➗90000=0x0133333333秒。

image.png
image.png

再给出个音频 stts,只是 mdhd 的 time scale 的差别,之前我们看到音频为44100,则计算第一个 sample 的时间1024/44100=0.0232199546485261秒。

image.png

stss

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

image.png

下图示例中,该视频 track 有3个关键帧:

image.png

image.png

stsc

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

image.png

  • First chunk 使用该表项的第一个 chunk 序号
  • Samples per chunk 使用该表项的 chunk 中包含有几个 sample
  • Sample description ID 使用该表项的 chunk 参考的 stsd 表项序号
    下图示例中,可以看到该视频 track 一共有1个 stsc 表项,chunk 序列1-x,每个 chunk 包含一个 sample。
    这里则说明每个chunk里面只有一个sample(一个chunk时可以有多个sample)

image.png

stsz

Sample Size Box,指定了每个 sample 的 size。Sample Size Atom 包含两个 sample 总数和一张包含了每个 sample size 表。
sample size 表的 entry 布局如下图:

image.png

下面的示例中,该视频一共有110个 sample,第一个 sample 大小为42072字节,第二个 sample 大小为7354个字节。

image.png
image.png

image.png

stco

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

image.png

需要注意,这里 stco 只是制定的每个 chunk 在文件中的便宜位置,并没有给出每个 sample 在文件中的偏移。想要获得每个 sample 的偏移位置,需要结合 Sample Size Box(stsz) 和 Sample-To-Chunk(stsc)计算后取得。
下面的示例中,该视频流第一个 chunk 在文件中的偏移为4750,而这里是每个 chunk 只有一个 sample,此时第一个 sample 的起始位置就是4750,数据大小则参照 stsz->0x1D78,第一个 sample size 为172818。

image.png

如何计算 sample 偏移位置

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

  • 将 pts 转换到媒体对应的时间坐标系
  • 根据 stts(decoding time-to-sample) 计算某个 pts 对应的 sample 序号
  • 根据 stsc(sample-to-chunk)计算 sample 序号存在哪个 chunk 中
  • 根据 stco(chunk offset)获取对应 chunk 在文件中的偏移位置
  • 根据 stsz 获取 sample 在 chunk 内的偏移位置并加上第四步获取的偏移,计算出 sample 在文件中的偏移

image.png
image.png
image.png
image.png