Bootstrap

音视频的文件封装——AVI、MP4、MKV

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.265HEVC)等压缩标准。
  • 音频流:常见的编码格式包括 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:样本到时间表。
  • stscsample-to-chunk 表。
  • STSZ:样本量(框架)
  • meta:包含元数据信息的容器。
以下是 MP4 中使用的二级原子列表:
  • mvhd:包含视频头信息以及视频的完整详细信息。
  • trak:包含单个轨道的容器。
  • udta:包含用户和轨迹信息的容器。
  • iodsMP4 文件描述符
也就是是 MP4 文件由若干个 Box 组成,对于一个 Box 是有一个 Header Box 组成如下所示:
对于 Box Header
  • size(大小):包含Header的整个Box所占用的大小。
  • type(类型):通常是4ASCII码的字符如“ftyp”“moov”等,这些box type都是已经预定义好的,表示固定的含义。如果是“uuid”,表示该box为用户自定义扩展类型,如果box type是未定义的,应该将其忽略。
  • largesize(更大的长度描述):如果header中的size1,则表示box长度需要更多的bits位来描述,在后面会有一个64bits位的largesize用来描述box的长度。如果size0,表示该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版本,01,一般为0
  • creation time : 创建时间(相对于UTC时间1904-01-01零点的秒数)。
  • modification time : 修改时间 。
  • timescale: 定义时间的单位(时间基准)。例如,视频时间可能是以每秒 1000 帧为基准的。比如 audio tracktime scale = 8000, duration = 560128,时长为70.016video tracktime scale =600, duration = 42000,时长为70
  • duration: 电影的总时长,通常以 timescale 为单位表示。
  • rate: 播放速率,通常为 1,表示正常播放速度。高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,该值为1.00x00010000)表示正常前向播放。
  • volume: 音量控制,通常为 1,表示正常音量。[8.8] 格式,1.00x0100)表示最大音量。
  • 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 Boxmdia
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 Boxhdlr
  • hdlr 盒子标识了该轨道的类型(如视频、音频、字幕等)。主要字段:
                handler_type : 该字段标识该轨道的类型,常见的值有:
                vide :视频轨道
                soun :音频轨道
                text :字幕轨道
                hint :用于提示信息流(例如流媒体)。
  • name: 可以包含一个名称字符串,通常用于表示该轨道的描述性信息。
通过 hdlr 盒子,播放器能够识别该轨道的内容类型,并选择合适的方式来处理或解码它。
2.2.6 Media Information Boxminf
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 Boxsmhd
MP4 文件格式中, smhd box Sound Media Header Box )是一个用于描述音频轨道的 box 。它包含了与音频相关的特定信息。
smhd box 是一个 Full Box ,这意味着它包含了 version flags 字段。其结构如下:
  • version1字节,表示box的版本号,通常为0
  • flags3字节,表示一些标志位,通常为0
  • balance2字节,表示立体声平衡,采用[8.8]格式的定点数值。0表示左右声道平衡,负值表示左声道更强,正值表示右声道更强。
  • reserved2字节,保留字段,通常为0
smhd box 的作用是提供音频轨道的基本信息,特别是立体声平衡信息。它通常包含在 Media
Information Box minf )中, minf Media Box mdia )的子 box。
2.2.8 Data Information Boxdinf
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 Boxstbl
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 Boxstsd
Sample Description Box 用于描述每个 track sample (样本)类型和初始化解码器所需的信息。它是Sample Table Box( stbl )的子 box
stsd box 是一个 Full Box ,包含以下字段:
  • version1字节,表示box的版本号,通常为0
  • flags3字节,表示一些标志位,通常为0
  • entry_count4字节,表示sample描述条目的数量。
  • sample_entries:包含若干个sample描述条目,每个条目描述一种sample类型,类型信息如 “vide”“soud”等。
  • format:视频或者音频的编码格式。
  • samplerate4字节):采样率。[16.16]格式的数据。
  • data_reference_index 2 字节):利用这个索引可以检索与当前 sample description 关联的数据。数据引用存储在data reference box
  • samplesize 2 字节):采样位数。默认是 16 比特。
  • channelcount 2 字节):通道个数
  • widthheight:像素宽高。
  • horizresolutionvertresolution:每英寸的像素值(dpi)[16.16]格式的数据。通常为 0x00480000(72 dpi)。
  • frame_count:每个sample中的视频帧数,默认是1。可以是一个sample中有多帧数据。
  • compressorname:编码器名称。
  • depth2字节,图像深度,通常为0x001824位)。
2.2.11 Decoding Time to Sample Boxstts
Decoding Time to Sample Box 用于记录每个 sample 的解码时间( DTS )。它是 Sample Table Box
stbl )的子 box stts box 通过一个时间戳映射表,定义了 sample 的解码时间,从而帮助播放器正确地解码和播放媒体数据。stts box 是一个 Full Box ,包含以下字段:
  • version1字节,表示box的版本号,通常为0
  • flags3字节,表示一些标志位,通常为0
  • entry_count4字节,表示时间戳映射表中的条目数量
  • 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 ,包含以下字段:
  • version1字节,表示box的版本号,通常为0
  • flags3字节,表示一些标志位,通常为0
  • entry_count4字节,表示关键帧的数量。
  • sample_number:每个关键帧的sample序号,entry_count个。
stss box 的主要作用是提供关键帧的位置信息。播放器在进行快进或快退操作时,会跳转到最近的关键帧,以确保视频能够正确解码和播放。具体来说,stss box 列出了所有关键帧的 sample 序号,帮助播放器快速定位到这些帧。
2.2.13 composition time to sample boxctts
Composition Time to Sample Box 用于记录每个 sample 的显示时间( PTS )和解码时间( DTS )之间的差值。它是Sample Table Box stbl )的子 box ctts box 通过提供 composition offset (显示时间偏移),帮助播放器正确地显示视频帧,特别是在处理包含B 帧的视频时。
ctts box 是一个 Full Box ,包含以下字段:
  • version1字节,表示box的版本号,通常为0
  • flags3字节,表示一些标志位,通常为0
  • entry_count4字节,表示时间戳映射表中的条目数量
  • 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 Boxstsc
Sample To Chunk Box stsc )用于描述 sample (样本)和 chunk (块)之间的映射关系。它是 Sample Table Box( stbl )的子 box stsc box 通过定义 sample 如何分配到 chunk 中,帮助播放器正确地读取和解码媒体数据。stsc box 是一个 Full Box ,包含以下字段
  • version1字节,表示box的版本号,通常为0
  • flags3字节,表示一些标志位,通常为0
  • entry_count4字节,表示时间戳映射表中的条目数量
  • sample_entries:包含若干个时间戳映射条目,每个条目包含两个字段:

        first_chunk4字节,表示第一个chunk的索引。

        samples_per_chunk4字节,表示每个chunk包含的sample数量。

        sample_description_index4字节,表示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 Boxstsz                
Sample Size Box stsz )用于存储每个样本的字节大小信息。这对于解码器来说非常重要,因为它需要知道每个样本的大小才能正确地读取和处理媒体数据。
        
stsz box 包含如下字段:
  • ample_size:一个32位的无符号整数。如果所有样本的大小相同,这个字段会记录样本的大小; 如果样本大小不同,这个字段为0
  • sample_count:一个32位的无符号整数,表示样本的总数。
  • entry_size:一个32位的无符号整数数组,只有当sample_size0时存在,记录每个样本的大小。
解析 stsz box 时,首先检查 sample_size 字段。如果 sample_size 不为 0 ,则所有样本的大小都相同,直接使用这个值即可。如果sample_size 0 ,则需要读取 entry_size 数组中的每个值来获取每个样本的大小。
2.2.16 Chunk Offset Boxstco
Chunk Offset Box stco )用于存储每个 chunk 的字节偏移量。解码器通过这些偏移量来定位和读取存储在文件中的媒体数据。stco box 包含如下字段:
  • version:一个8位的无符号整数,表示box的版本。flags24位的标志位,通常为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
;