Asterisk播放mp4(5)——MP4文件解析

Asterisk 现有版本不支持播放视频文件(支持视频通话),无法满足发送视频通知、视频 IVR 等场景。本系列文章,通过学习音视频的相关知识和工具,尝试实现一个通过 Asterisk 播放 mp4 视频文件的应用。

本文关注在MP4文件中,h264aac的媒体数据是如何存放的,又如何进行访问?为后续解析文件后,通过RTP进行发送进行准备。

MP4文件格式

MP4文件封装格式,对应的标准为ISO/IEC 14496-12,即:信息技术视听对象编码的第12部分:ISO 基本媒体文件格式(Information technology Coding of audio-visual objects Part 12: ISO base media file format)。MP4文件可以嵌入任何形式的数据,不过通常存放的是AVC(H.264)编码的视频和AAC/MPEG-4(Part 2)编码的音频。

MP4文件由许多box组成,box可以嵌套。box分为headerdata两部分。header包括size(4字节),type(4字节)和largesize(8字节,可选)。其中,size指明了整个box的大小,包括header部分。如果box很大(例如存放具体视频数据的mdat box),超过了uint32的最大数值,size就被设置为1,并用接下来的8位uint64来存放大小。box中的字节序为网络字节序,也就是大端字节序(Big-Endian),就是一个32位的4字节整数存储方式为高位字节在内存的低端。

下面看看几个主要的box

box类型 层级 名称 说明
ftyp 1 File Type Box 有且只有1个,只能被包含在文件层,而不能被其他 box 包含。该 box 应该被放在文件的最开始,指示该 MP4 文件应用的相关信息。
moov 1 Movie Box 有且只有1个,只能被包含在文件层。moov是一个container box,包含若干子box,例如:mvhd,trak等,子box中存放媒体的元数据(metadata)信息。
mvhd 2 Movie Header Box 描述了媒体一些基本信息,例如:timescale,duration等。
trak 2 Track Box trak也是一个container box,其子box包含了该track的媒体数据引用和描述(hint track除外)。一个MP4文件中的媒体可以包含1个或多个track,它们之间彼此独立,有自己的时间和空间信息。trak至少包含tkhd和mdia这两个box,此外还有很多可选的box。其中tkhdtrack header boxmdiamedia box,该box是一个包含一些track媒体数据信息box的container box。
mdat 1 Media Data 实际媒体数据,最终解码播放的音视频数据都在这里面。对于h264aac编码的媒体来说,其视频mdat中内容是nal,对于音频来说,其内容为aac的一帧。mdat中的帧依次存放,每个帧的位置、时间、长度都由moov中的信息指定。
mp4 box

trak是mp4中最复杂的部分,包含了读取媒体数据所需的各种信息。要理解trak下的box首先要掌握几个基本概念,包括:track,sample,trunk。

  • track:表示sample的集合,对于媒体数据来说,track表示一个视频或音频序列。

  • sample:video sample即为一帧视频,或一组连续视频帧,audio sample即为一段连续的压缩音频。

  • chunk:一个track中的几个sample组成的单元。

trak下有很多box,最重要也是最复杂的是trak/mdia/minf/stbl,它下面又包含了多个boxsample table指明sampe时序和存储地址的表。利用这个表,可以解析sample的时序、类型、大小以及在文件中的位置。下面对这些box做个简单的说明:

box类型 名称 说明
stsd Sample Description Box 包含h264编码的spspps。可以有一个到多个sample description
stsc Sample To Chunk Box 指定了chunksample的对应关系。从first_chunk这个chunk序号开始,每个chunk都有samples_per_chunksample,每个sample都可以通过sample_description_index这个索引,在stsd中找到描述信息。
stsz Sample Size Box 指定了每个sample的大小。
stco Sample Size Box 指定了每个chunk的在整个文件中的起始地址。
stss Sync Sample Box 关键帧。
stts DecodingTime to Sample 用于计算sampledts,其中sample_counts定义连续多少个sample的dts具有相同的差值,sample_deltadts的差值。
ctts Composition Time to Sample 每个sample的构成时间(Composition Time)和解码时间(DT)之间的差值。如果不存在ctts,则代表该流不存在B帧,那么CT就直接等于DT。
帧顺序及时间

上图是ISO/IEC 14496-12规范中给出的示例。第2行代表了视频帧的存储序列,帧后面的编号代表了显示顺序。视频流编码时,如果支持B帧,P帧会先于B帧编码,因此帧编码顺序(存储顺序)和帧播放顺序不一致。通过这个图我们就更容理解上面两个和时间相关的box的含义。stts定义的是表格中的第3行,DT,用于计算出每个sampledtsctts对应的是表格中的第6行,Composition offset,用于计算出每个samplepts(Compostion Time)

DTS(Decode Time Stamp):标识读入内存中的视频帧什么时候开始送入解码器中进行解码。PTS(Presentation Time Stamp):用于度量解码后的视频帧什么时候被显示出来 。这两个值对应的并不是秒,毫秒这些时间单位,而是时间刻度,它们的值除以mdhd中的timescale(每秒钟有多少个时间刻度)转换为时间。

制作样本

为了控制篇幅我们忽略音频流,只分析视频流。

ffmpeg -t 10 -lavfi sine -t 10 -lavfi color=red sine-red-10s.mp4

FFmpeg命令行输出 sine-red-10s.mp4
vi %!xxd sine-red-10s.mp4

mdat中存放的就是媒体数据,视频就是h264NALU,我们可以将mp4中的数据和h264裸流中的数据进行对比。

ffmpeg -t 10 -lavfi color=red red-default.h264

我们直接生成h264的裸流,其中I/P/B帧的数据和生成mp4文件中的h264流的数量是一致的。

FFmpeg命令行输出 red.h264

通过ffmpeg生成mp4文件时有很多参数可以指定,faststart是比较常用的一个,其作用是将moov挪到mdat前面,这样就可以实现边下载边播放。

ffmpeg -t 10 -lavfi sine -t 10 -lavfi color=red -movflags faststart sine-red-10s-faststart.mp4

FFmpeg输出 sine-red-10s-faststart.mp4
sine-red-10s-faststart.mp4

mp4文件的结构太复杂了,直接看二进制数据很费劲,下面我们通过一个在线工具解析mp4数据。

ftyp
video - mdhd

后面计算时序时要用到timescaleduration这两个参数,duration / timescale = 10秒。

video - stsd

stsd/avc1/avcC中可以获得h264spspps。另外,需要特别注意lengthSizeMinusOne这个参数,其含义是用几个字节表示nalu的长度,实际的长度是值加1,这里就是3+1=4h264裸流中,分割nalu通常采用的是Annex B这种用起始码的方式(用3字节或4字节的起始码),但是在MP4中使用的是AVCC方式(填加字节指定nalu的大小)。

video - stsz

stsc中指明track共有250个采样,以及每个采样的大小。这里需要注意两点:1、采样的大小是NALU的实际大小加4,因为前面有4字节记录用来记录尺寸;2、采样不一定是一个NALU,实际上第一个采样(759)就包括了SEIIDR两个NALU

video - stsc

stsc中定义了chunksample的对应关系,以及sample的描述信息(stsd)。这里第一个chunk包含了两个sample,后面每个chunk包含一个sample

video -stco

stco中定义了chunk在文件中的地址。通过stszstscstco就可以在文件中获得任意一个sample9792是第一个chunk的偏移量,第一个chunk包含2个采样,前2个采样的大小分别为75917,可以计算出下一个chunk的偏移量是10568,它不等于下一个视频chunk的偏移量10991,通过查看音频的stco,可知音频流的第一个chunk的偏移量是10568,这说明视频和音频的chunk是交错存储的。

video - stts

stts中记录了每个sample间相差的时间刻度512。前面的timescale的值为12800,512/12800=0.04秒,说明每帧之间的解码时间间隔为0.04秒。

video - ctts

ctts提供的是composition timedecoding time的差值,它们的和就是composition time

通过解析red.h264文件的slice可以知道每帧的大小和类型,这样方便我们理解decode time

解析red.h264文件的nalu
1 视频帧 I P B B B P B B B
2 DT(stts) 0 512 1024 1536 2048 2560 3072 3584 4096
3 Composition offset(ctts) 1024 2560 1024 0 512 2560 1024 0 512
4 CT 1024 3072 2048 1536 2560 5120 4096 3584 4608
5 seq 1 5 3 2 4 9 7 6 8
6 size 65 13 10 10 10 19 12 10 10

上表中的第1行(DT)代表的是文件中视频帧的存储顺序,第4行(CT)代表的是视频帧的播放时间(单位是时间刻度),第5行(seq)代表的是视频帧的播放顺序。可以看到存储顺序和播放顺序是不一致的,这是因为视频帧中包含B帧,它是双向依赖帧,解析是可能要依赖P(或B帧),所以虽然B帧的播放顺序靠前,但是解码的时候必须要先解码P帧,才能解码B帧。另外,在avcc中一个sample的前4个字节代表这个包的大小,因此stsz中记录的采样大小比NALU的大小多4。

通过对比h264裸流和mp4中的视频数据,我们可以得到一致的结果,就是说mp4中的sttsctts记录h264的解析结果,方便了数据的直接访问。

参考

QuickTime container 有box类型的定义

MP4文件格式解析

在线MP4解析工具

ISO/IEC 14496-12:2015 下载地址

FFmpeg formats - mov, mp4, ismv

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269