Skip to content

LV085-MP4常见Box

一、常见 box

好了,下面我们就来看看比较重要的 box 吧。 因为,MP4 的 box 特别多,我们不会一个个都介绍,我们只介绍一下比较重要的 box。

1. ftyp(File Type Box)

1.1 box 说明

首先,ftyp box 放在 MP4 文件的开始,用来表示文件类型,该 box 的 Box Data 包含了 4 字节的主版本(major brand)、4 字节的版本号(minor version)和若干个 4 字节数组组成的兼容版本(compatible_brands)。

该 Box 有且仅有 1 个,并且只能被包含在文件层,而不能被其他 Box 包含。该 Box 放在文件的最开始,指示文件的相关信息。伪代码如下:

c
aligned(8) class FileTypeBox
	extends Box(‘ftyp’) {
		unsigned int(32) major_brand;         // 主版本
		unsigned int(32) minor_version;       // 次版本
		unsigned int(32) compatible_brands[]; // 指定兼容的版本,注意此字段是一个 list,即可以包含多个 4 bytes 版本号
	}

1.2 示例

image-20251216151128679

这里是一个 ftyp box 的数据,可以看到大小为 0x18,也就是 24 字节,头占了 8 个字节,数据占了 16 字节。但是这里好像没有显示全,完整的数据应该是下面的部分:

image-20251216151927108

2. moov(Movie Box)

moov 是一个 container box,一个文件只有一个,其包含的所有 box 用于描述媒体信息(metadata)。它可以紧随着 ftyp 出现,也可以出现在文件末尾。

由于是一个 container box,所以除了 box header,其 box body 就是其它的 box。这个 box 中会一层层嵌套很多层 box。总体嵌套逻辑就是 movie 里面是 track,track 里面是 sample,多个 sample 又组成了一个个 chunk。

image-20251216154355374

2.1 mvhd(Movie Header Box)

2.1.1 box 说明

mvhd box(movie header box) 作为媒体信息的 header 出现 (注意此 header 不是 box header,而是 moov 媒体信息的 header),用于描述一些所有媒体共享的基本信息。比如说 MP4 文件的创建时间、时间单位、总时长等信息。

这个 box 的伪代码如下:

c
aligned(8) class MovieHeaderBox extends FullBox(‘mvhd’, version, 0) {
    if (version==1) {
        unsigned int(64) creation_time;
        unsigned int(64) modification_time;
        unsigned int(32) timescale;
        unsigned int(64) duration;
    } else { // version == 0
        unsigned int(32) creation_time;
        unsigned int(32) modification_time;
        unsigned int(32) timescale;
        unsigned int(32) duration;
    }
    template int(32) rate = 0x00010000; // typically 1.0
    template int(16) volume = 0x0100; // typically, full volume
    const bit(16) reserved = 0;
    const unsigned int(32)[2] reserved = 0;
    template int(32)[9] matrix = { 0x00010000,0,0,0,0x00010000,0,0,0,0x40000000 };
    // Unity matrix
    bit(32)[6] pre_defined = 0;
    unsigned int(32) next_track_ID;
}

mvhd 语法继承自 fullbox,注意下述示例出现的 version 和 flags 字段属于 fullbox header。

字段 类型 描述
version 8 bit 取 0 或 1,一般取 0
flags 24 bit 标识
creation time 64/32 bit 创建时间,当 version = 0 时取 32bit
modification time 64/32 bit 修改时间,当 version = 0 时取 32bit
timescale 32 bit 一秒包含的时间单位(整数)。举个例子,如果 timescale 等于 1000,那么,一秒包含 1000 个时间单位(后面 track 等的时间,都要用这个来换算,比如 track 的 duration 为 10,000,那么,track 的实际时长为 10,000/1000 = 10s)。
duration 64/32 bit 文件时长,当 version = 0 时取 32bit
rate 32 bit 播放速率,默认取 0x00010000,即 1.0
volume 16 bit 音量,默认取 0x0100,即 1.0
reserved 16 bit
reserved 2x32 bit
matrix 9x32 bit 可忽略
pre defined 6x32 bit
next track ID 32 bit 32 位整数,非 0,一般可以忽略不计。当要添加一个新的 track 到这个影片时,可以使用的 track id,必须比当前已经使用的 track id 要大。也就是说,添加新的 track 时,需要遍历所有 track,确认可用的 track id
2.1.2 示例

我们来找一些这个 duration,自己不想计算的话,可以换个工具,比如 MP4 Reader、AtomicBrowser 等工具,都可以直接解析出每部分的含义,这里使用 MP4 Reader 打开,因为 AtomicBrowser 没找到下载链接。

image-20251216161402603

2.2 trak

image-20251216154441744

track,轨道,用于描述音频流或视频流信息,可以有多个轨道,如上出现了 2 次,分别表示一路音频和一路视频流。具体是音频 trak 还是视频 trak,会在 trak box 中的 mdia box 里面的 hdlr box 中表示出来。

它是一个容器 Box,本身不包含任何内容,其含义由内部的 Box 定义。媒体文件中可能包含多条 Track,每一条 Track 是独立的,都有自己的时间和空间信息,比如音频和视频可以单独分为两个 Track 存放,而单个视频流也可以分为多个 Track 存放。

2.3 trak/tkhd

tkhd box(track header box) 作为媒体信息的 header 出现 (注意此 header 不是 box header,而是 track 媒体信息的 header),用于描述一些该 track 的基本信息。比如说视频的宽高信息和音频的音量信息等。一个 Track 只有一个 tkhd。

字段 类型 描述
version 8 bit 取 0 或 1, 一般取 0
flags 24 bit 标识
creation time 64/32 bit 创建时间, 当 version = 0 时取 32bit
modification time 64/32 bit 修改时间, 当 version = 0 时取 32bit
track ID 32 bit 当前 track id, 是唯一表示,一个文件中不应该存在两个 Track_ID 相同的 Track;
reserved 32 bit
duration 64/32 bit 当前轨道的时长,如果有轨道的编辑列表则值为所有编辑列表持续时间之和;否则为样本持续时间之和。如果无法确认则时间设置为 0xfffffff。另外时间需要根据 mvhd 中的 time_scale 计算。当 version = 0 时取 32bit
reserved 2x32 bit
layer 16 bit 视频轨道的叠加顺序, 数字越小越靠近观看者, 比如 1 比 2 靠上,0 比 1 靠上;
alternate group 16 bit 当前 track 的分组 ID, alternate group 值相同的 track 在同一个分组里面。同个分 组里的 track, 同一时间只能有一个 track 处于播放状态。 当 alternate group 为 0 时, 表示当前 track 没有跟其他 track 处于同个分组。一个分组里面, 也可以只有一个 track;
volume 16 bit 音量, 如果是 audio track, 则为 0x0100, 即 1.0, 否则取 0
reserved 16 bit
matrix 9x32 bit 视频的转换矩阵,默认是个单位矩阵;
width 32 bit 宽, [16.16] 格式(高 16 位为整数部分,低 16 位为小数部分), 不必与 sample 的像素尺寸一致, 用于播放时的展示宽高,在对轨道进行操作前图像都会缩放到当前的 size。
height 32 bit 高, [16.16] 格式(高 16 位为整数部分,低 16 位为小数部分), 不必与 sample 的像素尺寸一致, 用于播放时的展示宽高,在对轨道进行操作前图像都会缩放到当前的 size。

2.4 trak/mdia

trak box 还有一个 mdia box,它是媒体信息 box。它包含了 3 个子 box,一个是 mdhd box,一个是刚才提到的 hdlr box,一个是最重要的 minf box,这个 box 里面包含了 sample 的很多信息,这些信息是找到并正确使用音频和视频数据的关键。

c
aligned(8) class MediaBox extends Box(‘mdia’) {
}

2.5 trak/mdia/mdhd

mdhd(Media Header Box) 作为媒体信息的 header 出现 (注意此 header 不是 box header,而是 media 媒体信息的 header),用于描述一些该 media 的基本信息。mdhd 和 tkhd ,内容大致都是一样的。不过 tkhd 通常是对指定的 track 设定相关属性和内容。而 mdhd 是针对于独立的 media 来设置的。

它的语法继承自 fullbox,注意下述示例出现的 version 和 flags 字段属于 fullbox header。

字段 类型 描述
version 8 bit 取 0 或 1,一般取 0
flags 24 bit 标识
creation time 64/32 bit 创建时间,当 version = 0 时取 32bit
modificationtime 64/32 bit 修改时间,当 version = 0 时取 32bit
timescale 32 bit 时间基,同 mvhd 中 timescale
duration 64/32 bit 本 track 时长,当 version = 0 时取 32bit
pad 1 bit
language 3x5 bit 当前 track 的媒体的语言代码。最高位为 0,后面 15 位为 3 个字符(见 ISO 639-2/T 标准中定义)
pre defined 16 bit

mdhd box 里面最重要的一个值就是时间单位 time scale,这个时间单位是 sample 的时间戳的单位,控制播放速度和音视频同步都需要使用到这个值。

注:timescale 同 mvhd 中的 timescale,但是需要注意虽然意义相同,但是值有可能不同,下边 stts, ctts 等时间戳的计算都是以 mdhd 中的 timescale。

2.6 trak/mdia/hdlr

hdlr box (Handler Reference Box)主要解释了媒体的播放过程信息。声明当前 track 的类型,表明是音频还是视频 track,以及对应的处理器(handler)。

hdlr 语法继承自 fullbox,注意下述示例出现的 version 和 flags 字段属于 fullbox header。

字段 类型 描述
version 8 bit 取 0 或 1,一般取 0
flags 24 bit
pre defined 32 bit
handler type 32 bit vide (0x76 69 64 65) video track
soun (0x73 6f 75 6e) audio track
hint (0x68 69 6e 74) hint track
meta (0x6d 65 74 61): Timed Metadata track
auxv (0x61 75 78 76) Auxiliary Video track
reserved 3x32 bit
name 不定长度 自定义名称,以 \0 结尾

2.7 trak/mdia/minf

minf box(Media Information box) 解释 track 媒体数据的 handler-specific 信息,media handler 用这些信息将媒体时间映射到媒体数据并进行处理。minf 同样是个 container box,其内部需要关注的内容是 stbl box(sample table box),这也是 moov 中最复杂的部分。里面存放着可以计算得到每一个 chunk 的偏移地址、每一个 sample 在文件中的地址信息和大小、每一个 sample 的时间戳和每一个视频 IDR 帧的地址信息。

image-20251216194049614

一般情况下,“minf”包含一个 header box,一个 “dinf” 和一个 “stbl”,其中,header box 根据 track type(即 media handler type)分为“vmhd”、“smhd”、“hmhd” 和“nmhd”,“dinf”为 data information box,“stbl”为 sample table box。

2.7.1 *mhd

*mhd(Media Info Header Box)可分为 “vmhd”、“smhd”、“hmhd” 和“nmhd”,比如视频类型则为 vmhd,音频类型为 smhd。

  • vmhd

graphics mode:视频合成模式,为 0 时拷贝原始图像,否则与 opcolor 进行合成。

opcolor:一组 (red,green,blue),graphics modes 使用。

  • smhd

balance:立体声平衡,[8.8] 格式值,一般为 0 表示中间,-1.0 表示全部左声道,1.0 表示全部右声道。

2.7.2 dinf

dinf(Data Information Box)描述了如何定位媒体信息,是一个 container box。“dinf” 一般包含一个 “ dref ”(data reference box)

image-20251216194236099

“ dref ”下会包含若干个 “url” 或“urn”,这些 box 组成一个表,用来定位 track 数据。简单的说,track 可以被分成若干段,每一段都可以根据 “url” 或“urn”指向的地址来获取数据,sample 描述中会用这些片段的序号将这些片段组成一个完整的 track。一般情况下,当数据被完全包含在文件中时,“url”或 “urn” 中的定位字符串是空的。

2.7.3 stbl

在学习 stbl box 之前,需要先回顾一下 mp4 中定义的 sample 与 chunk:

image-20251216200717378

sample:ISO/IEC 14496-12 中定义 samples 之间不能共享同一个时间戳,因此,在音视频 track 中,一个 sample 代表一个视频或音频帧。

chunk:多个 sample 的集合,实际上音视频 track 中,chunk 与 sample 一一对应。

stbl box 是一个 container box,是整个 track 中最重要的一个 box,其子 box 描述了该路媒体流的解码相关信息、音视频位置信息、时间戳信息等。

image-20251216200824216

其中:

  • stsd(sample description box):存储了编码类型和初始化解码器需要的信息,并与具体编解码器类型有关。

  • stts(time to sample box):存储了该 track 每个 sample 到 dts 的时间映射关系。

  • stss(sync sample box):针对视频 track,关键帧所属 sample 的序号。

  • ctts(composition time to sample box):存储了该 track 中,每个 sample 的 cts 与 dts 的时间差。

  • stsc/stz2(sample to chunk box):存储了该 track 中每个 sample 与 chunk 的映射关系。

  • stsz(sample size box):存储了该 track 中每个 sample 的字节大小。

  • stco/co64(chunk offset box):存储了该 track 中每个 chunk 在文件中的偏移。

2.7.4 stbl/stsd

stsd(sample description box)主要存储了编码类型和初始化解码器需要的信息。

c
aligned(8) abstract class SampleEntry (unsigned int(32) format)
    extends Box(format){
        const unsigned int(8)[6] reserved = 0;
        unsigned int(16) data_reference_index;
	}

class BitRateBox extends Box('btrt'){
    unsigned int(32) bufferSizeDB;
    unsigned int(32) maxBitrate;
    unsigned int(32) avgBitrate;
}

aligned(8) class SampleDescriptionBox (unsigned int(32) handler_type)
    extends FullBox('stsd', version, 0){
    	int i ;
    	unsigned int(32) entry_count;
    	for (i = 1 ; i <= entry_count ; i++){
        	SampleEntry(); // an instance of a class derived from SampleEntry
        }
    }

针对不同的 handler_type,SampleDescriptionBox 后续应用不同的 SampleEntry 类型,比如当类型为 video track 时,SampleEntry 为 VisualSampleEntry。

字段 类型 描述
version 8 bit 取 0 或 1, 一般取 0
flags 24 bit
entry count 32 bit entry 个数
开始循环
AudioSampleEntry() 不定大小 子 box, 当 handler type ='soun' 时才有
VisualSampleEntry() 不定大小 子 box, 当 handler type ='vide' 时才有
HintSampleEntry() 不定大小 子 box, 当 handler type ='hint' 时才有
MetadataSampleEntry() 不定大小 子 box, 当 handler type ='meta' 时才有
结束循环

这里以视频为例,包含子 box:avc1,表示是 H264 的视频。

image-20251216201248106

这里我们只看一下 avc1 与 avcC,其余 box 可忽略。

  • avc1,是 avc/h264/mpeg-4 part 10 视频编解码格式的代称,是一个 container box,但是 box body 也携带自身的信息。
字段 类型 描述
reserved 6x8 bit 0
data_reference_index 16 bit 可以检索与当前 sampledescription 关联的数据。数据引用存储在 data reference box
pre_defined 16 bit 0
reserved 16 bit 0
pre_defined 3x32 bit 0
width 16 bit 像素宽度
height 16 bit 像素高度
horizresolution 32 bit 每英寸的像素值(dpi),[16.16] 格式的数据,固定为 0x00480000,72 dpi
vertresolution 32 bit 每英寸的像素值(dpi),[16.16] 格式的数据,固定为 0x00480000,72 dpi
reserved 32 bit 0
frame_count 16 bit 每个 sample 中的视频帧数,固定为 1
compressorname 32 bit 0
depth 16 bit 0x0018, rgb24 位深
pre_defined 16 bit -1
  • avcC(AVC Video Stream Definition Box),存储 sps && pps,即在 ISO/IEC 14496-15 中定义的 AVCDecoderConfigurationRecord 结构。
字段 类型 描述
configurationVersion 8 bit 固定 1
AVCProfileIndication 8 bit 编码时设置的 profile,例如 base、main、high 等,具体 参见 ISO_IEC_14496-10-AVC-2003.pdf, page 45
profile_compatibility 8 bit
AVCLevelIndication 8 bit 编码时设置的 level
reserved 6 bit '111111'b
lengthSizeMinusOne 2 bit
reserved 3 bit '111′b
numOfSequenceParameterSets 8 bit sps 个数,一般为 1
sps 循环开始
sequenceParameterSetLength 16 bit
sps 8*sequenceParameterSetLength sps
sps 循环结束
numOfPictureParameterSets 8 bit pps 个数,一般为 1
pps 循环开始
pictureParameterSetLength 16 bit
pps 8*pictureParameterSetLength pps
pps 循环结束
2.7.5 stbl/stts

stts(time to sample box)存储了该 track 每个 sample 到 dts 的时间映射关系。包含了一个压缩版本的表,通过这个表可以从解码时间映射到 sample 序号。表中的每一项是连续相同的编码时间增量 (Decode Delta) 的个数和编码时间增量。通过把时间增量累加就可以建立一个完整的 time to sample 表。

字段 类型 描述
box size 4*8 bit box 的字节数
box type 4*8 bit stts
version 8 bit 取 0 或 1,一般取 0
flags 24 bit
entry_count 32 bit 条目个数
开始循环
sample_count 32 bit 播放时长为 sample_delta 的连续 sample 个数
sample_delta 32 bit 单个 sample 的播放时长,单位为 timescale
结束循环
2.7.6 stbl/ctts

ctts(composition time to sample box)存储了该 track 中,每个 sample 的 pts 与 dts 时间差 (cts = pts - dts)。如果一个视频只有 I 帧和 P 帧,则 ctts 这个表就不需要了,因为解码顺序和显示顺序是一致的,但是如果视频中存在 B 帧,则需要 ctts。

字段 类型 描述
box size 4*8 bit box 的字节数
box type 4*8 bit ctts
version 8 bit 取 0 或 1, 一般取 0
flags 24 bit
entry_count 32 bit 条目个数
开始循环
sample_count 32 bit cts 为 sample_offset 的连续 sample 个数
sample_offset signed/unsigned 32 bit 单个 sample 的 cts, 单位为 timescale。支持负数, 当 version = 1 时为 signed
结束循环
2.7.7 stbl/stss

stss(sync sample box)它包含 media 中的关键帧的 sample 表。关键帧是为了支持随机访问。如果此表不存在,说明每一个 sample 都是一个关键帧。

字段 类型 描述
box size 4*8 bit box 的字节数
box type 4*8 bit stss
version 8 bit 取 0 或 1, 一般取 0
flags 24 bit
entry_count 32 bit 条目个数
开始循环
sample_number 32 bit 媒体流中关键帧的 sample 序号
结束循环
2.7.8 stbl/stsc

stsc(sample to chunk box)存储了该 track 中每个 sample 与 chunk 的映射关系。,也就是哪些 sample 属于哪个 chunk。

字段 类型 描述
box size 4*8 bit box 的字节数
box type 4*8 bit stsc
version 8 bit 取 0 或 1, 一般取 0
flags 24 bit
entry_count 32 bit 条目个数
开始循环
first_chunk 32 bit 一组 chunk 的第一个 chunk 的序号,chunk 的编号从 1 开始
samples_per_chunk 32 bit 每个 chunk 有多少个 sample
sample_description_index 32 bit stsd box 中 sample desc 信息的索引
结束循环
2.7.9 stbl/stco、co64

stco(chunk offset box)中存储了每个 chunk 在文件中的位置,这样就可以直接在文件中找到媒体数据,而不用解析 box。需要注意的是一旦前面的 box 有了任何改变,这张表都要重新建立。

字段 类型 描述
box size 4*8 bit box 的字节数
box type 4*8 bit stco/co64
version 8 bit 取 0 或 1, 一般取 0
flags 24 bit
entry_count 32 bit Chunk offset 的数目。
开始循环
chunk_offset 32/64 bit 这个 chunk 相对于文件开头的偏移。co64 box 为 64bit
结束循环

stco 有两种形式,如果视频过大的话,就有可能造成 chunkoffset 超过 32bit 的限制。所以,这里针对大 Video 额外创建了一个 co64 的 Box。它的功效等价于 stco,也是用来表示 sample 在 mdat box 中的位置。只是,里面 chunk_offset 是 64bit 的。

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

2.7.10 stbl/stsz

stsz(sample size box)包含 sample 的数量和每个 sample 的字节大小,这个 box 相对来说体积比较大的。表明视频帧或者音频帧大小,FFmpeg 里面的 AVPacket 的 size 数据大小,就是从这个 box 中来的。

字段 类型 描述
box size 4*8 bit box 的字节数
box type 4*8 bit stsz
version 8 bit 取 0 或 1, 一般取 0
flags 24 bit
sample_size 32 bit 指定默认的 sample 字节大小,如果所有 sample 的大小不一样,这个字段为 0, 如果所有的 sample 大小相同,那么大小就是这个值
sample_count 32 bit track 中 sample 的数量
开始循环
sample_size 32 bit 每个 sample 的字节大小
结束循环

3. mdat(media data box)

mdat box 是 MP4 的音视频数据存放的地方。mdat box 基本由头部和数据两部分组成,box type 是 “mdat” 的 ASCII 码值。对于 H264 来说,是一个个 NALU,码流格式使用的是《码流结构》里面的 MP4 格式。这里的 NLAU 不再包含 SPS 和 PPS,这些数据已经放到 moov box 里面了,此处 NALU 类型是图像数据或者 SEI 数据。

mdat 的位置比较灵活,可以位于 moov 之前,也可以位于 moov 之后,但必须和 stbl 中的信息保持一致。它可以引用外部的数据,参见 moov → udta → meta,这里不讨论,只讨论数据存储在本文件中的形式。

mdat 也是一个 box,拥有 box header 和 box body。对于 box body 部分,采用一个一个 samples 的形式进行存储,即一个一个音频帧或视频帧的形式进行存储。没有同步字,没有分隔符,只能根据索引进行访问,也就是说媒体数据 mdat 即便没有 Box Header 也能正常解析。。即:

md
Box header + Box Data
==>
Box size + Box type + NALU + ... + NALU
NALU = NALU length + NALU Header + NALU Data

码流组织方式采用 avcc 格式,即 AUD + slice size + slice 的形式。

AUD(Access Unit Delimiter)访问单元分隔符 用于标识一个访问单元(AU)的起始位置,帮助解码器快速同步视频流。H264 中它的 NALU 类型值为 9,加上起始码的话就是 00 00 00 01 09

参考资料:

MP4 封装格式 - 沉默的思想 - 博客园

(5 封私信) 视频封装格式:MP4 格式详解 - 知乎

封装格式之 MP4 格式简介 — MyNote release 文档

MP4 封装格式—音视频基础知识 · FFmpeg 原理 · FFmpeg 书籍

MP4 封装格式详解_mp4 封装-CSDN 博客

MP4 文件结构解析_在线解析 mp4 box-CSDN 博客

视频封装格式:MP4_格式详解