[时间:2016-06] [状态:Open]

学习多媒体容器格式的目的

主要是为了回答以下问题:

  1. 该容器中数据是如何组织的?
  2. 该容器包含哪些编码格式的数据?这些数据是如何存储的?
  3. 该容器包含哪些元数据信息?包含哪些节目信息?
  4. 对于支持多节目的容器格式,如何找到对应的音频流、视频流、字幕流?
  5. 如何确定该容器的节目播放时长?
  6. 如何从该容器中提取音频、视频、字幕数据,并交给解码器解码,有时间戳否?
  7. 该容器是否支持seek?有哪些辅助信息?
  8. 是否支持直接流化?
  9. 哪里可以找到该容器格式最标准的文档资料?
  10. 有哪些可用的工具,方便分析容器格式异常或者错误?

1. MP4文件内部结构

MP4文件是有多个box嵌套构成的,所有数据都必须保存在box中,而且必须包含一个File Type box。

box的定义

其基本存储结构box(或者atom),其定义如下:

==========
BoxHeader
----------
BoxData
==========

其中BoxHeader定义如下:

Field name Type Size(bits)
box size uint32 32
box type uint32 32
largesize uint64 0/64
usertype uint8[16] 0/128

其中box size为1时,表示largesize域存在,size为0时,表示该box持续到文件结尾;box长度是64位无符号整数。当box type是"uuid"时,usertype域存在,表示自定义的box。

在解析时,可以忽略所有无法识别的box。

还有一种FullBox,作为Box的扩展,仅在header中添加了以下两个字段:

Field name Type Size(bits)
boxHeader - -
version uint8 8
flag uint24 24

在解析时可以忽略所有无法识别的version。

MP4顶部视图

MP4文件的整体结构如下:

表1 MP4 file structure
ftyp
pdin
moov
-
-
-
-
moof
-
-
-
mfra
-
-
mdat
free
skip
-
meta
-
-
-
-
-
-
-
-
-
-
-
meco
-
styp
sidx
ssix
prft

Box是可以相互嵌套的。上面表格中加黑的box类型是比较常见的,需要重点关注下。这个表中也仅给出了box的第二层嵌套关系。更详细的建议参考标准文档的6.2节。

从表1中可以看出movie数据是存储在mdat box中,但是如何解析这个box需要参考moov box。

接下来的部分也主要是与moov box解析有关。

2. Movie Structure('moov' box)

Movie Box在mp4文件中有且仅有一个。

Movie Header Box

Movie Header Box包含在Movie Structure Box中,通常包含媒体无关的信息,比如说播放时长、创建时间等。它是FullBox("mvhd")

其结构定义如下:

Field name Type Size(bits)
FullBoxHeader - -
creation time uint32/uint64 32/64
modify time uint32/uint64 32/64
timescale uint32 32
duration uint32/uint64 32/64
rate uint32 32
volume uint16 16
reserved uint8 80
matrix uint32[9] 9*32
pre_defined uint32[6] 6*32
next_track_ID uint32 32

对于version为1时,上面表格中选择数据类型为uint64,对于version为0时,选择类型为uint32。

这里解释下,timescale表示单位时间内的精度,即1秒内经过的时间单位计数;举个例子,正常的时间系统里以毫秒为单位,timescale就是1000。

duration中记录的是最长的track的播放长度。rate是16.16的格式,表示优先选择的播放速度,比如ox00010000表示1.0的播放速度。volume是浮点数的8.8的格式,表示优先选择的播放音量,0x0100表示1.0的音量大小。next_track_ID主要用于添加新的track,通常会大约当前文件最大track-ID。

Track Structure('trak' box)

一个mp4文件至少包含一个media trak box,不同的Track box是相互独立的。每个track box都携带独立的时域空域信息,同时包含相关的media box。track box有两种:media track和hint track,前者用于保存media相关信息,后者包含用于流媒体的打包信息。

track box包含的sub-box如下:

'trak' box
tkhd
tref
trgr
edts
---
meta
mdia
---
---
---
---
---

.1 track header box('tkhd')

这里边有一个字段,track_ID,用于唯一的表示当前track。

另一个字段,duration,用于记录当前track的播放长度。

.2 track media box('mdia')

track media box包含用于声明当前track信息的所有对象。以下sub-box需要关注:

  • handler box('hdlr')

    可获取track类型信息,主要是有字段handler_type(uint32_t)区分,具体含义如下:

    • 'vide' Video track
    • 'soun' Audio track
    • 'hint' Hint track

.3 media infomation box ('minf')

先看看media infomation box的构成,如下表:

minf
vmhd
smhd
hmhd
sthd
nmhd
dinf
---
stbl
---
---
---
---
---
---
---
---
---
---
---
---
---
---
---
---
---
---
---

'minf' box中的header box是根据'hdlr' box中媒体类型一致的,只能出现一个。

.4 Sample Tables('stbl')

可以说stbl box是mp4中最复杂,包含媒体信息最多的box。主要包含时间和media samples的数据映射表,使用这部分数据可以按照时间检索sample的位置、类型、大小、实际偏移位置。

  • sample description box ('stsd')

    主要描述当前track有关的编码信息,以及用于初始化解码的附加信息。
  • Time to Sample box('stts' 'ctts')

    比较常见的'stts' box,decoding time to sample,通过这个box可以实现时间到sample number的映射。
  • sync sample box('stss')

    这个box提供了可以用于同步的sample索引号,并严格按照sample number递增顺序排列。如果不存在这个box,表示所有sample都是可以用于同步。对视频而言,sync sample通常指的关键帧。
  • sample size box('stsz' 'stz2')

    这个box记录每个sample的大小。'stsz' box存储格式如下:
Filed name type Size(bits)
FullBox Header --- ---
sample_size uint32 32
sample_count uint32 32
entry_size uint32[] varies

sample_size中表示sample长度,如果是0表示每个sample长度不定,会记录在entry_size中;否则每个sample长度一样,并且entry_size域不存在。

'stz2' box中的entry_size是compact的,长度由特定字段指定。

  • sample to chunk box('stsc')

    'stsc' box中记录了每个chunk中包含多少sample,其结构定义如下:
Filed name type Size(bits)
FullBox Header --- ---
entry_cout uint32 32
chunk_entry uint32[3] varies

chunk_entry包含三个字段:

first_chunk: uint32

samples_per_chunk: uint32

sample_description_index: uint32

每个entry表示从first_chunk开始的每个chunk都包含samples_per_chunk个samples,这些sample都可以用使用sample_description_index信息解码。

通过这个box,可以构建出当前track的chunk结构,及其包含的sample。

  • chunk offset box('stco' 'co64')

    这个box记录了chunk对应的offset,只是包含字段一个是32为('stco'),一个是64位('co64')。

    chunk offset box中记录都是相对文件的偏移量,可以直接通过这些信息读取。

Track Structure小结

由于'mdat' box中的多媒体数据是没有结构的,只能参考moov的trak box解析。反过头来。我们看一下针对单个track中的media信息存储应该是下面的结构:

|chunk #0| chunk#1| ... | chunk #n|

每个chunk的构成是下面的结构:

|sample #0|sample #1| ... | sample #n|

从trak box中的minf中可以看出,每个chunk的长度不定,其所包含的sample数目不同,每个sample的长度也不完全相同。

3. mp4中的节目信息有哪些? 如何获取?

每个'trak' box表示一个media,其类型记录在stsd中,对于视频,其中包括我们最关心的宽高信息、编码器,保存在VisualSampleEntry;对于音频,其中也包括采样率、声道数、编码方式等,这些信息保存在AudioSampleEntry或AudioSampleEntryV1中。

对于单节目的mp4文件,不需要选择流。从标准上来看'tkhd'中有一个字段alternate_group,估计这个是表示选择节目的一个标志。

4. 如何实现seek?

第2部分介绍moov的结构时,里面有很多信息是跟seek相关的,比如time-sample映射。那么为了实现seek到指定时间,在mp4中需要做如下工作:

  1. 使用timescale将目标时间标准化。
  2. 通过time-to-sample box找到指定track的给定时间之前的第一个sample number。
  3. 通过sync sample table查询sample number之前的第一个sync sample。
  4. 通过sample-to-chunk table查找到对应的chunk number。
  5. 通过chunk offset box查找到对应chunk在文件中的起始偏移量。
  6. 最后使用sample-to-chunk box和sample size box的信息计算出该chunk中需要读取的sample数据,即完成seek。

当然标准中还有关于edit list box的使用,这里多数情况下不涉及,所以不做额外介绍。

5. 其他问题

这里解释下上面没有涉及的问题。

该容器包含哪些元数据信息?包含哪些节目信息?

MP4中包含'meta' box,从中可以解析出需要的metadata,具体建议参考标准。

是否支持直接流化?

mp4支持流化,直接通过特定协议及hint track完成。后续会有介绍。

哪里可以找到该容器格式最标准的文档资料?

标准文档的全称是"ISO/IEC 14496-12:ISO base media file format"(c068960_ISO_IEC_14496-12_2015)。

我是从ISO.org的以下地址下载:http://www.iso.org/iso/home/store/catalogue_ics/catalogue_detail_ics.htm?csnumber=61988。

有哪些可用的工具,方便分析容器格式异常或者错误?

比较经典的工具是mp4info或者elecard streameye,但是如果对mp4熟悉了的话,直接二进制查看还是不错的。

总结

本文主要是关于mp4文件解析的介绍,是我第一次深入的了解mp4文件格式,虽然可用的测试文件不是很多,但是足够理解文件结构了。

本文内容主要作为我个人后续分析mp4文件的参考。

参考资料

  1. "ISO/IEC 14496-12:ISO base media file format"(c068960_ISO_IEC_14496-12_2015)。
  2. MP4文件格式解析
  3. http://blog.chinaunix.net/uid-20758197-id-5056943.html

多媒体文件格式之MP4的更多相关文章

  1. 多媒体文件格式(一):MP4 格式

    在互联网常见的格式中,跨平台最好的应该就属MP4文件了.因为MP4文件既可以在PC平台的Flashplayer中播放,又可以在移动平台的Android.iOS等平台中进行播放,而且使用系统默认的播放器 ...

  2. 多媒体文件格式分析 MP3文件结构及编解码流程

    多媒体文件格式分析 http://blog.csdn.net/taniya001/article/details/7962864 多媒体文件格式分析 MP3文件结构及编解码流程 http://www. ...

  3. 多媒体文件格式之FLV

    [时间:2016-07] [状态:Open] FLV是一个相对简单的多媒体格式,仅支持单节目,也就是说每个FLV只能至多一个音频.至多一个视频.FLV(Flash Video)是Adobe的一个免费开 ...

  4. 多媒体文件格式之MKV

    [时间:2016-07] [状态:Open] MKV是一种开源的多媒体封装格式,是Matroska中应用比较多的格式之一.常见的后缀格式是.mkv(视频,包括音频和字幕)..mka(纯音频)..mks ...

  5. 多媒体文件格式(二):FLV 格式

    在网络的直播与点播场景中,FLV也是一种常见的格式,FLV是Adobe发布的一种可以作为直播也可以作为点播的封装格式,其封装格式非常简单,均以FLVTAG的形式存在,并且每一个TAG都是独立存在的,接 ...

  6. 多媒体文件格式之AVI

    [时间:2016-07] [状态:Open] AVI(Audio Video Interleaved的缩写)是一种RIFF(Resource Interchange File Format的缩写)文件 ...

  7. 多媒体文件格式之RMVB

    [时间:2016-07] [状态:Open] RM/RMVB是Real公司私有的封装格式,常见的后缀形式是rm.ra.rmvb. 通常封装的都是real转悠的编码格式,比如音频中的sipro.cook ...

  8. 多媒体文件格式之ASF

    [时间:2016-06] [状态:Open] ASF,全称Advanced Systems Format,是由微软提出的开放封装格式标准.ASF是微软公司Windows Media的核心.这是一种包含 ...

  9. 多媒体文件格式(三):M3U8 格式

    一.M3U8 格式标准介绍 M3U8文件是指UTF-8编码格式的M3U文件.M3U文件是记录了一个索引纯文本文件,打开它时播放软件并不是播放它,而是根据它的索引找到对应的音视频文件的网络地址进行在线播 ...

随机推荐

  1. <转>字节码指令

    本文转自:http://www.cnblogs.com/nazhizq/p/6525263.html 在llimits.h文件中定义了指令的类型.其实就是32个字节. typedef lu_int32 ...

  2. <转>lua解释执行脚本流程

    本文转自:http://www.cnblogs.com/zxh1210603696/p/4458473.html #include "lua.hpp" #include <i ...

  3. ios持久化存储

    前言 iOS中常用的持久化存储方式有好几种: 偏好设置(NSUserDefaults) plist文件存储 归档 SQLite3 Core Data 沙盒 每个iOS应用都有自己的应用沙盒(应用沙盒就 ...

  4. 高性能Web服务之lnmp架构应用

    传统上基于进程或线程模型架构的web服务通过每进程或每线程处理并发连接请求,这势必会在网络和I/O操作时产生阻塞,其另一个必然结果则是对内存或CPU的利用率低下.生成一个新的进程/线程需要事先备好其运 ...

  5. 谈谈选用技术的原则,技术学习方法技巧,阅读代码的技巧及其它 MSF的一点心得

    谈谈技术原则,技术学习方法,代码阅读及其它(正文) 这篇文章是前一阵在水木BBS上和别人讨论中偶自己发言的摘编,是偶这几年开发过程完全经验式的总结.完全个人经验,供批判. 一.选用技术的原则 比较规范 ...

  6. bootstrap-datepicker限定可选时间范围

    此项目是 bootstrap-datetimepicker 项目 的一个分支,原项目不支持  Time 选择. 其它部分也进行了改进.增强,例如 load 过程增加了对 ISO-8601 日期格式的支 ...

  7. Oracle命令(二):Oracle数据库几种启动和关闭方式

    一.Oracle数据库几种启动方式 1.startup nomount 非安装启动,这种方式下启动可执行:重建控制文件.重建数据库,读取init.ora文件,启动instance,即启动SGA和后台进 ...

  8. [AaronYang原创] 敏捷开发-Jira 6.0.5环境搭建[1]

    我的环境 Win7 64位,MSSql2008 R2,已经安装tomcat了 拓展环境 jira  6.0.5     百度网盘下载           官网更多版本下载 安装好Java的运行环境(j ...

  9. 【转】java平台的编码问题 getByte()所用编码

    java平台的编码问题 getByte()所用编码 2013-09-30 11:31:22|  分类: java |  标签:java  编码  getbytes()  |字号 订阅     众所周知 ...

  10. Flume 相关

    在CentOS 7上安装配置Flume https://mos.meituan.com/library/41/how-to-install-flume-on-centos7/ Flume NG 学习笔 ...