原文地址:https://www.cnblogs.com/moonwalk/p/16244932.html

解析工具:

  • https://gpac.github.io/mp4box.js/test/filereader.html (mp4box)

1. 概述

mp4 容器格式相较于 flv、ts 容器格式来说,其定义较为复杂,本篇文章主要记录自己的学习理解。

2. mp4 结构概览

一个 mp4 文件可以看作有两个大类:

  • 记录媒体信息相关的部分
  • 媒体负载部分

典型结构如下:

  +-+-+-+-+-+-+-+-+-+-+-+-+-+
  |  ftyp  |  moov |  mdat  |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+

其中:

  • ftyp(file type box),文件头,记录一些兼容性信息
  • moov(movie box),记录媒体信息
  • mdat(media data),媒体负载

mp4box 图示如下:

img

编辑

添加图片注释,不超过 140 字(可选)

3. box 结构

mp4 封装格式采用称为 box 的结构来组织数据。 结构如下:

  +-+-+-+-+-+-+-+-+-+-+
  |  header  |  body  |
  +-+-+-+-+-+-+-+-+-+-+

其它所有 box 都在语法上继承自此基本 box 结构。

3.1 box header

box 分为普通 box 和 fullbox。 普通 box header 结构如下:

字段 类型 描述
size 4 Bytes 包含 box header 的整个 box 的大小
type 4 Bytes 4 个 ascii 值,如果是 “uuid”,则表示此 box 为用户自定义,可忽略
large size 8 Bytes size=1 时才有的字段,用于扩展,例如 mdat box 会需要此字段

fullbox 在上面的基础上新增了 2 个字段:

字段 类型 描述
version 1 Bytes 版本号
flags 3 Bytes 标识

3.2 box body

一个 box 可能会包含其它多个 box,此种 box 称为 container box。 因此 box body 可能是一种具体 box 类型,也有可能是其它 box。

4. ftyp(File Type Box)

ftyp 一般出现在文件的开头,用来指示该 mp4 文件使用的标准规范:

字段 类型 描述
major_brand 4 bytes 主版本
minor_version 4 bytes 次版本
compatible_brands[] 4 bytes 指定兼容的版本,注意此字段是一个 list,即可以包含多个 4 bytes 版本号

一个示例如下:

img

编辑

添加图片注释,不超过 140 字(可选)

5. moov(Movie Box)

moov 是一个 container box,一个文件只有一个,其包含的所有 box 用于描述媒体信息。 moov 的位置可以紧随着 ftyp 出现,也可以出现在文件末尾. 由于是一个 container box,所以除了 box header,其 box body 就是其它的 box。 一个示例如下:

img

编辑

添加图片注释,不超过 140 字(可选)

这些 box 并列出现,其中:

  • mvhd(moov header),用于简单描述一些所有媒体共享的信息
  • trak,即 track,轨道,用于描述音频流或视频流信息,可以有多个轨道,如上出现了 2 次,分别表示一路音频和一路视频流
  • udta(userdata),用户自定义,可忽略

5.1 mvhd(Movie Header Box)

mvhd 作为媒体信息的 header 出现(注意此 header 不是 box header,而是 moov 媒体信息的 header),用于描述一些所有媒体共享的基本信息。 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 时间基
duration 64/32 bit 文件时长,当 version=0 时取 32bit
rate 32 bit 播放速率,默认取 0x00010000,即 1.0
volume 16 bit 音量,默认取 0x0100,即 1.0
reserved 16 bit 0
reserved 2 x 32 bit 0
matrix 9 x 32 bit 可忽略
pre_defined 6 x 32 bit 0
next_track_ID 32 bit 下一个紧邻的 track box id

6. trak

trak box 是一个 container box,其子 box 包含了该 track 的媒体信息。 一个 mp4 文件可以包含多个 track,track之间是独立的,trak box 用于描述每一路媒体流。 一个示例如下:

img

编辑

添加图片注释,不超过 140 字(可选)

其中:

  • tkhd(track header box),用于简单描述该路媒体流的信息
  • edts(),
  • mdia(media box),用于详细描述该路媒体流的信息

6.1 tkhd(track header box)

tkhd 作为媒体信息的 header 出现(注意此 header 不是 box header,而是 track 媒体信息的 header),用于描述一些该 track 的基本信息。 tkhd 语法继承自 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
track_ID 32 bit 本 track id
reserved 32 bit 0
duration 64/32 bit 本 track 时长,当 version=0 时取 32bit
reserved 2 x 32 bit 0
layer 16 bit
alternate_group 16 bit
volume 16 bit 音量,如果是 audio track,则为 0x0100,即 1.0,否则取 0
reserved 16 bit 0
matrix 9 x 32 bit 可忽略
width 32 bit 宽,[16.16] 格式,不必与sample的像素尺寸一致,用于播放时的展示宽高
height 32 bit 高,[16.16] 格式 ,不必与sample的像素尺寸一致,用于播放时的展示宽高

6.2 edts

6.3 mdia(media box)

mdia box 是一个 container box,其子 box 描述 track 更详细的媒体信息。 一个示例如下:

img

编辑

添加图片注释,不超过 140 字(可选)

其中:

  • mdhd(Media Header Box),用于简单描述该路媒体流的信息
  • hdlr(Handler Reference Box),主要定义了 track 类型
  • stbl(Media Information Box),用于描述该路媒体流的解码相关信息和音视频位置等信息

6.3.1 mdhd(Media Header Box)

mdhd 作为媒体信息的 header 出现(注意此 header 不是 box header,而是 media 媒体信息的 header),用于描述一些该 track 的基本信息。 mdhd 语法继承自 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 时间基,同 mvhd 中 timescale
duration 64/32 bit 本 track 时长,当 version=0 时取 32bit
pad 1 bit 0
language 3 x 5 bit 最高位为0,后面15位为3个字符(见ISO 639-2/T标准中定义)
pre_defined 16 bit 0

6.3.2 hdlr(Handler Reference Box)

hdlr 主要定义了 track 类型。 hdlr 语法继承自 fullbox,注意下述示例出现的 version 和 flags 字段属于 fullbox header。

字段 类型 描述
version 8 bit 取 0 或 1,一般取 0
flags 24 bit
pre_defined 32 bit 0
handler_type 32 bit 取值为 vide:Video track,soun:Audio track,hint:Hint track,meta:Timed Metadata track,auxv:Auxiliary Video track
reserved 3 x 32 bit 0
name 不定长度 自定义名称,以 \0 结尾

7. 音视频 frame 与 sample、chunk 的关系

在继续介绍 stbl box 之前,需要先介绍一下 mp4 中定义的 sample 与 chunk:

  • sample,ISO/IEC 14496-12 中定义 samples 之间不能共享同一个时间戳,因此,在音视频 track 中,一个 sample 代表一个视频或音频帧
  • chunk,多个 sample 的集合,实际上音视频 track 中,chunk 与 sample 一一对应

8. stbl(Media Information Box)

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

img

编辑

添加图片注释,不超过 140 字(可选)

其中:

  • 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 在文件中的偏移

8.1 stsd(sample description box)

stsd 是个 container box,其存储了编码类型和初始化解码器需要的信息,并与具体编解码器类型有关:

字段 类型 描述
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’ 时才有
结束循环

8.1.1 h264 stsd

对于 h264 视频,典型结构如下:

img

编辑

添加图片注释,不超过 140 字(可选)

其上(只列出 avc1 与 avcC,其余 box 可忽略):

  • avc1,是 avc/h264/mpeg-4 part 10 视频编解码格式的代称,是一个 container box,但是 box body 也携带自身的信息
字段 类型 描述
reserved 6 x 8 bit 0
data_reference_index 16 bit
pre_defined 16 bit 0
reserved 16 bit 0
pre_defined 3 x 32 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 循环结束

在 srs 中,解析 avcc/AVCDecoderConfigurationRecord 结构解析参见 srs/trunk/src/kernel/srs_kerner_codec.cpp::SrsFormat::avc_demux_sps_pps() 函数。

8.1.2 aac stsd

对于 aac 音频,典型结构如下:

img

编辑

添加图片注释,不超过 140 字(可选)

可以看到,aac stsd 结构比较复杂,box 众多。实际上,在 ISO/IEC 14496-3 中,定义了 AudioSpecificConfig 类型,aac stsd 结构主要信息就来自 AudioSpecificConfig。 具体不做分析,可以参看 srs 中:

  • 解析 AudioSpecificConfig 结构的 srs/trunk/src/kernel/srs_kerner_codec.cpp::SrsFormat::audio_aac_sequence_header_demux() 函数
  • 封装 aac stsd 结构的 srs/trunk/src/kernel/srs_kernel_mp4.cpp::SrsMp4Encoder::flush() 函数

8.2 stts(time to sample box)

存储了该 track 每个 sample 到 dts 的时间映射关系:

字段 类型 描述
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
结束循环

这里为了节约条目的个数,采用了压缩存储的方式,即 sample_count 个连续的 sample 如果 sample_delta 时长一样,那么用一个条目就能表示了。 一个音频 track 的示例如下:

img

编辑

添加图片注释,不超过 140 字(可选)

一个视频 track 的示例如下:

img

编辑

添加图片注释,不超过 140 字(可选)

8.3 ctts(composition time to sample box)

存储了该 track 中,每个 sample 的 pts 与 dts 时间差(cts = pts - dts):

字段 类型 描述
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
结束循环

注意:

  • 此 box 在 dts 和 pts 不一样的情况下必须存在,如果一样,不用包含此 box
  • 如果 box 的 version=0,意味着所有 sample 都满足 pts >= dts,因而差值用一个无符号的数字表示。只要存在一个 pts < dts,那么必须使用 version=1、有符号差值来表示
  • 关于 ctts 的生成,可以参看 srs/trunk/src/kernel/srs_kernel_mp4.cpp::SrsMp4SampleManager::write_track() 函数 pts、dts、cts 满足公式:pts - dts = cts

8.4 stss(sync sample box)

针对视频 track,关键帧所属sample 的序号。

字段 类型 描述
version 8 bit 取 0 或 1,一般取 0
flags 24 bit
entry_count 32 bit 条目个数
开始循环
sample_number 32 bit sample 计数,从 1 开始
结束循环

一个视频示例如下:

img

编辑切换为居中

添加图片注释,不超过 140 字(可选)

8.5 stsc/stz2(sample to chunk box)

存储了该 track 中每个 sample 与 chunk 的映射关系。

字段 类型 描述
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 信息的索引
结束循环

一个音频示例如下:

img

编辑切换为居中

添加图片注释,不超过 140 字(可选)

  • 第一组 chunk 的 first_chunk 序号为 1,每个 chunk 的 sample 个数为 1,因为第二组 chunk 的 first_chunk 序号为 2,可知第一组 chunk 中只有一个 chunk
  • 第二组 chunk 的 first_chunk 序号为 2,每个 chunk 的 sample 个数为 2,因为第三组 chunk 的 first_chunk 序号为 24,可知第二组 chunk 中有 22 个 chunk,有 44 个 sample

8.6 stsz(sample size box)

存储了该 track 中每个 sample 的字节大小。

字段 类型 描述
version 8 bit 取 0 或 1,一般取 0
flags 24 bit
sample_size 32 bit 指定默认的 sample 字节大小,如果所有 sample 的大小不一样,这个字段为 0
sample_count 32 bit track 中 sample 的数量
开始循环
entry_size 32 bit 每个 sample 的字节大小
结束循环

8.7 stco/co64(chunk offset box)

存储了该 track 中每个 chunk 在文件中的偏移。

字段 类型 描述
version 8 bit 取 0 或 1,一般取 0
flags 24 bit
entry_count 32 bit
开始循环
chunk_offset 32 bit chunk 在文件中的位置
结束循环

9. mdat

mdat 也是一个 box,拥有 box header 和 box body。 mdat 可以引用外部的数据,参见 moov --> udta --> meta,这里不讨论,只讨论数据存储在本文件中的形式。 对于 box body 部分,采用一个一个 samples 的形式进行存储,即一个一个音频帧或视频帧的形式进行存储。 码流组织方式采用 avcc 格式,即 AUD + slice size + slice 的形式。

9.1 通过时间进行定位寻址/随机访问

参考 https://www.jianshu.com/p/529c3729f357 6.2 节

  >>> 音视频开发 视频教程: https://ke.qq.com/course/3202131?flowToken=1031864 
  >>> 音视频开发学习资料、教学视频,免费分享有需要的可以自行添加学习交流群: 739729163  领取

在这里插入图片描述

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐