热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

MP4文件格式的解析,以及MP4文件的分割算法mp4应该算是一种比较复杂的媒体格式了,起源于QuickTime。以前研究的时候就花了一番的功夫ÿ

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

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

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

 

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

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

  

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

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

  

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

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

  这是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。直接上代码可能会清楚些:

  1. 首先直接分析entry

  2. 然后,通过stco或co64获知chunk总个数之后,开始还原映射表

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

     

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

  

二、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,切记!

  以下是整个的逻辑过程:

  好了,所有这些都实现之后,就具备了做mp4点播系统的条件了。不过,要做mp4点播,还有一些其他的问题需要解决,我将在下一篇文章中介绍。


推荐阅读
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • Linux磁盘的分区、格式化的观察和操作步骤
    本文介绍了如何观察Linux磁盘的分区状态,使用lsblk命令列出系统上的所有磁盘列表,并解释了列表中各个字段的含义。同时,还介绍了使用parted命令列出磁盘的分区表类型和分区信息的方法。在进行磁盘分区操作时,根据分区表类型选择使用fdisk或gdisk命令,并提供了具体的分区步骤。通过本文,读者可以了解到Linux磁盘分区和格式化的基本知识和操作步骤。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Ubuntu 9.04中安装谷歌Chromium浏览器及使用体验[图文]
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
author-avatar
mobiledu2502877091
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有