MP4文件格式的相关内容

参考链接

  • 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 size4box大小
box type4box类型
version1box版本,0或1,一般为0。(以下字节数均按version=0)
flags3
creation time4创建时间(相对于UTC时间1904-01-01零点的秒数)
modification time4修改时间
time scale4文件媒体在1秒时间内的刻度值,可以理解为1秒长度的时间单元数
duration4该 track的时间长度,用duration和time scale值可以计算track时长,比如audio track的time scale = 8000, duration = 560128,时长为70.016,video track的time scale = 600, duration = 42000,时长为70
rate4推荐播放速率,高16位和低16位分别为小数点整数部分和小数部分,即[16.16] 格式,该值为1.0(0x00010000)表示正常前向播放
volume2与rate类似,[8.8] 格式,1.0(0x0100)表示最大音量
reserved10保留位
matrix36视频变换矩阵,一般忽略不计
pre-defined24
next track id4下一个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 size4box大小
box type4box类型
version1box版本,0或1,一般为0。(以下字节数均按version=0)
flags3按位或操作结果值,预定义如下: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 time4创建时间(相对于UTC时间1904-01-01零点的秒数)
modification time4修改时间
track id4id号,不能重复且不能为0
reserved4保留位
duration4track的时间长度;当前track的完整时长(需要除以timescale得到具体秒数)
reserved8保留位
layer2视频层,默认为0,值小的在上层;视频轨道的叠加顺序,数字越小越靠近观看者,比如1比2靠上,0比1靠上
alternate group2track分组信息,默认为0表示该track未与其他track有群组关系;当前track的分组ID,alternate_group值相同的track在同一个分组里面。同个分组里的track,同一时间只能有一个track处于播放状态。当alternate_group为0时,表示当前track没有跟其他track处于同个分组。一个分组里面,也可以只有一个track
volume2[8.8] 格式,如果为音频track,1.0(0x0100)表示最大音量;否则为0
reserved2保留位
matrix36视频变换矩阵
width4
height4高,均为 [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 size4box大小
box type4box类型
version1box版本,0或1,一般为0。(以下字节数均按version=0)
flags3
creation time4创建时间(相对于UTC时间1904-01-01零点的秒数)
modification time4修改时间
time scale4同前表
duration4track的时间长度
language2媒体语言码。最高位为0,后面15位为3个字符(见ISO 639-2/T标准中定义)
pre-defined2

 Handler Reference Box(hdlr)

  • “hdlr”解释了媒体的播放过程信息,该box也可以被包含在meta box(meta)中。“hdlr”结构如下表。
字段字节数意义
box size4box大小
box type4box类型
version1box版本,0或1,一般为0。(以下字节数均按version=0)
flags3
pre-defined4
handler type4在media box中,该值为4个字符:“vide”— video track“soun”— audio track“hint”— hint track
reserved12
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 size4box大小
box type4box类型
version1box版本,0或1,一般为0。(以下字节数均按version=0)
flags3
graphics mode4视频合成模式,为0时拷贝原始图像,否则与opcolor进行合成
opcolor2×3{red,green,blue}
  • Sound Media Header Box(smhd) 
字段字节数意义
box size4box大小
box type4box类型
version1box版本,0或1,一般为0。(以下字节数均按version=0)
flags3
balance2立体声平衡,[8.8] 格式值,一般为0,-1.0表示全部左声道,1.0表示全部右声道
reserved2
  • 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 size4box大小
box type4box类型
version1box版本,0或1,一般为0。(以下字节数均按version=0)
flags3
entry count4“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_chunksamples_per_chunksample_description_index
1151
16301
17281

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时序和物理布局的表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446025.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华三交换机如何进入配置_学校机房项目交换机的如何配置,理解这篇,交换机配置不再难...

弱电项目中&#xff0c;交换机的配置是无法避免的&#xff0c;大部分的项目都有可能会涉及到&#xff0c;尤其是机房等网络项目&#xff0c;本期我们就通过一个实际项目案例来详细了解交换机在项目中的应用配置&#xff0c;如果我们平时对交换机配置不熟&#xff0c;这个案例可…

百度地图迁徙大数据_百度地图大数据:五一高速拥堵不似预期,广深成热门迁出入地...

五一假期在即&#xff0c;你是否做好了“出行功课”&#xff1f;高速拥堵水平降低、公众出门不出城、公园成踏青赏景热门目的地……在全国疫情防控仍未松懈的时刻&#xff0c;2020年的五一或许注定与往年不同。近日&#xff0c;百度地图发布2020五一假期安全出行大数据&#xf…

音视频的基础知识 视频播放器原理/封装格式/视频音频编码数据/视频像素数据/音频采样数据

参考链接 FFMpeg视频播放器的制作-雷霄骅&#xff08;去除电流音版本&#xff09;_哔哩哔哩_bilibili 视频播放器原理 播放视频文件的流程YUV是一张屏幕中像素点的数值封装格式 MP4 RMVB TS FLV AVI将视频和音频码流按照一定的格式存储在一个文件中封装格式分析工具&#xf…

科立捷7代写频软件_天大厦大“两硕士论文雷同”通报,代写买卖论文

澎湃新闻记者 薛莎莎天津大学、厦门大学7月10日晚就“两硕士论文雷同”一事&#xff0c;分别发出调查处理通报。通报称&#xff0c;涉事两名学生存在由他人代写、买卖论文的学术作假的行为&#xff0c;均撤销其所获硕士学位&#xff0c;收回、注销硕士学位证书。澎湃新闻注意到…

FFMpeg命令行基础

参考链接 FFMpeg视频播放器的制作-雷霄骅&#xff08;去除电流音版本&#xff09;_哔哩哔哩_bilibili音视频处理 ffmpeg初级开发 命令行工具-实用命令_MY CUP OF TEA的博客-CSDN博客 介绍 FFMpeg是视频播放和转码的内核 使用 win中ffmpeg.exe用于视频转码简单命令&#xff1…

悲观锁和乐观锁_面试必备之乐观锁与悲观锁

何谓悲观锁与乐观锁乐观锁对应于生活中乐观的人总是想着事情往好的方向发展&#xff0c;悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点&#xff0c;不能不以场景而定说一种人好于另外一种人。大家可以点击加群【JAVA架构知识学习讨论群】47398464…

Microsoft Visual Studio2019环境下搭建FFmpeg开发环境

参考链接 《基于 FFmpeg SDL 的视频播放器的制作》课程的视频_雷霄骅的博客-CSDN博客_雷霄骅ffmpeg视频教程小学期课程资料 - 基于FFmpegSDL的视频播放器的制作.zip_免费高速下载|百度网盘-分享无限制辅助参考链接使用VS2019创建项目&#xff0c;添加文件和库地址_MY CUP OF …

vue process.env获取不到_从文档开始,重学vue(下)源码级别

此篇文章主要是从应用及源码层面讲解vue部分常用api,阅读起来可能略有难度,新手可以看《从文档开始,重学vue(上)》示例代码均在vue-cli3中完成Vue.extend()可以使用 extend 创建一个子类,该方法通常用于构建全局组件,如弹框组件等,下面我们就用它来制作个全局alert组件吧首先我…

Microsoft Visual Studio2019环境下搭建SDL开发环境

参考链接 《基于 FFmpeg SDL 的视频播放器的制作》课程的视频_雷霄骅的博客-CSDN博客_雷霄骅ffmpeg视频教程小学期课程资料 - 基于FFmpegSDL的视频播放器的制作.zip_免费高速下载|百度网盘-分享无限制辅助参考链接VS自动链接到Windows上随vcpkg安装的SDL2库 | 码农俱乐部 - G…

不关注公众号可以获取openid吗_微信公众号粉丝迁移

目录 [toc] 微信公众号迁移 正常的公众号迁移直接通过微信操作就可以&#xff0c;如下图。但是因为udb数据里面存的是迁移前公众号的openid以及unionid,需要自行获取新旧openid以及unionid。 旧的用户信息要在迁移之前获取&#xff0c;第三步点击同意之后就公众号的接口就调不通…

建筑专业规范大全 2020版_房屋建筑工程现行规范标准目录汇编(2020版)—建筑电气...

房屋建筑工程现行规范标准目录汇编(2020版)建筑电气规范编号规范名称GB 50034-2013建筑照明设计标准GB 50052-2009供配电系统设计规范GB 50053-201320kV及以下变电所设计规范GB 50057-2010建筑物防雷设计规范GB 50147-2010电气装置安装工程 高压电器施工及验收规范GB 50148-201…

基于Microsoft Visual Studio2019环境编写ffmpeg视频解码代码

旧代码 旧代码使用了很多过时的API&#xff0c;这些API使用后&#xff0c;vs会报编译器警告 (级别 3) C4996的错误即 函数被声明为已否决 报 C4996的错误 // test_ffmpeg.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #define SDL_MAIN_HANDLED …

16进制转double dotnet_终于把计算机进制弄明白了!

And theres one thing that I need from you我只需要你为我做一-件事Can you come through, through待在我的身边就好Through, yeah你可以抚慰一切不满And theres one thing that I need from you你可以过来Can you come through?待在我的身边吗-comethruJeremy Zucker进制进制…

FFmpeg源代码简单分析-架构图-解码

参考链接 FFmpeg源代码结构图 - 解码_雷霄骅的博客-CSDN博客_ffmpeg雷霄骅函数背景色 函数在图中以方框的形式表现出来。不同的背景色标志了该函数不同的作用&#xff1a; 粉红色背景函数&#xff1a;FFmpeg的API函数。白色背景的函数&#xff1a;FFmpeg的内部函数。黄色背景…

JUnit单元测试笔记

#01 JUnit简介 1.在项目工程中的Library,add 一个JUnit的Jar包&#xff0c;按需要添加JUnit 3 或 JUnit 4&#xff08;分为被测试类与测试类较佳&#xff09;。 2.单元测试是由程序员完成的。 3.Java 5 之前的版本只能 用JUnit 4前的版本&#xff08;因为JUnit 4用到Java 5的…

jqery获取每个月天数_三年级《年、月、日》单元重要知识点整理汇总,以及难点题型解析...

昨天给大家分享了《计算经过的时间》问题&#xff0c;今天给大家分享的是《年、月、日》单元中重要的几个知识点&#xff0c;以及难点题型解析。知识点1 感知年、月、日一、结合生活实际&#xff0c;看看下面事情需要经过多少时间。跑完100米大约需要经过十几(秒)。2.打一场篮球…

FFmpeg源代码简单分析-架构图-编码

参考链接 FFmpeg源代码结构图 - 编码_雷霄骅的博客-CSDN博客_ffmpeg 源码函数背景色 函数在图中以方框的形式表现出来。不同的背景色标志了该函数不同的作用&#xff1a; 粉红色背景函数&#xff1a;FFmpeg的API函数。白色背景的函数&#xff1a;FFmpeg的内部函数。黄色背景的…

为革命,保护视力——为Eclipse更换暗黑皮肤及编辑页面的字体颜色主题

1.在Eclipse中的菜单栏的Help -> Eclipse Market 的 Search栏中输入 Eclipse Moonrise UI Theme &#xff0c;之后自己执生啦&#xff08;确保上网配置正确&#xff09;。 2.与上面操作类似&#xff0c;输入 Eclipse Color Theme&#xff0c;选择安装。 3.选择菜单栏的Win…

FFmpeg源代码简单分析-通用- 内存的分配和释放(av_malloc()、av_free()等)

参考链接 FFmpeg源代码简单分析&#xff1a;内存的分配和释放&#xff08;av_malloc()、av_free()等&#xff09;_雷霄骅的博客-CSDN博客_av_malloc 内容介绍 内存操作的常见函数位于libavutil\mem.c中本文记录最常使用的几个函数&#xff1a; av_malloc()av_realloc()av_mal…

FFmpeg源代码简单分析-通用-结构体分析-AVFormatContext

参考链接 FFMPEG结构体分析&#xff1a;AVFormatContext_雷霄骅的博客-CSDN博客_avformatcontext AVFormatContext AVFormatContext是包含码流参数较多的结构体结构体的定义位于libavformat/avformat.h/*** Format I/O context.//格式化 I/O 上下文* New fields can be added…