MP4(二)-解復(fù)用器
MP4的一些基本的信息在上一篇博文已經(jīng)介紹,轉(zhuǎn)載的別人的博文,不過(guò)寫的很好。這里指將幾個(gè)遇到的問題,碰到新問題希望大家一起交流。
1:MP4的box官方文檔給了70多個(gè),如果都解析了估計(jì)會(huì)寫哭了,所以,解復(fù)用器中要得到幾個(gè)box:
moov,mdia,minf,stbl,stsd,stts,stco,stss,stsz,stsc,mdat,等等幾個(gè)先關(guān)的box.
2:chunk和sample的關(guān)系,一個(gè)chunk中有一個(gè)或多個(gè)sample,一個(gè)文件有多個(gè)chunk,在stco中標(biāo)記了chunk在
文件中的絕對(duì)位置。不是相對(duì)于某一個(gè)box.stsz標(biāo)記了每一個(gè)sample的大小,stsc則是chunk和sample的對(duì)應(yīng)關(guān)系。
這里有個(gè)問題就是Stsc中有個(gè) 參數(shù)是first_chunk,這個(gè)是什么意思呢?
First chunk Samples per chunk Sample description ID
1 4 1
4 3 1
5 4 1
8 3 1
可以看出chunk1、chunk2、chunk3都有4個(gè)sample,chunk4有3個(gè)sample,chunk5、chunk6、chunk7有4個(gè)sample……
就是這個(gè)意思。
3:stsd這個(gè)box,很重要里面存放了音視頻的信息,聲道,采樣率,樣本,寬高,等等信息。通過(guò)這個(gè)box里面有個(gè)box,
名稱:“avcC",這個(gè)box里面存放了H264的sps,pps等信息.
4:如果音頻是aac的則從mdat中取出來(lái)的數(shù)據(jù)既不是latm的也不是adts的,如果想轉(zhuǎn)成adts的則需要加一個(gè)7字節(jié)的頭,
每一幀都要加,這個(gè)頭根據(jù)的填寫根據(jù),幀長(zhǎng)度,聲道,采樣率有個(gè)下標(biāo):
//ADTS 頭中相對(duì)有用的信息 采樣率、聲道數(shù)、幀長(zhǎng)度
//adts頭
//typedef struct
//{
// unsigned int syncword; //12 bslbf 同步字The bit string ‘1111 1111 1111’,說(shuō)明一個(gè)ADTS幀的開始
// unsigned int id; //1 bslbf MPEG 標(biāo)示符, 設(shè)置為1
// unsigned int layer; //2 uimsbf Indicates which layer is used. Set to ‘00’
// unsigned int protection_absent; //1 bslbf 表示是否誤碼校驗(yàn)
// unsigned int profile; //2 uimsbf 表示使用哪個(gè)級(jí)別的AAC,如01 Low Complexity(LC)--- AACLC
// unsigned int sf_index; //4 uimsbf 表示使用的采樣率下標(biāo)
// 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 一個(gè)ADTS幀的長(zhǎng)度包括ADTS頭和raw data block
// unsigned int adts_buffer_fullness; //11 bslbf 0x7FF 說(shuō)明是碼率可變的碼流
//
//
// 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中取出來(lái)的數(shù)據(jù)是4個(gè)字節(jié)的長(zhǎng)度加上幀數(shù)據(jù),需要轉(zhuǎn)換的是將四個(gè)字節(jié)的長(zhǎng)度轉(zhuǎn)換為
00 00 00 01 ,如果遇到一幀數(shù)據(jù)是I幀則需要將sps,pps填寫到前面。關(guān)鍵幀信息在stssbox中存儲(chǔ),有些I幀前面是個(gè)SEI
幀,也就是說(shuō)取出來(lái)的是兩幀數(shù)據(jù),則需要將這兩幀分開,記住前綴 00 00 00 01 的問題。
6:關(guān)于本程序是將文件中的box放到內(nèi)存中做的處理,如果文件過(guò)大會(huì)出現(xiàn)分配內(nèi)存失敗的問題,所以應(yīng)用到項(xiàng)目中時(shí)根據(jù)
需要分析所需要的box.
7:這里暫時(shí)沒做多個(gè)mdat_box的判斷,一個(gè)文件中有可能有多個(gè)mdatbox,本程序未做判斷,未找到類似的文件。這樣會(huì)產(chǎn)生
一個(gè)問題就是文件定位數(shù)據(jù)幀的時(shí)候定位會(huì)有問題。
8:本文參考官方文檔:ISO_IEC_14496-12_2005(E)這個(gè)是文件中各個(gè)box的結(jié)構(gòu)體信息
ISO_IEC_14496-14_2003-11-15這個(gè)文檔是 ”avcC"box的結(jié)構(gòu)體
相關(guān)的文檔信息下載地址:http://download.csdn.net/detail/zhuweigangzwg/5441775
9:本文參考了一些網(wǎng)絡(luò)中文章,寫的都很好,分享給大家:
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./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
交流請(qǐng)加QQ:379969650
改進(jìn):
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;
|