参考链接

  • FFmpeg中mp4的demuxer(mov.c)代码阅读 - 简书
  • mp4文件格式解析 - 简书
  • mp4封装格式各box类型讲解及IBP帧计算_青丶空゛的博客-CSDN博客
  • 5分钟入门MP4文件格式 - 程序猿小卡 - 博客园
  • ​关于M4A文件的随机访问 - 云+社区 - 腾讯云

MP4文件格式相关内容

  • MP4文件由许多box组成,每个box包含不同的信息, 这些box以树形结构的方式组织。
  • 以下是主要box的简要说明:

  • 根节点之下,主要包含三个节点:ftyp、moov、mdat。

    • ftyp:文件类型。描述遵从的规范的版本。
    • moov box:媒体的metadata信息,保存了音视频数据的时空信息。
    • mdat:具体的媒体数据。
    • 说明:在 mp4 中默认写入字节序是 Big-Endian的。

2. mp4文件基本信息

分析mp4文件的工具:

  • mp4box.js:一个在线解析mp4的工具。
  • bento4:包含mp4dump、mp4edit、mp4encrypt等工具。
  • MP4Box:类似于bento4,包含很全面的工具。
  • mp4info.exe: windows平台图形界面展示mp4基本信息的工具。

  • mvhd针对整个影片,tkhd针对单个track,mdhd针对媒体,vmhd针对视频,smhd针对音频,可以认为是从 宽泛 > 具体,前者一般是从后者推导出来的。

mp4文件基本信息

  • audio信息:

    • smplrate:sample rate(采样率)。
    • channel:通道个数。
    • bitrate:比特率。
    • audiosamplenum:音频sample的个数。
  • video信息:
    • width、height:视频的宽/高。
    • bitrate:比特率(码率),秒为单位。等于视频总的大小/时长。
    • frames:视频帧数。
    • fps:帧率(frame per second)。
    • total_time:时间长度,ms为单位。等于duration/timescale。
    • timescale:时间的粒度,1000表示1000个单位为1s。
    • duration:时间粒度的个数。
    • videosamplenum:视频sample的个数。

3. 封装格式重要概念

box

  • mp4文件由若干个box组成。下面是box结构的一个示意图。

  • box由header和body组成,header指明box的size和type。size是包含box header的整个box的大小。
  • box type,通常是4个ASCII码的字符如“ftyp”、“moov”等,这些box type都是已经预定义好的,表示固定的含义。如果是“uuid”,表示该box为用户自定义扩展类型,如果box type是未定义的,应该将其忽略。
  • 如果header中的size为1,则表示box长度需要更多的bits位来描述,在后面会有一个64bits位的largesize用来描述box的长度。如果size为0,表示该box为文件的最后一个box,文件结尾(同样只存在于“mdat”类型的box中)。
  • 只有“mdat”类型的box才可能会用到large size
  • size后面紧跟着的32位为box type,一般是4个字符,如“ftyp”、“moov”等,这些box type都是预定义好的,分别表示固定的意义。如果是“uuid”,表示box为用户的扩展类型,如果未定义box type 需要将其忽略
  • box中可以包含box,这种box称为container box。
  • box分为两种,Box和Fullbox。FullBox 是 Box 的扩展,Header 中增加了version 和 flags字段,分别定义如下:
aligned(8) class Box (unsigned int(32) boxtype,optional unsigned int(8)[16] extended_type) {unsigned int(32) size;unsigned int(32) type = boxtype;if (size==1) {unsigned int(64) largesize;} else if (size==0) {// box extends to end of file}if (boxtype==‘uuid’) {unsigned int(8)[16] usertype = extended_type;}
}
  • FullBox有version和flags字段,
aligned(8) class FullBox(unsigned int(32) boxtype, unsigned int(8) v, bit(24) f)
extends Box(boxtype) {unsigned int(8) version = v;bit(24) flags = f;
}

MP4box

ftyp box

  • 该box有且只有1个,并且只能被包含在文件层,而不能被其他box包含。该box应该被放在文件的最开始,指示该MP4文件应用的相关信息。
  • “ftyp” body依次包括1个32位的major brand(4个字符),1个32位的minor version(整数)和1个以32位(4个字符)为单位元素的数组compatible brands。这些都是用来指示文件应用级别的信息。
  • major_brand:比如常见的 isom、mp41、mp42、avc1、qt等。它表示“最好”基于哪种格式来解析当前的文件。举例,major_brand 是 A,compatible_brands 是 A1,当解码器同时支持 A、A1 规范时,最好使用A规范来解码当前媒体文件,如果不支持A规范,但支持A1规范,那么,可以使用A1规范来解码;
  • minor_version:提供 major_brand 的说明信息,比如版本号,不得用来判断媒体文件是否符合某个标准/规范;
  • compatible_brands:文件兼容的brand列表。比如 mp41 的兼容 brand 为 isom。通过兼容列表里的 brand 规范,可以将文件 部分(或全部)解码出来;
  • 在实际使用中,不能把 isom 做为 major_brand,而是需要使用具体的brand(比如mp41),因此,对于 isom,没有定义具体的文件扩展名、mime type。

  • 下面是常见的几种brand,以及对应的文件扩展名、mime type,更多brand可以参考 这里 。

  • MP4封装格式介绍及解析_tiankong19999的博客-CSDN博客_mp4封装

补充

关于AVC/AVC1

  • 在讨论 MP4 规范时,提到AVC,有的时候指的是“AVC文件格式”,有的时候指的是"AVC压缩标准(H.264)",这里简单做下区分。

    • AVC文件格式:基于 ISO基础文件格式 衍生的,使用的是AVC压缩标准,可以认为是MP4的扩展格式,对应的brand 通常是 avc1,在MPEG-4 PART 15 中定义。
    • AVC压缩标准(H.264):在MPEG-4 Part 10中定义。
    • ISO基础文件格式(Base Media File Format) 在 MPEG-4 Part 12 中定义。

FREE(可选的)

  • free是可选的,如果存在,则通常出现在moov与mdat之间,即moov-free-mdat。
  • free中的数据通常为全0,其作用相当于占位符,在实时拍摄视频,moov数据增多时分配给moov使用。
  • 因为设备录制视频时并不能预先知道视频数据大小,如果moov在mdat之前,随着拍摄mdat的数据会增加,moov数据也会增多,如果没有free预留的空间,则要不停的向后移动mdat数据以腾出moov空间。
  • “free”中的内容是无关紧要的,可以被忽略。该box被删除后,不会对播放产生任何影响。

moov box

  • moov box 是一个 container box 该box包含了文件媒体的元数据信息,具体内容信息由子box诠释。同File Type Box一样,该box有且只有一个,且只被包含在文件层。一般情况下,“moov”会紧随“ftyp”出现。
  • 可以看到这个demo 中有 mvhd、trak、udta 三种 box 一般情况下 “moov”中会包含1个“mvhd”和若干个“trak”。其中“mvhd”为header box,一般作为“moov”的第一个子box出现。“trak”包含了一条音、视频轨/流/track的相关信息,也是一个container box。
  • 该box是解析MP4文件里面最重要的一个box,它包含了音视频数据的编码格式、音视频数据样本,chunks的大小、存储位置也即偏移offset、时间戳单位、DTS,CTS(PTS),解码时间、显示时间等等…
  • moov box中记录的每帧音视频数据位置信息,实际上都在mdat box中,通过解析moov box来获取到每帧音视频数据具体位置后,使得播放器能方便的拖拉进度条。

mvhd box (Movie Header Box)

  • mvhd 描述了与具体音频或视频流无关的文件整体信息,其中的duration/timescale的值即为单位为秒的媒体时长。
  • 创建时间、修改时间、时间度量标尺、可播放时长等信息

字段 字节数 意义
box size 4 box大小
box type 4 box类型
version 1 box版本,0或1,一般为0。(以下字节数均按version=0)
flags 3
creation time 4 创建时间(相对于UTC时间1904-01-01零点的秒数)
modification time 4 修改时间
time scale 4 文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数
duration 4 该 track的时间长度,用duration和time scale值可以计算track时长,比如audio track的time scale = 8000, duration = 560128,时长为70.016,video track的time scale = 600, duration = 42000,时长为70
rate 4 推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,该值为1.0(0x00010000)表示正常前向播放
volume 2 与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量
reserved 10 保留位
matrix 36 视频变换矩阵,一般忽略不计
pre-defined 24
next track id 4 下一个track使用的id号

补充

  • timescale:一秒包含的时间单位(整数)。举个例子,如果timescale等于1000,那么,一秒包含1000个时间单位(后面track等的时间,都要用这个来换算,比如track的duration为10,000,那么,track的实际时长为10,000/1000=10s);
  • next_track_ID:32位整数,非0,一般可以忽略不计。当要添加一个新的track到这个影片时,可以使用的track id,必须比当前已经使用的track id要大。也就是说,添加新的track时,需要遍历所有track,确认可用的track id;

trak box (Track Box)

  • trak也是一个container box,其子box包含了该track的媒体数据引用和描述。一个MP4文件中的媒体可以包含多个track,且至少有一个track,这些track之间彼此独立,有自己的时间和空间信息。“trak”必须包含一个“tkhd”和一个“mdia”,此外还有很多可选的box(略)
  • track表示一些sample集合,对于媒体数据来说,track表示一个视频或者音频序列
  • 一系列子box描述了每个媒体轨道的具体信息
  • hint track并不包含媒体数据,而是包含将一些其他数据track打包成流媒体的指示信息
  • sample对于非hint track来说,video sample 表示视频帧,或者一组连续视频帧,audio sample即为一段连续的压缩音频,统称为sample,对于hint track,sample定义了一个或者多个流媒体的格式
  • sample table指明sample的时序和物理布局的表
  • chunk 一个track的几个sample组成的单元
  • MP4文件中 媒体内容在moov的box中,一个moov包含多个track,每个track就是一个随时间变化的媒体序列,track里每个时间单位是一个sample,sample是按照时间顺序排列。注意,一帧音频可以分解为多个音频sample,所以音频一般用sample作为单位,而不用帧

tkhd(track header box)

  • tkhd 描述的该track的,如果是视频会有宽、高信息、 还有文件创建时间、修改时间等。

字段 字节数 意义
box size 4 box大小
box type 4 box类型
version 1 box版本,0或1,一般为0。(以下字节数均按version=0)
flags 3 按位或操作结果值,预定义如下:0x000001 track_enabled,否则该track不被播放;0x000002 track_in_movie,表示该track在播放中被引用;0x000004 track_in_preview,表示该track在预览时被引用。一般该值为7,如果一个媒体所有track均未设置track_in_movie和track_in_preview,将被理解为所有track均设置了这两项;对于hint track,该值为0
creation time 4 创建时间(相对于UTC时间1904-01-01零点的秒数)
modification time 4 修改时间
track id 4 id号,不能重复且不能为0
reserved 4 保留位
duration 4 track的时间长度;当前track的完整时长(需要除以timescale得到具体秒数)
reserved 8 保留位
layer 2 视频层,默认为0,值小的在上层;视频轨道的叠加顺序,数字越小越靠近观看者,比如1比2靠上,0比1靠上
alternate group 2 track分组信息,默认为0表示该track未与其他track有群组关系;当前track的分组ID,alternate_group值相同的track在同一个分组里面。同个分组里的track,同一时间只能有一个track处于播放状态。当alternate_group为0时,表示当前track没有跟其他track处于同个分组。一个分组里面,也可以只有一个track
volume 2 [8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0
reserved 2 保留位
matrix 36 视频变换矩阵
width 4
height 4 高,均为 [16.16] 格式值,与sample描述中的实际画面大小比值,用于播放时的展示宽高

补充

  • flags:按位或操作获得,默认值是7(0x000001 | 0x000002 | 0x000004),表示这个track是启用的、用于播放的 且 用于预览的。

    • Track_enabled:值为0x000001,表示这个track是启用的,当值为0x000000,表示这个track没有启用;
    • Track_in_movie:值为0x000002,表示当前track在播放时会用到;
    • Track_in_preview:值为0x000004,表示当前track用于预览模式;

mdia (Track Media Structure)

  • mdia box 描述了这条音视频轨/流(trak)的媒体数据样本的主要信息,对播放器来说是一个很重要的box
  • “mdia”也是个container box,其子box的结构和种类还是比较复杂的。先来看一个“mdia”的实例结构树图。

  • 总 体来说,“mdia”定义了track媒体类型以及sample数据,描述sample信息。一般“mdia”包含一个“mdhd”,一个“hdlr”和 一个“minf”,其中“mdhd”为media header box,“hdlr”为handler reference box,“minf”为media information box。下面依次看一下这几个box的结构。

mdhd (Media Header Box)

  • 当前音/视频轨/流(trak)的总体信息, 该box中有duration字段和timescale字段,duration/timescale的值即为当前流的时长。
  • hdlr box用来指定该流的类型

字段 字节数 意义
box size 4 box大小
box type 4 box类型
version 1 box版本,0或1,一般为0。(以下字节数均按version=0)
flags 3
creation time 4 创建时间(相对于UTC时间1904-01-01零点的秒数)
modification time 4 修改时间
time scale 4 同前表
duration 4 track的时间长度
language 2 媒体语言码。最高位为0,后面15位为3个字符(见ISO 639-2/T标准中定义)
pre-defined 2

Handler Reference Box(hdlr)

  • “hdlr”解释了媒体的播放过程信息,该box也可以被包含在meta box(meta)中。“hdlr”结构如下表。
字段 字节数 意义
box size 4 box大小
box type 4 box类型
version 1 box版本,0或1,一般为0。(以下字节数均按version=0)
flags 3
pre-defined 4
handler type 4 在media box中,该值为4个字符:“vide”— video track“soun”— audio track“hint”— hint track
reserved 12
name 不定 track type name,以‘\0’结尾的字符串
  • handler_type的取值包括:

    • vide(0x76 69 64 65),video track;
    • soun(0x73 6f 75 6e),audio track;
    • hint(0x68 69 6e 74),hint track;
  • name为utf8字符串,对handler进行描述,比如 L-SMASH Video Handler(参考 这里)。
  • “hdlr”的字节实例如下图,各字段已经用颜色区分开:

  • stsd box的子box用于保存该流的编码类型

  • avcC box指定了该流的编码类型为H264,储了解码所需的SPS、PPS信息。
  • stsc stsz stco三个box用于保存每帧视频或音频数据在文件中的保存位置。
  • stts stss ctts三个box用于保存媒体数据和时间戳的对应关系。
  • 在同级的stbl的样本表box里面可以查到对应的样本 描述信息(stsd),时序信息(stts),样本的大小信息(stsz),样本到chunk的映射信息(stsc),chunk的位置信息(stco)等等

Media Information Box(minf)

  • “minf” 存储了解释track媒体数据的handler-specific信息,media handler用这些信息将媒体时间映射到媒体数据并进行处理。“minf”中的信息格式和内容与媒体类型以及解释媒体数据的media handler密切相关,其他media handler不知道如何解释这些信息。“minf”是一个container box,其实际内容由子box说明。
  • 一 般情况下,“minf”包含一个header box,一个“dinf”和一个“stbl”,其中,header box根据track type(即media handler type)分为“vmhd”、“smhd”、“hmhd”和“nmhd”,“dinf”为data information box,“stbl”为sample table box。下面分别介绍。
  • 下图为“minf”部分字节实例,其中红色为box header,蓝色为“smhd”,绿色为“dinf”,黄色为一部分“stbl”。

Media Information Header Box(vmhd、smhd、hmhd、nmhd)

  • Video Media Header Box(vmhd)
字段 字节数 意义
box size 4 box大小
box type 4 box类型
version 1 box版本,0或1,一般为0。(以下字节数均按version=0)
flags 3
graphics mode 4 视频合成模式,为0时拷贝原始图像,否则与opcolor进行合成
opcolor 2×3 {red,green,blue}
  • Sound Media Header Box(smhd)
字段 字节数 意义
box size 4 box大小
box type 4 box类型
version 1 box版本,0或1,一般为0。(以下字节数均按version=0)
flags 3
balance 2 立体声平衡,[8.8] 格式值,一般为0,-1.0表示全部左声道,1.0表示全部右声道
reserved 2
  • Hint Media Header Box(hmhd)  略
  • Null Media Header Box(nmhd)  非视音频媒体使用该box,略

Data Information Box(dinf)

  • “dinf”解释如何定位媒体信息,是一个container box。“dinf”一般包含一个“dref”,即data reference box;“dref”下会包含若干个“url”或“urn”,这些box组成一个表,用来定位track数据。简单的说,track可以被分成若干段,每 一段都可以根据“url”或“urn”指向的地址来获取数据,sample描述中会用这些片段的序号将这些片段组成一个完整的track。一般情况下,当 数据被完全包含在文件中时,“url”或“urn”中的定位字符串是空的。
  • “dref”的字节结构如下表。
字段 字节数 意义
box size 4 box大小
box type 4 box类型
version 1 box版本,0或1,一般为0。(以下字节数均按version=0)
flags 3
entry count 4 “url”或“urn”表的元素个数
“url”或“urn”列表 不定
  • “url”或“urn”都是box,“url”的内容为字符串(location string),“urn”的内容为一对字符串(name string and location string)。当“url”或“urn”的box flag为1时,字符串均为空。
  • 下 面是一个“dinf”的字节实例图。其中黄色为“dinf”的box header,由红色部分我们知道包含的“url”或“urn”个数为1,红色后面为“url”box的内容。紫色为“url”的box header(根据box type我们知道是个“url”),绿色为box flag,值为1,说明“url”中的字符串为空,表示track数据已包含在文件中。

Sample Table Box(stbl)

  • “stbl”几乎是普通的MP4文件中最复杂的一个box了,首先需要回忆一下sample的概念。sample是媒体数据存储的单位,存储在media的chunk中,chunk和sample的长度均可互不相同,如下图所示。

  • “stbl” 包含了关于track中sample所有时间和位置的信息,以及sample的编解码等信息。利用这个表,可以解释sample的时序、类型、大小以及在各自存储容器中的位置。“stbl”是一个container box,其子box包括:sample description box(stsd)、time to sample box(stts)、sample size box(stsz或stz2)、sample to chunk box(stsc)、chunk offset box(stco或co64)、composition time to sample box(ctts)、sync sample box(stss)等。
  • “stsd”必不可少,且至少包含一个条目,该box包含了data reference box进行sample数据检索的信息。没有“stsd”就无法计算media sample的存储位置。“stsd”包含了编码的信息,其存储的信息随媒体类型不同而不同。

Sample Description Box(stsd)

  • 给出视频、音频的编码、宽高、音量等信息,以及每个sample中包含多少个frame
  • 存储了编码类型和初始化解码器需要的信息。有与特定的track-type相关的信息,相同的track-type也会存在不同信息的情况如使用不一样的编码标准。
  • 结构如下:

  • box header和version字段后会有一个entry count字段,根据entry的个数,每个entry会有type信息,如“vide”、“sund”等,根据type不同sample description会提供不同的信息,例如对于video track,会有“VisualSampleEntry”类型信息,对于audio track会有“AudioSampleEntry”类型信息。
  • 视频的编码类型、宽高、长度,音频的声道、采样等信息都会出现在这个box中。

Time To Sample Box(stts)

  • 结构如下:

  • “stts” 存储了sample的duration,描述了sample时序的映射方法,我们通过它可以找到任何时间的sample。“stts”可以包含一个压缩的 表来映射时间和sample序号,用其他的表来提供每个sample的长度和指针。表中每个条目提供了在同一个时间偏移量里面连续的sample序号,以 及samples的偏移量。递增这些偏移量,就可以建立一个完整的time to sample表。

Sample Size Box(stsz)

  • 每个sample的size(单位是字节)   ,根据 sample_size 字段,可以知道当前track包含了多少个sample(或帧)。
  • 结构如下:

  • “stsz” 定义了每个sample的大小,包含了媒体中全部sample的数目和一张给出每个sample大小的表。这个box相对来说体积是比较大的。
  • 有两种不同的box类型,stsz、stz2。

stsz:

  • sample_size:默认的sample大小(单位是byte),通常为0。如果sample_size不为0,那么,所有的sample都是同样的大小。如果sample_size为0,那么,sample的大小可能不一样。
  • sample_count:当前track里面的sample数目。如果 sample_size==0,那么,sample_count 等于下面entry的条目;
  • entry_size:单个sample的大小(如果sample_size==0的话)

stz2:

  • field_size:entry表中,每个entry_size占据的位数(bit),可选的值为4、8、16。4比较特殊,当field_size等于4时,一个字节上包含两个entry,高4位为entry[i],低4位为entry[i+1];
  • sample_count:等于下面entry的条目;
  • entry_size:sample的大小。

Sample To Chunk Box(stsc)

  • 结构如下:

  • 用chunk组织sample可以方便优化数据获取,一个thunk包含一个或多个sample。“stsc”中用一个表描述了sample与chunk的映射关系,查看这张表就可以找到包含指定sample的thunk,从而找到这个sample。

Sync Sample Box(stss)

  • 结构如下:

  • “stss” 确定media中的关键帧。对于压缩媒体数据,关键帧是一系列压缩序列的开始帧,其解压缩时不依赖以前的帧,而后续帧的解压缩将依赖于这个关键帧。 “stss”可以非常紧凑的标记媒体内的随机存取点,它包含一个sample序号表,表内的每一项严格按照sample的序号排列,说明了媒体中的哪一个 sample是关键帧。如果此表不存在,说明每一个sample都是一个关键帧,是一个随机存取点。

Chunk Offset Box(stco)

  • thunk在文件中的偏移
  • 结构如下:

  • “stco” 定义了每个thunk在媒体流中的位置。位置有两种可能,32位的和64位的,后者对非常大的电影很有用。在一个表中只会有一种可能,这个位置是在整个文 件中的,而不是在任何box中的,这样做就可以直接在文件中找到媒体数据,而不用解释box。需要注意的是一旦前面的box有了任何改变,这张表都要重新 建立,因为位置信息已经改变了。
  • 针对小文件、大文件,有两种不同的box类型,分别是stco、co64,它们的结构是一样的,只是字段长度不同。
  • chunk_offset 指的是在文件本身中的 offset,而不是某个box内部的偏移。
  • 在构建mp4文件的时候,需要特别注意 moov 所处的位置,它对于chunk_offset 的值是有影响的。有一些MP4文件的 moov 在文件末尾,为了优化首帧速度,需要将 moov 移到文件前面,此时,需要对 chunk_offset 进行改写。

PTS和DTS的计算

I P B 帧的概念

  • 在音视频中,为了提高压缩效率,会将每帧画面压缩为不同类型的视频帧数据。
  • I帧表示关键帧,包含有一帧画面的完整信息,解码时只需要本帧数据就可以解码出完整的一帧画面。
  • P帧表示前向参考帧,它保存了本帧与上一帧的差异信息,它不能单独解码,需要根据上一帧的画面加上本帧保存的差值来获取本帧的完整画面。
  • B帧为双向参考帧,它解码时需要依赖它之前和之后的帧来获取最终的画面
  • 因为B帧需要依赖它后面的帧来进行解码,所以它的解码顺序就必然和显示顺序不能保持一致,这时就需要解码时间戳(DTS)和显示时间戳(PTS)来共同决定一帧视频数据何时解码,然后何时显示了。
  • 举个例子
  • 一小段视频帧序列如下 :
    • type : I — B — B — P — B — B — P
    • PTS : 0.33 0.67 1.00 1.33 1.67 2.00 2.33
    • DTS : 0.00 0.67 1.00 0.33 1.67 2.00 1.33
    • PTS >= DTS
  • 根据mp4 stts和ctts 可以得到DTS和PTS

stts(Decoding Time to Sample Box)

  • stts 可以计算出每个sample的dts,其中sample_delta为该sample的dts相对于上一个smaple的差值,
  • stts包含了DTS到sample number的映射表,主要用来推导每个帧(sample)的时长。
  • 那么此样本数据的dts为 :   0   1000 2000 3000 4000 ···
  • entry_count:stts 中包含的entry条目数;
  • sample_count:单个entry中,具有相同时长(duration 或 sample_delta)的连续sample的个数。
  • sample_delta:sample的时长(以timescale为计量)

ctts(Composition Time to Sample Box)

  • Composition Time 构成时间目前我直接理解的PTS。。
  • ctts 有每个sample的构成时间(Composition Time)和解码时间(DTS)之间的差值(CTTS)即图中的composition_offset。
  • 如果不存在ctts,则代表该流不存在B帧,那么PTS就直接等于DTS。
  • 帧解码到渲染的时间差值,通常用在B帧的场景,对于存在B帧的视频来说,ctts就需要存在了。当PTS、DTS不相等时,就需要ctts了,公式为 CT(n) = DT(n) + CTTS(n) 。
  • 对于只有I帧、P帧的视频来说,解码顺序、渲染顺序是一致的,此时,ctts没必要存在。

timescale

  • 最后就是关于单位,你可以看到图中样本的单位都是以1000为单位浮动,实际上真实DTS和PTS时间是需要除以mdia/mdhd中的timescale。这里是30000。
  • 有了这些,我们就可以在ctts里面计算出pts了 :
 else if (box_type_equa(uint32_to_str(bh.type, sbuffer), "ctts")) {uint32_t version = 0;read_net_bytes_to_host_uint32(&box[8], &version);if(version != 0) {LOG_E("ctts unsupport version :%d ", version)return;}uint32_t entry_cnt = 0;read_net_bytes_to_host_uint32(&box[12], &entry_cnt);char buf[128] = {0};tree_childs_insert_with_val(tree, "version", uint32_to_ascii(version, buf));tree_childs_insert_with_val(tree, "entry_cnt", uint32_to_ascii(entry_cnt, buf));uint32_t i = 0, j = 0, num = 0, pos = 16;for (i = 0; i < entry_cnt; i++) {uint32_t sample_cnt;read_net_bytes_to_host_uint32(&box[pos], &sample_cnt);pos += 4;uint32_t sample_offset;read_net_bytes_to_host_uint32(&box[pos], &sample_offset);pos += 4;for (j = 0; j < sample_cnt; j++) {PushBack_Array(pts_array, At_Array(dts_array, num++) + sample_offset);float dt, pt = 0.0;printf("dts : %9.3f ms | pts : %9.3f ms | \n", At_Array(dts_array, num - 1) / (mdhd_time_scale * 1.0), At_Array(pts_array, num - 1) / (mdhd_time_scale * 1.0));}

stss (Sync Sample Box)

  • stss 里面存放了关键帧的序号(I帧),跳转时,需要从关键帧开始解码,否则会花屏。
  • 哪些sample是关键帧
  • mp4文件中,关键帧所在的sample序号。如果没有stss的话,所有的sample中都是关键帧。
  • entry_count:entry的条目数,可以认为是关键帧的数目;
  • sample_number:关键帧对应的sample的序号;(从1开始计算)


stsz (Sample Size Boxes):

  • 顾名思义,样本大小.

stsc (Sample To Chunk Box):

  • 媒体数据的样本是被打包进chunks(块)的,chunks和样本(samples)的大小不固定,该box用于说明chunks关联样本的信息。
  • 每个thunk中包含几个sample
  • entry_count:有多少个表项(每个表项,包含first_chunk、samples_per_chunk、sample_description_index信息);
    • first_chunk 该入口第一个chunks的索引(index).
    • samples_per_chunk 样本数量/chunks.
    • sample_description_index:指向 stsd 中 sample description 的索引值(参考stsd小节);
  • sample 以 chunk 为单位分成多个组。chunk的size可以是不同的,chunk里面的sample的size也可以是不同的

前面描述比较抽象,这里看个例子,这里表示的是:

  • 序号1~15的chunk,每个chunk包含15个sample;
  • 序号16的chunk,包含30个sample;
  • 序号17以及之后的chunk,每个chunk包含28个sample;
  • 以上所有chunk中的sample,对应的sample description的索引都是1;
first_chunk samples_per_chunk sample_description_index
1 15 1
16 30 1
17 28 1

stco (Chunk Offset Box)

  • 描述每个chunks相对文件的偏移量。
  • 如图 第一个chunks即前10个样本(此例), samples.1起始地址为 423257, samples.1的地址则为 423257 + 140798 = 564055, 依此类推…
  • 有了这些即可计算出音视频的时间和空间信息了


mdat box

  • Meida Data Box 媒体数据box 位于顶层,定义是一个字节数组,用来存储媒体数据。该box数量可以为0个,也可以有多个(当媒体数据全部为外部文件引用时),数据直接跟在box type字段后面,具体数据结构的意义需要参考metadata(主要在sample table中描述)。
  • 实际媒体数据。我们最终解码播放的数据都在这里面
  • 该box包含于文件层,可以有多个,也可以没有(当媒体数据全部为外部文件引用时),用来存储媒体数据。数据直接跟在box type字段后面,具体数据结构的意义需要参考metadata(主要在sample table中描述)。

mehd(Movie Extends Header Box)

  • mehd是可选的,用来声明影片的完整时长(fragment_duration)。如果不存在,则需要遍历所有的fragment,来获得完整的时长。对于fmp4的场景,fragment_duration一般没办法提前预知。

trex(Track Extends Box)

  • 用来给 fMP4 的 sample 设置各种默认值,比如时长、大小等
  • 字段含义如下:

    • track_id:对应的 track 的 ID,比如video track、audio track 的ID;
    • default_sample_description_index:sample description 的默认 index(指向stsd);
    • default_sample_duration:sample 默认时长,一般为0;
    • default_sample_size:sample 默认大小,一般为0;
    • default_sample_flags:sample 的默认flag,一般为0;
    • 老版本规范里,前6位都是保留位,新版规范里,只有前4位是保留位。is_leading 含义不是很直观,下一小节会专门讲解下。
    • reserved:4 bits,保留位;
    • is_leading:2 bits,是否 leading sample,可能的取值包括:
      • 0:当前 sample 不确定是否 leading sample;(一般设为这个值)
      • 1:当前 sample 是 leading sample,并依赖于 referenced I frame 前面的 sample,因此无法被解码;
      • 2:当前 sample 不是 leading sample;
      • 3:当前 sample 是 leading sample,不依赖于 referenced I frame 前面的 sample,因此可以被解码;
    • sample_depends_on:2 bits,是否依赖其他sample,可能的取值包括:
      • 0:不清楚是否依赖其他sample;
      • 1:依赖其他sample(不是I帧);
      • 2:不依赖其他sample(I帧);
      • 3:保留值;
    • sample_is_depended_on:2 bits,是否被其他sample依赖,可能的取值包括:
      • 0:不清楚是否有其他sample依赖当前sample;
      • 1:其他sample可能依赖当前sample;
      • 2:其他sample不依赖当前sample;
      • 3:保留值;
    • sample_has_redundancy:2 bits,是否有冗余编码,可能的取值包括:
      • 0:不清楚是否存在冗余编码;
      • 1:存在冗余编码;
      • 2:不存在冗余编码;
      • 3:保留值;
    • sample_padding_value:3 bits,填充值;
    • sample_is_non_sync_sample:1 bits,不是关键帧;
    • sample_degradation_priority:16 bits,降级处理的优先级(一般针对如流传过程中出现的问题);

is_leading

  • 为方便讲解,下面的 leading frame 对应 leading sample,referenced frame 对应 referenced samle。
  • 以 H264编码 为例,H264 中存在 I帧、P帧、B帧。由于 B帧 的存在,视频帧的 解码顺序、渲染顺序 可能不一致。
  • mp4文件的特点之一,就是支持随机位置播放。比如,在视频网站上,可以拖动进度条快进。
  • 很多时候,进度条定位的那个时刻,对应的不一定是 I帧。为了能够顺利播放,需要往前查找最近的一个 I帧,如果可能的话,从最近的 I帧 开始解码播放(也就是说,不一定能从前面最近的I帧播放)。
  • 将上面描述的此刻定位到的帧,称作 leading frame。leading frame 前面最近的一个 I 帧,叫做 referenced frame。
  • 回顾下 is_leading 为 1 或 3 的情况,同样都是 leading frame,什么时候可以解码(decodable),什么时候不能解码(not decodable)?
  • 我没看懂

1、is_leading 为 1 的例子: 如下所示,帧2(leading frame) 解码依赖 帧1、帧3(referenced frame)。在视频流里,从 帧2 往前查找,最近的 I帧 是 帧3。哪怕已经解码了 帧3,帧2 也解不出来。

2、is_leading 为 3 的例子: 如下所示,此时,帧2(leading frame)可以解码出来。

moof

  • moof是个container box,相关 metadata 在内嵌box里,比如 mfhd、 tfhd、trun 等。

mfhd(Movie Fragment Header Box)

  • 结构比较简单,sequence_number 为 movie fragment 的序列号。根据 movie fragment 产生的顺序,从1开始递增。

traf(Track Fragment Box)

  • 对 fmp4 来说,数据被氛围多个 movie fragment。一个 movie fragment 可包含多个track fragment(每个 track 包含0或多个 track fragment)。
  • 每个 track fragment 中,可以包含多个该 track 的 sample。 每个 track fragment 中,包含多个 track run,每个 track run 代表一组连续的 sample。

tfhd(Track Fragment Header Box)

  • tfhd 用来设置 track fragment 中 的 sample 的 metadata 的默认值。
  • sample_description_index、default_sample_duration、default_sample_size 没什么好讲的,这里只讲解下 tf_flags、base_data_offset。
  • 首先是 tf_flags,不同 flag 的值如下(同样是求按位求或) :
    • 0x000001 base‐data‐offset‐present:存在 base_data_offset 字段,表示 数据位置 相对于整个文件的 基础偏移量。
    • 0x000002 sample‐description‐index‐present:存在 sample_description_index 字段;
    • 0x000008 default‐sample‐duration‐present:存在 default_sample_duration 字段;
    • 0x000010 default‐sample‐size‐present:存在 default_sample_size 字段;
    • 0x000020 default‐sample‐flags‐present:存在 default_sample_flags 字段;
    • 0x010000 duration‐is‐empty:表示当前时间段不存在sample,default_sample_duration 如果存在则为0 ,;
    • 0x020000 default‐base‐is‐moof:如果 base‐data‐offset‐present 为1,则忽略这个flag。如果 base‐data‐offset‐present 为0,则当前 track fragment 的 base_data_offset 是从 moof 的第一个字节开始计算;
    • sample 位置计算公式为 base_data_offset + data_offset,其中,data_offset 每个 sample 单独定义。如果未显式提供 base_data_offset,则 sample 的位置的通常是基于 moof 的相对位置。
    • 举个例子,比如 tf_flags 等于 57,表示 存在 base_data_offset、default_sample_duration、default_sample_flags。

  • base_data_offset 为 1263 (ftyp、moov 的size 之和为 1263)。

trun(Track Fragment Run Box)

  • 前面听过,track run 表示一组连续的 sample,其中:

    • sample_count:sample 的数目;
    • data_offset:数据部分的偏移量;
    • first_sample_flags:可选,针对当前 track run中 第一个 sample 的设置;
  • tr_flags 如下,大同小异:
    • 0x000001 data‐offset‐present:存在 data_offset 字段;
    • 0x000004 first‐sample‐flags‐present:存在 first_sample_flags 字段,这个字段的值,只会覆盖第一个 sample 的flag设置;当 first_sample_flags 存在时,sample_flags 则不存在;
    • 0x000100 sample‐duration‐present:每个 sample 都有自己的 sample_duration,否则使用默认值;
    • 0x000200 sample‐size‐present:每个 sample 都有自己的 sample_size,否则使用默认值;
    • 0x000400 sample‐flags‐present:每个 sample 都有自己的 sample_flags,否则使用默认值;
    • 0x000800 sample‐composition‐time‐offsets‐present:每个 sample 都有自己的 sample_composition_time_offset;
    • 0x000004 first‐sample‐flags‐present,覆盖第一个sample的设置,这样就可以把一组sample中的第一个帧设置为关键帧,其他的设置为非关键帧;
  • 举例如下,tr_flags 为 2565。此时,存在 data_offset 、first_sample_flags、sample_size、sample_composition_time_offset。

补充

  • moofbox,这个box是视频分片的描述信息。并不是MP4文件必须的部分,但在我们常见的可在线播放的MP4格式文件中(例如Silverlight Smooth Streaming中的ismv文件)确是重中之重
  • mfra box,一般在文件末尾,媒体的索引文件,可通过查询直接定位所需时间点的媒体数据。
    • 附:Smooth Streaming中ismv文件结构,文件分为了多个Fragments,每个Fragment中包含moof和mdat。这样的结构符合渐进式播放需求。(mdat及其描述信息逐步传输,收齐一个Fragment便可播放其中的mdat)。
  • mp4和fmp4的区别
  • fMP4 跟普通 mp4 基本文件结构是一样的。普通mp4用于点播场景,fmp4通常用于直播场景。
    • 它们有以下差别:

      • 普通mp4的时长、内容通常是固定的。fMP4 时长、内容通常不固定,可以边生成边播放;
      • 普通mp4完整的metadata都在moov里,需要加载完moov box后,才能对mdat中的媒体数据进行解码渲染;
      • fMP4中,媒体数据的metadata在moof box中,moof 跟 mdat (通常)结对出现。moof 中包含了sample duration、sample size等信息,因此,fMP4可以边生成边播放;
    • 怎么判断mp4文件是普通mp4,还是fMP4呢?一般可以看下是否存在存在mvex(Movie Extends Box)。
      • 当存在mvex时,表示当前文件是fmp4(非严谨)。此时,sample相关的metadata不在moov里,需要通过解析moof box来获得。
  • sample:
    • video sample 即为一帧或者一组连续的视频帧
    • audio sample 即为一段连续的音频
    • sample table 指明sample时序和物理布局的表

MP4文件格式的相关内容相关推荐

  1. 【音视频】MP4文件格式解析

    MP4文件格式解析 一.目的 二.MP4结构一览 2.2 MP4结构参考图 2.2 MP4结构参考表 三. MP4格式解析 & 实例分析 3.1 box 3.2 ftyp (File Type ...

  2. MOV及MP4文件格式中几个重要的Table

    MP4,全称是MPEG4 Part 14,是一种使用MPEG-4的多媒体文件格式,扩展名为.mp4. MOV,是QuickTime影片格式,它是Apple公司开发的一种音频.视频文件格式,用于存储常用 ...

  3. mp4文件格式解析(一)

    原文地址:mp4文件格式解析(一)作者:可下人间 目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的升级版),即MPEG-2 AAC标准.随后MP4概念被转移到视频上,对应的是MPE ...

  4. 第七季1:MP4文件格式解析

    以下内容源于朱有鹏课程,如有侵权,请告知删除. 本季内容 (1)将编解码得到的视频打包成mp4格式并存储到TF卡 MP4的组织形式和box解析 移植和使用mp4v2开源库来打包MP4 进一步研究MP4 ...

  5. MP4 | MP4文件格式的解析

    参考资料: 1.MP4文件格式的解析,以及MP4文件的切割算法 2.mp4文件解析(纯c解析代码) 3.MP4文件格式详解--元数据moov(一)mvhd box 4.音视频解封装:MP4核心Box详 ...

  6. 【音视频知识】MP4文件格式解析-详解

    目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的升级版),即MPEG-2 AAC标准.随后MP4概念被转移到视频上,对应的是MPEG-4标准.而现在我们流行的叫法,多半是指能播放M ...

  7. MMAction2 学习笔记 (一)——骨骼动作识别模型相关内容

    MMAction2 学习笔记 (一)--骨骼动作识别模型相关内容 0- 写在前面 好久不用CSDN发东西了,近期研究可以说有进展却又没什么进展,达到方向切换到了动作识别,目前正在实习,具体的内容方向是 ...

  8. [转]MP4文件格式的解析及分割算法

    目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的升级版),即MPEG-2 AAC标准.随后MP4概念被转移到视频上,对应的是MPEG-4标准.而现在我们流行的叫法,多半是指能播放M ...

  9. MP4文件格式详解——文件类型ftyp

    原谅地址:http://blog.csdn.net/pirateleo/article/details/7583321 文件类型ftyp(ISO-14496-12) Author:Pirate Leo ...

  10. MP4文件格式详解——文件类型ftyp(转)

    文件类型ftyp(ISO-14496-12) Author:Pirate Leo Email:codeevoship@gmail.com ISO 14496 - 12 定义了一种封装媒体数据的基础文件 ...

最新文章

  1. Git 同一个Git HostName 配置多个sshkey
  2. 配置vbox fedora虚拟机的VboxGuestAdditions
  3. uImage和zImage的区别
  4. 域控制器与客户机之:域账号不能登录问题排查
  5. 一对一,一对多,多对多查询 (注解写法)
  6. vmware虚拟机安装 安卓Android x86
  7. 【elasticsearch】 Elasticsearch集群规模和容量规划的底层逻辑
  8. 【报告分享】2019互联网大会大佬演讲实录 (附11个演讲文档下载链接)
  9. 1)关于配置centos的网络问题
  10. 持续集成商 Travis CI 爆严重漏洞,数千开源项目机密或被盗
  11. 对比罗小平先生的《delphi精要》和李维先生的《inside VCL》
  12. Ubuntu21.04安装网易有道词典
  13. CentOS网络问题汇总
  14. 初学knockoutjs记录5——Computed observables依赖监控(2 Writable computed observables可写计算监控属性)...
  15. paip.手机时间设置不能修改灰色禁用 解决大法
  16. 为酒店设计一套计算机网络管理系统,酒店管理系统设计方案(9页)-原创力文档...
  17. (附源码)计算机毕业设计ssm房屋中介管理信息系统
  18. 【Project】基于LD3320 的智能语音控制系统
  19. HDU-1869 六度分离
  20. 教你怎么免费升级宝塔企业版和专业版

热门文章

  1. Springboot整合telemetry gPRC
  2. snap telemetry-Intel 网络遥测框架简介
  3. 【Lintcode】1132. Valid Triangle Number
  4. cython安装ubuntu_cython简单使用方法
  5. 微信外部链接无法使用浏览器打开 微信链接打不开的解决方案
  6. vue开发企业微信应用-使用微信开发者工具
  7. matlab PTB 学习笔记02——开启PTB设置
  8. app毕业设计开题报告基于Uniapp实现的美食餐厅订单点餐APP
  9. 论文阅读(Multimodal Dialog Systems via Capturing Context-aware Dependencies of Semantic Elements)
  10. 李白打酒递归java_李白打酒----递归理解