2.MP4(MPEG-4 Part 14)
MPEG-4 Part 14
或
MP4
是一种数字多媒体容器格式,最常用于存储视频和音频,但它也可用于存储其他数据,例如字幕和静止图像。与大多数现代容器格式一样,它允许通过 Internet
进行流式传输。规范定义的 MPEG-4 Part 14
文件的唯一文件扩展名是
.mp4
。
MPEG-4 Part 14
(正式名称为
ISO/IEC 14496-14:
2003
)是指定为
MPEG-4
一部分的标准。
MP4
文件本质上是一个容器,它可以包含多种媒体元素,通常包括:
- 视频流:通常采用 H.264 或 H.265(HEVC)等压缩标准。
- 音频流:常见的编码格式包括 AAC 和 MP3。
- 字幕:MP4 文件可以存储字幕信息,常见的格式包括 SRT 和 ASS。
- 图像:MP4 文件可以包含静态图像,如封面图或视频截图。
- 元数据:包括视频的标题、创作者、时长、版权信息等
2.1 MP4文件结构
MP4
是一个可扩展的容器文件,这意味着它没有定义严格的结构,并允许为每种媒体类型自定义结构和层次结构。MP4
文件中的数据分为两个部分,第一个部分包含与媒体相关的数据,第二个部分包含元数据。MP4
中的结构通常称为原子
(atoms)
或者盒子
(box)
。原子的最小大小为
8
字节(前
4
个字节指定大小,接下来的 4
个字节指定类型)
以下是
MP4
文件中包含的根级原子的列表:
- ftyp:包含文件类型、描述和常用数据结构。
- pdin:包含渐进式视频加载/下载信息。
- moov:所有电影元数据的容器。
- moof:包含视频片段的容器。
- mfra:可随机访问视频片段的容器
- mdat:媒体的数据容器。
- stts:样本到时间表。
- stsc:sample-to-chunk 表。
- STSZ:样本量(框架)
- meta:包含元数据信息的容器。
以下是
MP4
中使用的二级原子列表:
- mvhd:包含视频头信息以及视频的完整详细信息。
- trak:包含单个轨道的容器。
- udta:包含用户和轨迹信息的容器。
- iods:MP4 文件描述符
也就是是
MP4
文件由若干个
Box
组成,对于一个
Box
是有一个
Header
和
Box
组成如下所示:
对于
Box Header
:
- size(大小):包含Header的整个Box所占用的大小。
- type(类型):通常是4个ASCII码的字符如“ftyp”、“moov”等,这些box type都是已经预定义好的,表示固定的含义。如果是“uuid”,表示该box为用户自定义扩展类型,如果box type是未定义的,应该将其忽略。
- largesize(更大的长度描述):如果header中的size为1,则表示box长度需要更多的bits位来描述,在后面会有一个64bits位的largesize用来描述box的长度。如果size为0,表示该box为文件的最后一个box,文件结尾(同样只存在于“mdat”类型的box中)。
- version(版本):是一个整数,用于指定此Box的版本。
- flags(标志位):是一个带有 flags 的 24 位整数(当前全部为零)。
2.2 Box类型
2.2.1 File Type Box(ftyp)
ftyp
盒子的结构通常包含以下几个字段:
1.
Box Type (4 bytes)
ftyp
盒子的类型标识符,固定值为
"ftyp"
,用于标识该盒子。
2.
Major Brand (4 bytes)
这是文件的主品牌,表示该文件的标准或文件格式的主要版本。它指示该文件符合某种特定的规范
或兼容性要求。例如,如果
ftyp
盒子的
major brand
字段为
"isom"
或
"mp41"
,那么该文件被
认为是符合
ISO
标准的
MP4
文件。
3.
Minor Version (4 bytes)
这是一个次版本号,表示文件的次版本。通常,次版本号为
0
。这个字段主要用于标识文件格式的
次要变更。如果没有版本变化,这个字段的值通常为
0
。
4.
Compatible Brands (variable length)
该字段是一个可选部分,它列出了一些兼容的品牌。兼容品牌是文件可以兼容的其他文件格式或文
件版本标识符(通常是
4
个字节)。播放器或工具可以通过检查这些兼容品牌,来判断该文件是否
能够被它们正确解析和播放。这个字段包含的品牌列表是可变长度的,可以包含多个品牌标识符。
2.2.2 Movie Box(moov)
包含了整个视频文件的元数据,包括视频和音频的编码信息、时间信息、以及其他与媒体播放相关的详细信息。简单来说, moov
盒子存储着所有必要的内容描述,使播放器能够正确地解码和播放视频文件。
moov
是
MP4
文件中的
Movie Atom
(电影原子),它位于
MP4
文件的结构中,通常位于文件的
中间部分。这个盒子是 MP4
文件的核心组成部分,提供了文件的播放信息和媒体流的详细说明。
1.
mvhd (Movie Header Box)
包含了整个电影文件的全局信息。这些信息对于播放器在播放过程中进行时间同步和解析非常重要。mvhd 包含以下内容:
- version : box版本,0或1,一般为0。
- creation time : 创建时间(相对于UTC时间1904-01-01零点的秒数)。
- modification time : 修改时间 。
- timescale: 定义时间的单位(时间基准)。例如,视频时间可能是以每秒 1000 帧为基准的。比如 audio track的time scale = 8000, duration = 560128,时长为70.016,video track的time scale =600, duration = 42000,时长为70。
- duration: 电影的总时长,通常以 timescale 为单位表示。
- rate: 播放速率,通常为 1,表示正常播放速度。高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,该值为1.0(0x00010000)表示正常前向播放。
- volume: 音量控制,通常为 1,表示正常音量。[8.8] 格式,1.0(0x0100)表示最大音量。
- matrix: 一个用于定义视频和音频轨道变换矩阵的字段,通常用来处理屏幕显示或旋转等效果。
- next_track_id: 下一轨道的 ID,帮助系统分配新的轨道 ID。
2.
trak (Track Box)
trak
盒子,代表每个独立的媒体轨道(例如,一个视频轨道或一个音频轨道)。每个
trak
盒子描述了一个轨道的具体信息,包括轨道的头信息、时间戳、数据流以及样本表等。一个 MP4
文件可能包含多个 trak
盒子,分别代表不同的媒体流。
在每个
trak
盒子内部,通常会有以下子盒子:
- tkhd (Track Header Box): 描述轨道的基本信息,如轨道 ID、轨道的时长、轨道的显示尺寸等。
- mdia (Media Box) : 用于包含媒体数据的详细信息
3.
udta (User Data Box)
udta
盒子用于存储与用户数据相关的信息,它通常包含一些元数据,如标题、版权、创作者信息、封面图像等。该部分不是播放所必需的,但常见于包含元信息和附加数据的媒体文件中。
2.2.3 Media Box(mdia)
mdia
盒子本身并不包含媒体数据(即音频或视频数据),而是包含了一些描述性的信息,帮助播放器或解码器理解如何正确处理和播放这个轨道的数据。每个 mdia
盒子代表了一个特定的媒体轨道(如视频、音频或字幕轨道)的描述,它为该轨道提供了所有必要的元数据,以便正确地播放该媒体流。通常,一个 trak
盒子包含一个
mdia
盒子,每个
mdia
盒子则包含有关该轨道的时间、解码信息、样本信息等多个详细部分。一个“mdia”
必须包含如下容器:
- 一个Media Header Atom(mdhd)
- 一个Handler Reference(hdlr)
- 一个media information(minf)和User Data
2.2.4 Media Header Box (mdhd)
mdhd
盒子存储了与媒体轨道的时间相关的元数据。主要字段包括:
- timescale: 时间基准,即每个时间单位表示多少个时间戳。比如,视频可能以每秒 1000 个时间戳为基准,而音频则可能以每秒 44100 个时间戳为基准。
- duration: 媒体轨道的总持续时间,通常以 timescale 为单位表示。通过这个字段可以知道媒体轨道的时长。与track的时间长度一致。
- language: 媒体轨道的语言(例如,音频轨道可能是英语或法语)。
该盒子帮助播放器计算出媒体的播放时间和播放速率,确保在播放过程中实现正确的时间同步。
2.2.5 Handler Reference Box(hdlr)
- hdlr 盒子标识了该轨道的类型(如视频、音频、字幕等)。主要字段:
handler_type : 该字段标识该轨道的类型,常见的值有:
vide :视频轨道
soun :音频轨道
text :字幕轨道
hint :用于提示信息流(例如流媒体)。
- name: 可以包含一个名称字符串,通常用于表示该轨道的描述性信息。
通过
hdlr
盒子,播放器能够识别该轨道的内容类型,并选择合适的方式来处理或解码它。
2.2.6 Media Information Box(minf)
minf
盒子包含了与媒体轨道实际数据流的处理和解码有关的详细信息。它进一步包含多个子盒子,其中最重要的是 stbl
。
minf
盒子包含:
- vmhd (Video Media Header Box): 如果是视频轨道, vmhd 描述视频流的特性(如视频模式、宽高比、色彩空间等)。
- smhd (Sound Media Header Box): 如果是音频轨道, smhd 描述音频流的特性(如音频格式、通道数、采样率等)。
- stbl (Sample Table Box): 该盒子存储了所有关于样本的数据
2.2.7 Sound Media Header Box(smhd)
在
MP4
文件格式中,
smhd box
(
Sound Media Header Box
)是一个用于描述音频轨道的
box
。它包含了与音频相关的特定信息。
smhd box
是一个
Full Box
,这意味着它包含了
version
和
flags
字段。其结构如下:
- version:1字节,表示box的版本号,通常为0。
- flags:3字节,表示一些标志位,通常为0。
- balance:2字节,表示立体声平衡,采用[8.8]格式的定点数值。0表示左右声道平衡,负值表示左声道更强,正值表示右声道更强。
- reserved:2字节,保留字段,通常为0。
smhd box
的作用是提供音频轨道的基本信息,特别是立体声平衡信息。它通常包含在
Media
Information Box
(
minf
)中,
minf
是
Media Box
(
mdia
)的子
box。
2.2.8 Data Information Box(dinf)
在
MP4
文件格式中,
Data Information Box
(
dinf
)
是一个用于描述如何定位媒体数据的
box
。它是Media Information Box(
minf
)的子
box
,
minf
又是
Media Box
(
mdia
)的子
box
。
dinf box
的主要作用是提供媒体数据的位置引用信息。
dinf box
本身是一个
container box
,通常包含一个或多个
Data Reference Box
(
dref
)。
dref box
中包含了若干个URL
或
URN box
,这些
box
组成一个表,用于定位
track
数据。以下是
dinf box
的详细结构:
- dref box:Data Reference Box,包含了数据引用信息
- URL box:指向一个外部数据源的URL
- URN box:指向一个外部数据源的URN
2.2.9 Sample Table Box(stbl)
Sample Table Box
包含了定位和解码
sample
(样本)所需的所有信息。
stbl box
是
Media Information Box(
minf
)的子
box
,
minf
又是
Media Box
(
mdia
)的子
box
。
stbl box
本身是一个
container box
,包含多个子box
,每个子
box
都有特定的功能。主要的子
box
包括:
1.
Sample Description Box
(
stsd
)
:描述
sample
的格式和编码信息。
2.
Time to Sample Box
(
stts
)
:记录
sample
的时间戳信息。
3.
Sync Sample Box
(
stss
)
:标识关键帧(
I
帧)。
4.
Sample to Chunk Box
(
stsc
)
:定义
sample
和
chunk
之间的映射关系。
5.
Sample Size Box
(
stsz
或
stz2
)
:记录每个
sample
的大小。
6.
Chunk Offset Box
(
stco
或
co64
)
:记录每个
chunk
在文件中的偏移位置。
根据
Sample Table Box
包含的所有
sample
的时间
/
位置
/
编解码等信息,解析
sample
的时序、类型、大小以及各自存储容器的位置。
2.2.10 Sample Description Box(stsd)
Sample Description Box
用于描述每个
track
的
sample
(样本)类型和初始化解码器所需的信息。它是Sample Table Box(
stbl
)的子
box
。
stsd box
是一个
Full Box
,包含以下字段:
- version:1字节,表示box的版本号,通常为0。
- flags:3字节,表示一些标志位,通常为0。
- entry_count:4字节,表示sample描述条目的数量。
- sample_entries:包含若干个sample描述条目,每个条目描述一种sample类型,类型信息如 “vide”、“soud”等。
- format:视频或者音频的编码格式。
- samplerate(4字节):采样率。[16.16]格式的数据。
-
data_reference_index ( 2 字节):利用这个索引可以检索与当前 sample description 关联的数据。数据引用存储在data reference box 。
-
samplesize ( 2 字节):采样位数。默认是 16 比特。
-
channelcount ( 2 字节):通道个数
- width、height:像素宽高。
- horizresolution、vertresolution:每英寸的像素值(dpi),[16.16]格式的数据。通常为 0x00480000(72 dpi)。
- frame_count:每个sample中的视频帧数,默认是1。可以是一个sample中有多帧数据。
- compressorname:编码器名称。
- depth:2字节,图像深度,通常为0x0018(24位)。
2.2.11 Decoding Time to Sample Box(stts)
Decoding Time to Sample Box
用于记录每个
sample
的解码时间(
DTS
)。它是
Sample Table Box
(
stbl
)的子
box
。
stts box
通过一个时间戳映射表,定义了
sample
的解码时间,从而帮助播放器正确地解码和播放媒体数据。stts box
是一个
Full Box
,包含以下字段:
- version:1字节,表示box的版本号,通常为0。
- flags:3字节,表示一些标志位,通常为0。
- entry_count:4字节,表示时间戳映射表中的条目数量
- sample_entries:包含若干个时间戳映射条目,每个条目包含两个字段:
sample_count:
4
字节,表示具有相同时间间隔的连续
sample的数量,即
连续相同的
offset
的个数
sample_delta:
4
字节,表示每个
sample
的时间间隔(以时间单位表示),
CT
和
DT
之间的
offset
stts box
的主要作用是提供
sample
的解码时间信息。播放器通过解析
stts box
,可以计算出每个
sample 的解码时间(DTS
),从而正确地播放媒体数据。
stts box
定义了一个时间戳映射表,通过
sample_count
和
sample_delta
字段,描述了
sample
的时间间隔。
DT(decoding time)
:编码时间。
CT(composition time)
:创作时间。
Decode Delta
:编码时间增量。
Composition offset
:显示时间同解码时间的差值,等于
CT - DT
。
2.2.12 sync sample box(stss)
sync sample box(stss)
用于标识文件中的关键帧(
I
帧)。关键帧是可以独立解码的帧,对于视频的快速跳转和播放非常重要。stss box
是
Sample Table Box
(
stbl
)的子
box
。
stss box
是一个
Full Box
,包含以下字段:
- version:1字节,表示box的版本号,通常为0。
- flags:3字节,表示一些标志位,通常为0。
- entry_count:4字节,表示关键帧的数量。
- sample_number:每个关键帧的sample序号,entry_count个。
stss box
的主要作用是提供关键帧的位置信息。播放器在进行快进或快退操作时,会跳转到最近的关键帧,以确保视频能够正确解码和播放。具体来说,stss box
列出了所有关键帧的
sample
序号,帮助播放器快速定位到这些帧。
2.2.13 composition time to sample box(ctts)
Composition Time to Sample Box
用于记录每个
sample
的显示时间(
PTS
)和解码时间(
DTS
)之间的差值。它是Sample Table Box
(
stbl
)的子
box
。
ctts box
通过提供
composition offset
(显示时间偏移),帮助播放器正确地显示视频帧,特别是在处理包含B
帧的视频时。
ctts box
是一个
Full Box
,包含以下字段:
- version:1字节,表示box的版本号,通常为0。
- flags:3字节,表示一些标志位,通常为0。
- entry_count:4字节,表示时间戳映射表中的条目数量
- sample_entries:包含若干个时间戳映射条目,每个条目包含两个字段:
sample_count:
4
字节,表示具有相同时间间隔的连续
sample的数量,即
连续相同的
offset
的个数
sample_delta:
4
字节,表示每个
sample
的时间间隔(以时间单位表示),
CT
和
DT
之间的
offset
ctts box
的主要作用是提供
sample
的显示时间(
PTS
)信息。播放器通过解析
ctts box
,可以计算出每个 sample的显示时间(
PTS
),从而正确地播放媒体数据。
ctts box
定义了一个时间偏移表,通过 sample_count和
sample_offset
字段,描述了
sample
的显示时间偏移。
2.2.14 Sample To Chunk Box(stsc)
Sample To Chunk Box
(
stsc
)用于描述
sample
(样本)和
chunk
(块)之间的映射关系。它是
Sample Table Box(
stbl
)的子
box
。
stsc box
通过定义
sample
如何分配到
chunk
中,帮助播放器正确地读取和解码媒体数据。stsc box
是一个
Full Box
,包含以下字段
- version:1字节,表示box的版本号,通常为0。
- flags:3字节,表示一些标志位,通常为0。
- entry_count:4字节,表示时间戳映射表中的条目数量
- sample_entries:包含若干个时间戳映射条目,每个条目包含两个字段:
first_chunk:4字节,表示第一个chunk的索引。
samples_per_chunk:4字节,表示每个chunk包含的sample数量。
sample_description_index:4字节,表示sample描述的索引,指向Sample Description
Box(
stsd
)中的描述条目。
stsc box
的主要作用是提供
sample
和
chunk
之间的映射关系。播放器通过解析
stsc box
,可以确定每个chunk包含的
sample
数量,从而正确地读取和解码媒体数据。
stsc box
定义了一个映射表,通过first_chunk、
samples_per_chunk
和
sample_description_index
字段,描述了
sample
如何分配到
chunk中。
第一组
chunk
的
first_chunk
序号为
1
,每个
chunk
的
sample
个数为
2
第二组
chunk
的
first_chunk
序号为
3
,每个
chunk
的
sample
个数为
1
2.2.15 Sample Size Box(stsz)
Sample Size Box
(
stsz
)用于存储每个样本的字节大小信息。这对于解码器来说非常重要,因为它需要知道每个样本的大小才能正确地读取和处理媒体数据。
stsz box
包含如下字段:
- ample_size:一个32位的无符号整数。如果所有样本的大小相同,这个字段会记录样本的大小; 如果样本大小不同,这个字段为0。
- sample_count:一个32位的无符号整数,表示样本的总数。
- entry_size:一个32位的无符号整数数组,只有当sample_size为0时存在,记录每个样本的大小。
解析
stsz box
时,首先检查
sample_size
字段。如果
sample_size
不为
0
,则所有样本的大小都相同,直接使用这个值即可。如果sample_size
为
0
,则需要读取
entry_size
数组中的每个值来获取每个样本的大小。
2.2.16 Chunk Offset Box(stco)
Chunk Offset Box
(
stco
)用于存储每个
chunk
的字节偏移量。解码器通过这些偏移量来定位和读取存储在文件中的媒体数据。stco box
包含如下字段:
- version:一个8位的无符号整数,表示box的版本。flags:24位的标志位,通常为0。
- entry_count:一个32位的无符号整数,表示chunk的数量。
- chunk_offset:一个32位的无符号整数数组,记录每个chunk的偏移量
解析
stco box
时,首先读取
version
和
flags
字段。然后读取
entry_count
字段,确定
chunk
的数量。最
后,根据
entry_count
读取
chunk_offset
数组中的每个偏移量。
2.2.17 mdat Box (Media Data Box)
mdat Box
包含了媒体文件的主要数据部分。与其他盒子不同,
mdat
盒子不包含任何元数据或描述信息,而是直接存储媒体数据本身。这些数据通常是视频帧、音频样本等。
音视频数据的编解码信息都在其它
box
中保存,解析的时候先读取其它
box
的信息获取编解码信息以及音视频数据在mdat
中的位置,然后再读取
mdat
获取音视频数据。
mdat
盒子的结构相对简单,主要由以下部分组成:
Box Header
(盒子头部)
:
Size(大小)
:
盒子的总大小,包括头部和数据部分。
Type(类型)
:
盒子的类型标识符,对于
mdat
盒子,这个值是
'mdat'
。
Box Data
(盒子数据)
:
Media Data
(媒体数据)
:
实际的媒体数据,如视频帧和音频样本。
mdat
盒子的主要功能是存储媒体数据,使得播放器可以从中读取和解码视频和音频内容。
mdat
盒子通常与其他盒子(如 moov
盒子)配合使用,后者包含了描述媒体数据的元数据。
2.3 封装H264码流和AAC码流
使用
FFMPEG
库合成
H264
视频和
AAC
音频
ffmpeg -i input.h264 -i input.aac -c:v copy -c:a copy output.mp4
输出文件的持续时间与最短的输入流匹配
ffmpeg -i input.h264 -i input.aac -c:v copy -c:a copy -shortest output.mp4