fmp4打包H264详解

fmp4打包H264详解

1 mp4介绍

MP4(MPEG-4 Part 14)是在“ISO/IEC 14496-14”标准文件中定义的,属于MPEG-4的一部分,是“ISO/IEC 14496-12(MPEG-4 Part 12 ISO base media file format)”标准中所定义的媒体格式的一种实现,后者定义了一种通用的媒体文件结构标准。MP4是一种描述较为全面的容器格式,被认为可以在其中嵌入任何形式的数据,包含各种编码的视频、音频等,我们常见的大部分的MP4文件存放的AVC(H.264)或MPEG-4(Part 2)编码的视频和AAC编码的音频。MP4格式的官方文件后缀名是“.mp4”。

1.1 基本概念

mp4是由一个个“box”组成的,大box中存放小box,一级嵌套一级来存放媒体信息。一个mp4文件有可能包含非常多的box,在很大程度上增加了解析的复杂性,这个网页上http://mp4ra.org/atoms.html记录了一些当前注册过的box类型。看到这么多box,如果要全部支持,一个个解析,是非常困难的。还好,大部分mp4文件没有那么多的box类型,下图就是一个简化了的,常见的mp4>文件结构:

mp4文件结构

mp4流媒体文件封装和解封装,主要涉及视频文件的宽高、时长、码率、编码格式、帧列表、关键帧列表以及所对应的时戳和在文件中的位置,这些信息,在mp4中,是以特定的算法分开存放在moov box下属的几个box中的,需要解析stbl下面所有的box,来还原媒体信息。下表是对于以上几个重要的box存放信息的说明:
moov

要获取到mp4文件的帧列表,需要一层层解析,然后综合stts stsc stsz stss stco等这几个box的信息,才能还原出帧列表,每一帧的时戳和偏移量。而且,你要照顾可能出现或者可能不出现的那些box。可以看的出来,mp4把帧sample进行了分组,也就是chunk,需要间接的通过chunk来描述帧,这样做的理由是可以压缩存储空间,缩小媒体信息所占用的文件大小。
MP4文件格式中,所有的内容存在一个称为movie的容器中。一个movie可以由多个tracks 组成。每个track就是一个随时间变化的媒体序列,例如,视频帧序列。track 里的每个时间单位是一个sample,它可以是一帧视频,或者音频。sample按照时间顺序排列。注意,一帧音频可以分解成多个音频sample,所以音频一般用sample 作为单位,而不用帧。MP4 文件格式的定义里面,用sample 这个单词表示一个时间帧或者数据单元。每个track会有一个或者多个sample descriptions。track 里面的每个sample通过引用关联到一个sample description。这个sample descriptions 定义了怎样解码这个sample,例如使用的压缩算法。与其他的多媒体文件格式不同的是,MP4 文件格式经常使用几个不同的概念,理解其不同是理解这个文件格式的关键。

1.2 常见mp4封装格式

有两种比较常见的封装格式,一种是整体封装,一种是分段封装(fmp4)
第一种格式,整个mp4文件的meta数据都在文件头,所有媒体数据为一整体。当文件较大的时候,meta数据就较大。这样对mp4文件本地播放是没有问题。但对于一些视频播放网站而言,用户播放器必须下载全meta数据才能开始播放,这就意味着用户的缓冲时间将因为mp4文件的存储结构而延长。目前一种解决方法是将大的mp4文件切成物理分离的多段,使得每段的meta都比较小,从而在一定程度上减少缓冲时间。

第二种格式,mp4文件被分成多个frag分片,而原来的meta数据大大变小,且没个frag都可以单独索引、传输和播放,这样就可以解决mp4不能流式传输播放的问题。对用户体验比较好,本文主要讲述的还是分段的mp4方式,来应用于H264实时预览。

fmp4增加了一个moof box来描述视频分片信息,文件分为了多个Fragments,每个Fragment中包含moof和mdat,这样的结构符合渐进式播放要求,同时可以用来适配直播等实时预览的场景。
fmp4

2 各类型box详解

mp4由一个个box组成,box可以嵌套子box,所有的流媒体数据极其描述信息都封装到box,box中的字节序为网络字节序,也就是大端字节序(Big-Endian),封装和解封装的时候需要注意。

2.1 box构成

Box由header和body组成,其中header统一指明box的大小和类型,body根据类型有不同的意义和格式。标准的box开头的4个字节(32位)为box size,box size值包括box header和box body整个box的大小,如果数据过大超过4个字节能够表征的最大值,则可把box size = 1,则表示这个box的大小为large size,真正的size值要在largesize域上得到,如果size为0,表示该box为文件的最后一个box,文件结尾即为该box结尾,size后面紧跟的32位为box type,一般是4个字符,如“ftyp”、“moov”等,这些box type都是已经预定义好的,分别表示固定的意义,其值为类型的ASCII值,当type是uuid时,代表Box中的数据是用户自定义扩展类型。Data是Box的实际数据,可以是纯数据也可以是更多的子Boxes,其结构图如下:
box结构

FullBox是Box的扩展,在Box结构的Header中增加8bits version和24bits flags。
当一个Box的Data中是一系列子Box时,这个Box又可成为Container Box,其结构如下:

Container Box

如果我们要用代码封装box,则其封装格式如下:

[4bytes box size] [4bytes box type] [8bytes largesize, if size ==1] [contents of the box, if any]

一般的MP4文件需要有ftyp、moov、mdat,它们都是顶级box,不能被其他box嵌套,ftyp标示了MP4文件,必须出现在第一个,moov保存了媒体的基本信息,mdat保存视频和音频数据,后两个顺序不确定,但是一般会把moov放到mdat前面,以便播放器可以快速识别解码信息并播放。moov在mdat之前,可实现流式读取视频数据,适配在线播放场景。
MP4文件

fmp4主要为了适配流式播放场景,其视频流一直在播放和传输,没有终止,因此无法准确的给出媒体的整体播放长度信息,因此增加了一个moof类型的box,来描述当前传输的数据samples信息,其一般在关键帧打包时发送moov,其他帧发送时采用moof+mdat的方式进行打包和传输。
fmp4

本章节主要根据fmp4封装格式,来对各个box进行详细解释,fmp4的封包示意图如下:
在这里插入图片描述

2.2 ftyp box

ftyp(File Type) box是fmp4第一个box,用来确定文件的类型,版本及兼容的协议,每个文件有且只有一个,由于要支持流式传输,一般在客户端第一次发起请求时,发送一次带有ftypbox的数据,一般与moov合并发送给客户端,也可定时发送(通过chrome解码验证,可以多次发送此box),其格式如下:

[4字节size][4字节类型(ftyp的ASCII)][4字节major brand][4字节minor version][4字节为单位元素的数组compatible brands]

实例如下(16进制):
00 00 00 18 66 74 79 70 69 73 6F 6D 00 00 00 01 69 73 6F 6D 61 76 63 31

  • 00 00 00 18:标识整个box的大小,为24个字节
  • 66 74 79 70:标识box类型,通过ascii转换后为ftype
  • 69 73 6F 6D:标识支持的主要推荐版本,这里为isom的ASCII
  • 00 00 00 01:最低兼容版本,这里为1.0版本
  • 69 73 6F 6D 61 76 63 31:兼容版本,isom和avc1的ASCII

2.3 moov box

Movie box包含本文件中所有媒体数据的宏观描述信息以及每路媒体轨道的具体信息, fmp4格式需要紧跟在ftyp box之后,moov顶层box中没有具体信息,其信息都记录在其子box中,具体子box可参照:
moov

2.3.1 mvhd box

mvhd(Movie Header Box),为moov的子box,记录整个媒体文件的描述信息,如创建时间、修改时间、时间度量标尺、可播放时长、播放速率、音量等,由于fmp4很多信息放入moof中,这里需要注意的是时间度量,一般H264视频为90000,其格式如下:
[4字节size][4字节type][4字节版本和flags][4字节创建时间][4字节修改时间][4字节timescale][4字节deration][4字节播放速率][2字节音量][10字节预留][36字节 unity matrix][24字节pre_defined][4字节next_track_ID]

示例如下:

00 00 00 6C 6D 76 68 64 00 00 00 00 00 00 00 01 00 00 00 02 00 01 5F 90 00 01 5F 90 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF FF FF  
  • 00 00 00 6C:box大小为108
  • 6D 76 68 64:boxtype为mvhd
  • 00 00 00 00: 第一字节为版本,后面三个字节为flags,这里都赋值0
  • 00 00 00 01:从1970年开始,创建时间的秒数,fmp4可随意赋值
  • 00 00 00 02:从1970年开始,修改时间的秒数,fmp4可随意赋值
  • 00 01 5F 90:timescale,时间刻度,持续时间通过timescale计算,这里取得是90000的采样频率,持续时间计算工时为duration=(实际持续时间:单位s)/(1/timescale)=(实际持续时间:单位s)timescale,以H264帧率为25的每一个帧间隔为40ms为例,其每个sample的持续时间=0.0490000=3600
  • 00 01 5F 90:Duration持续时间,是指整个文件的持续时间,fmp4此字段没啥意义,这里可以为90000,也就是1s,赋值其他好像也没啥影响
  • 00 01 00 00:播放速率,这里赋值为0x00010000
  • 01 00:播放音量, 默认赋值0x0100
  • 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00:表示视频变换矩阵,取默认值即可
  • 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 预定义相关,这里取0
  • FF FF FF FF:下一个轨的ID,fmp4这里取最大值即可
2.3.2 trak box

moov中可以存在一个或多个 track,通常包含两个trak box,一个视频索引,一个音频索引,它们之间是相互独立的。每个 track 包含tkhd和mdia子box,trak为顶层box无具体含义,其Data为其子box

2.3.2.1 tkhd box

tkhd(Track Header) box包含关于媒体流的头信息,如trackid,视频分辨率等信息,其格式如下:
[4字节size][四字节type][4字节版本和flags][4字节创建时间][4字节修改时间][4字节trackid][4字节预留][4字节持续时间][8字节预留][2字节layer][2字节备份分组][2字节音量][2字节预留][36字节 unity matrix][4字节宽][4字节高]

示例及详解如下:

00 00 00 5C 74 6B 68 64 00 00 00 07 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 01 5F 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 07 80 00 00 04 38 00 00   
  • 00 00 00 5C:size=92
  • 74 6B 68 64: type为tkhd
  • 00 00 00 07:第一个自己为版本,赋值为0,后面三个字节为flags默认赋值为7,具体含义我没详细研究
  • 00 00 00 00:创建时间,fmp4可以随意,这里赋值为0
  • 00 00 00 00:修改时间,fmp4可以随意,这里赋值为0
  • 00 00 00 01:表示当前track的trackid,这里为一路H264流,trackid设置为1,后面4个字节预留
  • 00 01 5F 90:表示持续时间,fmp4可以随意,这里赋值为90000,后面8个字节预留
  • 00 00:视频layer,相当于前后排序,这里就一路视频,设置为0,后面2个字节预留
  • 00 00:音量设置,这里设置为0,后面2个字节预留
  • 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00:表示变换矩阵,默认值即可
  • 07 80 00 00:视频宽=0x70800000>>16=1920
  • 04 38 00 00: 视频高=0x04380000>>16=1080
2.3.2.2 mdia box

mdia box包含 track 媒体数据信息的 container box,其子box主要包含视频流长度/创建时间/媒体播放过程/sample的偏移量/解码格式等

2.3.2.2.1 mdhd box

Media Header Box,存放视频流创建时间,长度等信息,其格式如下:
[4字节size][4字节type][4字节版本和flags][4字节创建时间][4字节修改时间][4字节timescale][4字节持续时间][2字节语言][2字节pre-define]
示例及详解如下:

00 00 00 20 6D 64 68 64 00 00 00 00 00 00 00 00 00 00 00 00 00 01 5F 90 00 01 5F 90 55 C4 00 00 
  • 00 00 00 20: size=32
  • 6D 64 68 64: type= mdhd
  • 00 00 00 00: 第一个自己为版本,赋值为0,后面三个字节为flags默认0
  • 00 00 00 00:创建时间,fmp4可以随意,这里赋值为0
  • 00 00 00 00:修改时间,fmp4可以随意,这里赋值为0
  • 00 01 5F 90: timescale,时间刻度,持续时间通过timescale计算,这里取得是90000的采样频率
  • 00 01 5F 90: duration, 持续时间,fmp4可以随意,这里赋值为90000
  • 55 C4:language,支持的语言,ISO-639-2/T 语言代码
  • 00 00:默认0即可
2.3.2.2.2 hdlr box

Handler Reference Box,媒体的播放过程信息,例如video track 将由video handle box来处理,其格式如下:
[4字节size][4字节type][4字节版本和flags][4字节pre-define][4字节handler type][24字节预留][n字节处理器名称]

00 00 00 2D 68 64 6C 72 00 00 00 00 00 00 00 00 76 69 64 65 00 00 00 00 00 00 00 00 00 00 00 00 56 69 64 65 6F 48 61 6E 64 6C 65 72 00 
  • 76 69 64 65:handler type,这里值为vido,说明为video track
  • 56 69 64 65 6F 48 61 6E 64 6C 65 72 00:处理者名称,这里赋值为VideoHandler
2.3.2.2.3 minf box

Media Information Box,解释 track 媒体数据的 handler-specific 信息。minf 同样是个 container box,Media Information Box,解释 track 媒体数据的 handler-specific 信息。minf 同样是个 container box,其内部需要关注的内容是 stbl,这也是 moov 中最复杂的部分。
其他几个子box较为简单,简单介绍:

  • MOOV::TRAK::MDIA::VMHD/SMHD/HMHD/NMHD: Media Information Header Boxes。每种音轨类型都有不同的媒体信息头(对应media handler-type),其只包含版本和flags,fmp4中版本赋值为0,VMHD的flags=1,SMHD的flags=0,格式如下:
    [4字节size][4字节type][4字节版本和flags][2字节graphicsmode][2字节opcolor[3]]
    VMHD示例如下:
    00 00 00 14 76 6D 68 64 00 00 00 01 00 00 00 00 00 00 00 00

  • MOOV::TRAK::MDIA::MINF::DINF:是一个container box,Data Reference Box 其包含dref box,fmp4给默认赋值即可,是示例如下:
    00 00 00 1C 64 72 65 66 00 00 00 00 00 00 00 01 00 00 00 0C 75 72 6C 20 00 00 00 01

Sample Table Box(stbl)是mdia中最主要的部分,存放文件中每个 Sample信息.首先介绍下Sample和trunk的概念,在 MP4文件中,Sample 是一个媒体流的基本单元,例如视频流的一个 Sample 代表实际的nal数据。Chunk是数据存储的基本单位,它是一系列Sample数据的集合,一个 Chunk 中可以包含一个或多的Sample,stbl 用来描述每个Sample 的信息,对mp4来说非常重要,但是对于fmp4,其描述在moof中,这里可以大大简化,stbl消息体是子box,无其他信息

Sample Description Box(stbl-stsd),存放解码必须的描述信息,其也是一个container box,对于H264码流来说其包含avc1子box,stsd消息格式如下:
[4字节size][4字节type][4字节版本和flags][4字节entry_count][entry box]

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

stsd整体示例及详解:

00 00 00 A9 73 74 73 64 00 00 00 00 00 00 00 01 00 00 00 99 61 76 63 31 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07 80 04 38 00 48 00 00 00 48 00 00 00 00 00 00 00 01 12 62 69 6E 65 6C 70 72 6F 2E 72 75 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 FF FF 00 00 00 2F 61 76 63 43 01 4D 
00 2A FF E1 00 18 67 4D 00 2A 96 35 40 F0 04 4F CB 37 01 01 01 40 00 01 C2 00 00 57 E4 01 01 00 04 68 EE 3C 80 00 00 00 14 62 74 72 74 00 1C 9C 80 00 2D C6 C0 00 2D C6 C0
  • 00 00 00 A9: stsd box的长度为169
  • 73 74 73 64:类型是stsd
  • 00 00 00 00: version和flags都赋值为0
  • 00 00 00 01:entry count为1,说明后面跟了一个音视频描述信息,这里是H264,后面跟的是avc1

stsd-avc1 box说明H264视频封装格式为avc1,即是H.264 bitstream without start codes,不带由00000001起始码的数据,这里注意mdat box里封装的H264需要去掉起始码;此box中带有H264编码的信息,具体格式如下:
[4字节size][4字节type][6字节预留][2字节data_reference_index][2字节pre_defined][2字节预留][12字节pre_defined][2字节宽][2字节高][4字节horizresolution][四字节 vertresolution][4字节预留][2字节视频帧数量][Compression name长度][Compression name][Compression name预留位(32-Compression name长度-1)][2字节深度][2字节pre_defined][avcC box][btrt box]

  • 00 00 00 99:avc1 box size=153
  • 61 76 63 31:box类型位avc1
  • 00 01:表示data_reference_index,这里赋值为01
  • 07 80:宽为1920
  • 04 38:高为1080
  • 00 48 00 00:水平分辨率,默认值即可
  • 00 48 00 00:垂直分辨率,默认值即可
  • 00 01:帧数量,fmp4封装赋值为1
  • 12 62 69 6E 65 6C 70 72 6F 2E 72 75 00 00:第一个字节表示压缩名称长度,后面是压缩名称ASCII,这里是binelpro.ru,可以改成其他
  • 00 18: 深度,赋值为24

stsd-avc1后会跟avcC box和btrt box两个子box
stsd-avc1-avcC box主要是记录视频编码规格和编码水平、sps/pps原始数据,其格式如下:
[4字节size][4字节type][1字节版本][1字节profile][1字节compat][1字节level][1字节nalu长度头字节数][1字节sps个数][2字节sps长度][sps][1字节pps个数][2字节pps长度][pps]
示例及详解如下:

00 00 00 2F 61 76 63 43 01 4D 00 2A FF E1 00 18 67 4D 00 2A 96 35 40 F0 04 4F CB 37 01 01 01 40 00 01 C2 00 00 57 E4 01 01 00 04 68 EE 3C 80 
  • 00 00 00 2F:表示box长度为47
  • 61 76 63 43:类型为avcC
  • 01: 表示版本
  • 4D 00 2A:表示H264编码信息,profile为4D(main profile),兼容性为00,level为2A(4.2),即取值为SPS帧头后的三个字节sps[1]/sps[2]/sps[3]
  • FF:此位标识nalu去掉起始位后,前面多少位用来表示nalu长度,此字节前五位默认为1,后三位值+1表示帧size占用的字节数,我们用4个字节来存储帧大小,所以这里为3,即为0xFC|0x03=0xFF
  • E1:前3位预留,默认位1,后五位表示sps个数,我们只放了一个sps,因此为E0|01=E1
  • 00 18:sps帧长度,为24,后面24个字节为sps数据
  • 01:pps个数为1个
  • 00 04:pps长度,后面四个字节为pps

stsd-avc1-btrt bitrate box描述码率信息,其包含最大码率,平均码率等信息,其格式如下:
[4字节size][4字节type][4字节bufferSizeDB][4字节maxBitrate][4字节avgBitrate]
示例如下,不做过多解释:
00 00 00 14 62 74 72 74 00 1C 9C 80 00 2D C6 C0 00 2D C6 C0

Decoding Time to Sample Box(stbl-stts),存储了sample的duration,描述了sample时序的映射方法,我们通过它可以找到任何时间的sample,“stts”也可包含一个压缩的表来映射时间和sample序号,用其他的表来提供每个sample的长度和指针,表中每个条目提供了在同一个时间偏移量里面连续的sample序号,以及samples的偏移量。递增这些偏移量,就可以建立一个完整的time to sample表。在fmp4中这些信息以moof中为主,这里可不必赋值,只做一个box即可,示例如下:
00 00 00 10 73 74 74 73 00 00 00 00 00 00 00 00

Sample To Chunk Box(stbl-stsc),用chunk组织sample可以方便优化数据获取,一个chunk包含一个或多个sample。“stsc”中用一个表描述了sample与chunk的映射关系,查看这张表就可以找到包含指定sample的thunk,从而找到这个sample,当然每个table entry可能包含一个或者多个chunk。fmp4方式,此box不必赋值,简单封装一个box即可,示例如下:
00 00 00 10 73 74 73 63 00 00 00 00 00 00 00 00

Sample Size Boxes (stbl-stsz),指定了每个sample的size,针对fmp4这里无需赋值,示例如下:
00 00 00 14 73 74 73 7A 00 00 00 00 00 00 00 00 00 00 00 00

Chunk Offset Box(stbl-stco),Chunk的偏移量表,指定了每个chunk在文件中的位置。fmp4方式,此box不必赋值,简单封装一个box即可,示例如下:
00 00 00 10 73 74 63 6F 00 00 00 00 00 00 00 00

2.3.3 mvex box

Movie Extends Box (mvex)(fMP4专有) mvex是fMP4 的标准盒子。它的作用是告诉解码器这是一个fMP4的文件,具体的 samples信息内容不再放到 trak里面,而是在每一个 moof中

Trac kExtends Box (trex) 是 mvex 的子box,用来给fMP4的sample设置默认值。基格式如下:
[4字节size][4字节type][4字节版本和flags][4字节track_ID][4字节default_sample_description_index][4字节default_sample_duration][4字节default_sample_size][4字节default_sample_flags]

示例及详解如下:
00 00 00 20 74 72 65 78 00 00 00 00 00 00 00 01 00 00 00 01 00 00 00 00 00 00 00 00 00 01 00 01

  • 00 00 00 20: box size = 32
  • 74 72 65 78:box type=trex
  • 00:版本和flags默认为0
  • 00 00 00 01: trackid,这里设置为1
  • 00 00 00 01:默认sample描述索引,设置为1
  • 00 00 00 00:默认持续时间为0
  • 00 00 00 00:默认尺寸为0
  • 00 01 00 01:默认flags为00010001

2.4 moof box

Movie Fragment Box(moof),是 fmp4中数据追加的box,moof 和mdat是成对出现的,这个box是视频分片的描述信息,每个Fragment中包含moof和mdat,这样的结构符合渐进式播放需求。moof是一个顶级box,同时是一个容器box,下面紧跟一个mfhd,自身无内容。

2.4.1 mfhd box

Movie Fragment header Box(mfhd),包含分片序列信息,标识每个track的分片序列,其格式如下:
[4字节size][4字节type][4字节版本和flags][4字节序列号]

示例及详解如下:
00 00 00 10 6D 66 68 64 00 00 00 00 00 00 00 01

  • 00 00 00 10: box size=16
  • 6D 66 68 64: type取值mfhd的ASCII
  • 00 00 00 00: 版本和flags都赋值欸0
  • 00 00 00 01:媒体流序列号,每个trunk一个序列号,序列号从1开始递增,就是每个moof的序列号,相比前一个要加1
2.4.2 traf box

Track Fragment Box(traf), 每个分片可能包含一个或多个track分片,每个分片可能包含1个或多个连续的sample,traf主要用来描述这些信息,包含trackid,基准解码时间,sample序列,持续时间、数据偏移等信息,traf也是容器box,包含多个子box,本身无内容

2.4.2.1 tfhd Box

Track Fragment Header box(tfhd),对制定的track进行相关的默认配置,包含trackid、sample时长、大小、偏移量等信息,其格式如下:
[4字节size][4字节type][4字节版本和flags][4字节trackid][8字节Base data offset][4字节Sample description index][4字节Default sample duration][4字节Default sample size][4字节Default sample flags]

示例及详解:
00 00 00 10 74 66 68 64 00 02 00 00 00 00 00 01

  • 00 00 00 10: size=16
  • 74 66 68 64: type为tfhd的ASCII
  • 00 02 00 00:版本为0 ,flags赋值为0x020000
  • 00 00 00 01: trackid赋值为1,视频track
    其他字段可选,这里默认不包含
2.4.2.2 tfdt box

Track Fragment Base Media Decode Time Box(tfdt), 主要是用来存放相关sample编码的绝对时间的,因为FMP4是流式的格式,所以不像MP4一样可以直接根据sample直接seek到具体位置。这里就需要一个标准时间参考,来快速定位都某个具体的fragment。其格式如下:
[4字节size][4字节type][4字节版本和flags][4字节Base media decode time]

示例及详解:
00 00 00 10 74 66 64 74 00 00 00 00 00 00 00 00

  • 00 00 00 10: box size = 16
  • 74 66 64 74: type取值tfdt
  • 00 00 00 00: 版本和flags都赋值为0
  • 00 00 00 00:基准解码时间,从0开始,主要计算每个分片的时间偏移,所以其等于前一个基准时间+前一个分片所有sample持续时间的总和,第一个分片的基准时间为0,例如每个分片包含一个sample,每个sample持续时间为3600,那么第一个分片的基准解码时间为0.第二个分片为0+3600=3600,第三个分片等于3600+3600=7200,如此类推。
2.4.2.3 trun box

Track Fragment Run Box(trun),记录moof中有关sample的相关信息,如每个sample的size,duration,offset等信息,其格式如下:
[4字节size][4字节type][4字节版本和flags][4字节sample count][4字节data offset][sample count个16字节的sample描述信息]

sample描述信息格式如下:
[4字节持续时间][4字节sample size][4字节sample flags][4字节cts]

示例及详解:

00 00 00 24 74 72 75 6E 00 00 0F 01 00 00 00 01 00 00 00 79 00 00 0E 10 00 03 6B FB 02 00 00 00 00 00 00 00
  • 00 00 00 24: box size = 36
  • 74 72 75 6E: type取值trun的ASCII
  • 00 00 0F 01:flags取值00000f01, 表示每个sample都是用字节的参数
  • 00 00 00 01:表示sample数量,示例每一帧为一个sample,每个分片只包含一个sample,也就是一个H264
  • 00 00 00 79:表示和moof配套的mdat中实际数据位置聚类moof开头有多少偏移,其等于整个moof的长度+mdat的头长度
  • 00 00 0E 10:表示第一个sample的持续时间duration=3600
  • 00 03 6B FB:表示sample对应的数据帧的实际大小size=224251
  • 02 00 00 00: 表示sample-flags,其四位定义如下:
(sample.IsLeading << 2) | sample.DependsOn,
(sample.IsDependedOn << 6) | (sample.HasRedundancy << 4) | (0x00 << 1) | sample.IsNonSync,
sample.DegradPrio & 0xF0 << 8,
sample.DegradPrio & 0x0F, 

sample flags的含义可参照https://blog.csdn.net/CHYabc123456hh/article/details/125100494,这里以单个分片单个sample的模式,只要碰到关键帧,DependsOn=2 ,其他等于0,非关键帧DependsOn=1,IsNonSync等于1,其他等于0

  • 00 00 00 00: cts一般取值为0
2.4.2.4 sdtp box

Independent and Disposable Samples Box(sdtp),主要是用来描述具体某个 sample 是否是 I 帧,是否是 leading frame 等相关属性值,主要用来作为当进行点播回放时的同步参考信息,这里简单赋值即可,其格式如下:
[4字节size][4字节type][4字节预留][sample count个1字节flags]
其flags的1字节表示方式:(sample.DependsOn << 4) | (sample.IsDependedOn << 2) | (sample.HasRedundancy)
示例如下:
00 00 00 0D 73 64 74 70 00 00 00 00 20

2.5 mdat box

Media Data Box(mdat), 该box包含媒体数据, 对于h264,aac编码的媒体来说,其视频mdat中内容是nalu,对于音频来说,其内容为aac的一帧。mdat中的帧依次存放,每个帧的位置、时间、长度都由moov中的信息指定,本文实例以H264为例,每个mdat包含一帧或多帧H264,采用avc1封装格式,即是去掉起始头后,在帧前面加上4字节帧size,其格式如下:
[4字节box size][4字节type][4字节数据包size][流媒体数据包]
此box很简单,不做过多解释,只需要注意,如果采用avc1封装格式,请去掉H264起始头,在前面加上四个字节的帧大小size

至此有关H264打包为fmp4的内容已经写完,可参照ffmpeg相关源码进行对照阅读。
有关fmp4示例文件及分析工具mp4reader安装包获取,请关注微信公众号壹零仓,发送fmp4,获取
参考资料:
音视频学习之fmp4

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您可以使用一些开源的Javascript库来将H.264编码的视频转换为FMP4格式。其中一个常用的库是mux.js。 首先,您需要在您的页面中引入mux.js库。您可以通过以下方式将其添加到您的HTML文件中: ```html <script src="https://unpkg.com/[email protected]/dist/mux.min.js"></script> ``` 接下来,您可以使用以下代码将H.264视频转换为FMP4格式: ```javascript // 创建MSE对象 const videoElement = document.querySelector('video'); const mediaSource = new MediaSource(); videoElement.src = URL.createObjectURL(mediaSource); mediaSource.addEventListener('sourceopen', async () => { const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"'); // 加载H.264视频数据 const response = await fetch('path/to/h264/video'); const videoData = await response.arrayBuffer(); // 转换为FMP4格式 const fmp4Data = muxjs.mp4.tools.h264ToMp4(videoData); // 将转换后的数据添加到SourceBuffer中 sourceBuffer.appendBuffer(fmp4Data); }); ``` 上述代码首先创建了一个`MediaSource`对象,并将其与`video`元素关联起来。然后,在`sourceopen`事件中,我们创建了一个`SourceBuffer`对象,并指定了H.264编码的视频类型。接下来,我们使用`fetch`函数加载H.264视频数据,并使用`mux.js`库中的`h264ToMp4`函数将其转换为FMP4格式。最后,我们将转换后的数据追加到`SourceBuffer`中。 请注意,上述代码仅演示了如何使用`mux.js`库将H.264视频转换为FMP4格式。您可能需要根据您的实际需求进行适当的调整和修改。 希望这可以帮助到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

壹零仓

感谢您的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值