MP4(二)-解复用器
MP4的一些基本的信息在上一篇博文已经介绍,转载的别人的博文,不过写的很好。这里指将几个遇到的问题,碰到新问题希望大家一起交流。
1:MP4的box官方文档给了70多个,如果都解析了估计会写哭了,所以,解复用器中要得到几个box:
moov,mdia,minf,stbl,stsd,stts,stco,stss,stsz,stsc,mdat,等等几个先关的box.
2:chunk和sample的关系,一个chunk中有一个或多个sample,一个文件有多个chunk,在stco中标记了chunk在
文件中的绝对位置。不是相对于某一个box.stsz标记了每一个sample的大小,stsc则是chunk和sample的对应关系。
这里有个问题就是Stsc中有个 参数是first_chunk,这个是什么意思呢?
First chunk Samples per chunk Sample description ID
1 4 1
4 3 1
5 4 1
8 3 1
可以看出chunk1、chunk2、chunk3都有4个sample,chunk4有3个sample,chunk5、chunk6、chunk7有4个sample……
就是这个意思。
3:stsd这个box,很重要里面存放了音视频的信息,声道,采样率,样本,宽高,等等信息。通过这个box里面有个box,
名称:“avcC",这个box里面存放了H264的sps,pps等信息.
4:如果音频是aac的则从mdat中取出来的数据既不是latm的也不是adts的,如果想转成adts的则需要加一个7字节的头,
每一帧都要加,这个头根据的填写根据,帧长度,声道,采样率有个下标:
//ADTS 头中相对有用的信息 采样率、声道数、帧长度
//adts头
//typedef struct
//{
// unsigned int syncword; //12 bslbf 同步字The bit string ‘1111 1111 1111’,说明一个ADTS帧的开始
// unsigned int id; //1 bslbf MPEG 标示符, 设置为1
// unsigned int layer; //2 uimsbf Indicates which layer is used. Set to ‘00’
// unsigned int protection_absent; //1 bslbf 表示是否误码校验
// unsigned int profile; //2 uimsbf 表示使用哪个级别的AAC,如01 Low Complexity(LC)--- AACLC
// unsigned int sf_index; //4 uimsbf 表示使用的采样率下标
// unsigned int private_bit; //1 bslbf
// unsigned int channel_configuration; //3 uimsbf 表示声道数
// unsigned int original; //1 bslbf
// unsigned int home; //1 bslbf
//
// unsigned int copyright_identification_bit; //1 bslbf
// unsigned int copyright_identification_start; //1 bslbf
// unsigned int aac_frame_length; // 13 bslbf 一个ADTS帧的长度包括ADTS头和raw data block
// unsigned int adts_buffer_fullness; //11 bslbf 0x7FF 说明是码率可变的码流
//
//
// unsigned int no_raw_data_blocks_in_frame; //2 uimsfb
//} ADTS_HEADER;
//•0: 96000 Hz
//•1: 88200 Hz
//•2: 64000 Hz
//•3: 48000 Hz
//•4: 44100 Hz
//•5: 32000 Hz
//•6: 24000 Hz
//•7: 22050 Hz
//•8: 16000 Hz
//•9: 12000 Hz
//•10: 11025 Hz
//•11: 8000 Hz
//•12: 7350 Hz
//•13: Reserved
//•14: Reserved
//•15: frequency is written explictly
//•0: Defined in AOT Specifc Config
//•1: 1 channel: front-center
//•2: 2 channels: front-left, front-right
//•3: 3 channels: front-center, front-left, front-right
//•4: 4 channels: front-center, front-left, front-right, back-center
//•5: 5 channels: front-center, front-left, front-right, back-left, back-right
//•6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
//•7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-
channel
//•8-15: Reserved
5:如果视频是H264的,从mdat中取出来的数据是4个字节的长度加上帧数据,需要转换的是将四个字节的长度转换为
00 00 00 01 ,如果遇到一帧数据是I帧则需要将sps,pps填写到前面。关键帧信息在stssbox中存储,有些I帧前面是个SEI
帧,也就是说取出来的是两帧数据,则需要将这两帧分开,记住前缀 00 00 00 01 的问题。
6:关于本程序是将文件中的box放到内存中做的处理,如果文件过大会出现分配内存失败的问题,所以应用到项目中时根据
需要分析所需要的box.
7:这里暂时没做多个mdat_box的判断,一个文件中有可能有多个mdatbox,本程序未做判断,未找到类似的文件。这样会产生
一个问题就是文件定位数据帧的时候定位会有问题。
8:本文参考官方文档:ISO_IEC_14496-12_2005(E)这个是文件中各个box的结构体信息
ISO_IEC_14496-14_2003-11-15这个文档是 ”avcC"box的结构体
相关的文档信息下载地址:http://download.csdn.net/detail/zhuweigangzwg/5441775
9:本文参考了一些网络中文章,写的都很好,分享给大家:
http://www.cnblogs.com/haibindev/archive/2011/10/17/2214518.html
http://wmnmtm.blog.163.com/blog/static/382457142011629523934/
http://blog.csdn.net/wangxiaowanghui/article/details/8538574
http://blog.csdn.net/lius1984/article/details/4464688
http://www.rosoo.net/a/201109/15013.html
http://blog.csdn.net/linzhiji/article/details/5630464
http://www.cnblogs.com/skyseraph/archive/2012/04/01/2429384.html
注:本程序的demo地址:http://download.csdn.net/detail/zhuweigangzwg/5441809
交流请加QQ:379969650
改进:
1:demux.cpp,548行的eles代码替
else
{
printf("temporary_typestr : \"%s\" , m_box->size : %d\n",temporary_typestr,m_box->size);
if (!is_found_mdat_box)
{
m_in_mdat_box_place += m_box->size;
}
}
2:stsd_box.cpp, 189行更改为:
stsdvide_pos -= 5;
//stsdvide->depth =
// stsdvide_buf[stsdvide_pos] << 8 |
// stsdvide_buf[stsdvide_pos +1];
//stsdvide_pos +=2;
//stsdvide->pre_defined_2 =
// stsdvide_buf[stsdvide_pos] << 8 |
// stsdvide_buf[stsdvide_pos +1];
//stsdvide_pos +=2;