MP4(二)-解復用器
MP4的一些基本的信息在上一篇博文已經(jīng)介紹,轉(zhuǎn)載的別人的博文,不過寫的很好。這里指將幾個遇到的問題,碰到新問題希望大家一起交流。
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中有個 參數(shù)是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中取出來的數(shù)據(jù)既不是latm的也不是adts的,如果想轉(zhuǎn)成adts的則需要加一個7字節(jié)的頭,
每一幀都要加,這個頭根據(jù)的填寫根據(jù),幀長度,聲道,采樣率有個下標:
//ADTS 頭中相對有用的信息 采樣率、聲道數(shù)、幀長度
//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 表示聲道數(shù)
// 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中取出來的數(shù)據(jù)是4個字節(jié)的長度加上幀數(shù)據(jù),需要轉(zhuǎn)換的是將四個字節(jié)的長度轉(zhuǎn)換為
00 00 00 01 ,如果遇到一幀數(shù)據(jù)是I幀則需要將sps,pps填寫到前面。關鍵幀信息在stssbox中存儲,有些I幀前面是個SEI
幀,也就是說取出來的是兩幀數(shù)據(jù),則需要將這兩幀分開,記住前綴 00 00 00 01 的問題。
6:關于本程序是將文件中的box放到內(nèi)存中做的處理,如果文件過大會出現(xiàn)分配內(nèi)存失敗的問題,所以應用到項目中時根據(jù)
需要分析所需要的box.
7:這里暫時沒做多個mdat_box的判斷,一個文件中有可能有多個mdatbox,本程序未做判斷,未找到類似的文件。這樣會產(chǎn)生
一個問題就是文件定位數(shù)據(jù)幀的時候定位會有問題。
8:本文參考官方文檔:ISO_IEC_14496-12_2005(E)這個是文件中各個box的結(jié)構體信息
ISO_IEC_14496-14_2003-11-15這個文檔是 ”avcC"box的結(jié)構體
相關的文檔信息下載地址:http://download.csdn.net/detail/zhuweigangzwg/5441775
9:本文參考了一些網(wǎng)絡中文章,寫的都很好,分享給大家:
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;