mp4格式解析、分割

MP4文件格式的解析,以及MP4文件的分割算法

  mp4应该算是一种比较复杂的媒体格式了,起源于QuickTime。之前研究的时候就花了一番的功夫,尤为是如何把它完美的融入到视频点播应用中,更是费尽了心思,主要问题是处理mp4文件庞大的“媒体头”。固然,流媒体点播也能够采用flv格式来作,flv也能够封装H.264视频数据的,不过Adobe却不推荐这么作,人家说毕竟mp4才是H.264最佳的存储格式嘛。html

  这几天整理并重构了一下mp4文件的解析 程序,融合了分解与合并的程序,之前是c语言写的,应用在linux上运行的服务器程序上,如今改为c++,方便我在其余项目中使用它,至于用不用移植一 份c#的,暂时用不到,等有必要了再说吧。这篇文章先简单介绍一下mp4文件的大致结构,以及它的分割算法,以后再写文章介绍如何把mp4完美应用在点播 项目中。linux

 

1、MP4格式分析                  c++

  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”,还有其余的以mp4为基础进行的扩展或者是缩水版本的格式,包括:M4V,  3GP, F4V等。算法

  mp4是由一个个“box”组成的,大box中存放小box,一级嵌套一级来存放媒体信息。box的基本结构是:c#

  

  其中,size指明了整个box所占用的大小,包括header部分。若是box很大(例如存放具体视频数据的mdat box),超过了uint32的最大数值,size就被设置为1,并用接下来的8位uint64来存放大小。服务器

  一个mp4文件有可能包含很是多的box,在很大程度上增长了解析的复杂性,这个网页上http://mp4ra.org/atoms.html记录了一些当前注册过的box类型。看到这么多box,若是要所有支持,一个个解析,怕是头都要爆了。还好,大部分mp4文件没有那么多的box类型,下图就是一个简化了的,常见的mp4文件结构:ui

  

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

  看吧,要获取到mp4文件的帧列表,还挺不容易的,须要一层层解析,而后综合stts stsc stsz stss stco等这几个box的信息,才能还原出帧列表,每一帧的时戳和偏移量。并且,你要照顾可能出现或者可能不出现的那些box。。。能够看的出来,mp4 把帧sample进行了分组,也就是chunk,须要间接的经过chunk来描述帧,这样作的理由是能够压缩存储空间,缩小媒体信息所占用的文件大小。这 里面,stsc box的解析相对来讲比较复杂,它用了一种巧妙的方式来讲明sample和chunk的映射关系,特别介绍一下。atom

  这是stsc box的结构,前几项的意义就不解释了,能够看到stsc box里每一个entry结构体都存有三项数据,它们的意思是:“从first_chunk这个chunk序号开始,每一个chunk都有samples_per_chunk个数的sample,并且每一个sample均可以经过sample_description_index这个索引,在stsd box中找到描述信息”。也就是说,每一个entry结构体描述的是一组chunk,它们有相同的特色,那就是每一个chunk包含samples_per_chunk个sample,好,那你要问,这组相同特色的chunk有多少个?请经过下一个entry结构体来推算,用下一个entry的first_chunk减去本次的first_chunk,就获得了这组chunk的个数。最后一个entry结构体则代表从该first_chunk到最后一个chunk,每一个chunk都有sampls_per_chunk个sample。很拗口吧,不过,就是这个意思:)。因为这种算法没法得知文件全部chunk的个数,因此你必须借助于stco或co64。直接上代码可能会清楚些:spa

  1. 首先直接分析entry

  2. 而后,经过stco或co64获知chunk总个数以后,开始还原映射表

  读出stsc以后,就能够综合stbl下的全部box,推算出视频和音频帧列表,时戳和偏移量等数据。下面截图展现获取到的关键帧列表:

     

  有了关键帧列表以后,就能够继续咱们一下个题目,就是mp4文件的分割。实现mp4的分割,是把mp4应用到点播系统中最关键的技术环节,作不到这个,就没法实现点播播放mp4影片的“拖动”。

  

2、MP4文件的分割算法

  所谓“分割”,就是把大文件切成小文件,要实现mp4的分割,

  •   首先,须要获取到关键帧列表
  •   而后,选择要分割的时间段(好比从关键帧开始)
  •   接着,从新生成moov box(注意全部相关的box 以及 box size都须要改变)
  •   最后,拷贝对应的数据,生成新文件

  第一点,上面已经介绍了,第二点,只须要遍历关键帧列表,就能找到离你想要分割的时间段最接近的关键帧,第四点就是“copy-paste”的 工做,关键在于第三点。由于这一步涉及到stbl下的全部box,必须从新生成entrys,一样的,其余的box都还好,只须要保留关键帧所对应的 sample和chunk,其他的删掉便可,只是stsc box的比较麻烦,提及来比较啰嗦,仍是直接看代码吧:

  修改完box以后,须要从新生成moov box,因为moov box的大小以及时长等信息都发生了改变,因此须要box的大小作相应的修改,这点千万不能忘记,不然播放器会解析错误。从新生成box以后,还要计算一 下分割后的数据的长度,因为数据长度也发生了改变,因此修改mdat box的大小的同时,要同时修改stbl下全部box的chunk offset,切记!

  如下是整个的逻辑过程:

相关文章
相关标签/搜索