Android系統(tǒng)WMA文件播放功能的設(shè)計(jì)與實(shí)現(xiàn)
WMA文件開(kāi)始有一個(gè)16 Byte的標(biāo)識(shí),表示是WMA:30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 62 CE 6C。如果音頻文件的前16個(gè)字符和這16 Byte相符,那么就可以判斷該文件為WMA文件。WMAExtraetor中的SniffWMA函數(shù)就是通過(guò)讀取文件前16 Byte來(lái)判斷該文件是不是WMA文件。在SniffWMA函數(shù)中,如果判斷前16 Byte和WMA的16個(gè)標(biāo)識(shí)字節(jié)相等,就會(huì)把MEDIA_MIMETYPE_AUDIO_WMA給mimeType指針,標(biāo)志著該音頻文件類(lèi)型為WMA格式。MEDIA_MIMETYPE_AUDIO_WMA是在MediaDefs.h文件中定義,在MediaDefs.cpp文件中賦值:
(2)WMA文件的解析。
WMAExtmetor從WMA文件的第31 Byte開(kāi)始取16 Byte,然后依次和file_header、stream_header、data_header、comment_header、exten-ded_content_header對(duì)比,如果和file_header相等,則從下個(gè)Byte開(kāi)始依次獲取文件大小、創(chuàng)建時(shí)間、數(shù)據(jù)包個(gè)數(shù)、…數(shù)據(jù)包大小。然后再?gòu)南聜€(gè)Byte開(kāi)始讀取16 Byte再進(jìn)行對(duì)比,如果和extended_content_header相等,則可以從下個(gè)Byte中依次獲取名稱(chēng)、藝術(shù)家、版權(quán)、注釋等非音頻信息。然后再接著讀取16 Byte進(jìn)行比對(duì),直到和data_eader相等。data_header后就是音頻文件解碼數(shù)據(jù),data_header的結(jié)束位置就是第一個(gè)數(shù)據(jù)包在文件中的偏移量。WMAExtractor會(huì)創(chuàng)建一個(gè)MetaData,并把文件頭中獲取的sample_rate、Byte_rate、channels、dura-tion都存入MetaData中。在WMAExtractor的getMetaData函數(shù)中,把之前獲取的非音頻信息放入MetaData中,最后返回該MetaData。在WMAEx-tractor的getTrack函數(shù)中,創(chuàng)建一個(gè)WMASource,并把WMA數(shù)據(jù)和MetaData傳給WMASource。
(3)編碼數(shù)據(jù)的讀取。
獲取未解碼數(shù)據(jù)是通過(guò)WmASource的read函數(shù)讀取的。WMA數(shù)據(jù)是以數(shù)據(jù)包為單位的,同文件中的數(shù)據(jù)包大小相同。每個(gè)數(shù)據(jù)包中有多幀數(shù)據(jù),每個(gè)數(shù)據(jù)包的起始位置減去第—個(gè)數(shù)據(jù)包的起始位置再除以包的大小等于一個(gè)整數(shù),這個(gè)整數(shù)就是該數(shù)據(jù)包之前數(shù)據(jù)包的個(gè)數(shù)。每個(gè)數(shù)據(jù)包的第一個(gè)Byte一般都等于0x82。第二個(gè)Byte以后是該數(shù)據(jù)包的相關(guān)信息。根據(jù)包的相關(guān)數(shù)據(jù)就可以獲取該包中的未解碼數(shù)據(jù)。
WMASource的read讀取未解碼數(shù)據(jù)時(shí),首先會(huì)判斷從WMADecoder傳來(lái)的options是否為空,如果不為空,并可以從options中獲取一個(gè)播放時(shí)間seekTimeUs,就通過(guò)seekTimeUs、總播放時(shí)間和總數(shù)據(jù)包的個(gè)數(shù)算出要播放數(shù)據(jù)包的起始位置,然后從該起始位置獲取一個(gè)數(shù)據(jù)包的數(shù)據(jù),并從該數(shù)據(jù)包中獲取有效數(shù)據(jù)的大小、起始位置、時(shí)間等數(shù)據(jù),最后把該有效數(shù)據(jù)和時(shí)間放在WMADecoder傳來(lái)的Buffer里。
WMASource的Read被調(diào)用時(shí),如果傳來(lái)的Options為空或是不能從Options中獲取時(shí)間seekTimeUs,就會(huì)從WMA文件中讀取一個(gè)數(shù)據(jù)包,根據(jù)其中的有效數(shù)據(jù)的大小、起始位置獲取有效數(shù)據(jù),并獲取該數(shù)據(jù)包中的時(shí)間,然后把該有效數(shù)據(jù)和時(shí)間放在WMADecoder傳來(lái)的buffer里。第一個(gè)數(shù)據(jù)包的起始位置就是解析頭文件時(shí)獲取的第一個(gè)數(shù)據(jù)包的偏移量,所以第一次調(diào)用WMASource的read時(shí),就是從這個(gè)偏移量的下個(gè)位置讀取第一個(gè)數(shù)據(jù)包的。在WMASource中有一個(gè)專(zhuān)門(mén)記錄讀取位置的指針。每次讀取1個(gè)數(shù)據(jù)包后,該指針就會(huì)指向數(shù)據(jù)包末尾的下一個(gè)位置,當(dāng)下一次WMASource的read讀取未解碼數(shù)據(jù)時(shí),如果不是音樂(lè)定點(diǎn)播放,就會(huì)從該指針?biāo)傅奈恢瞄_(kāi)始讀取數(shù)據(jù)包。本文引用地址:http://www.ex-cimer.com/article/194616.htm
(4)編碼數(shù)據(jù)的解碼和輸出。
AwesomePlayer通過(guò)OMXCodec中的Create函數(shù)創(chuàng)建WMADecoder,所以在OMXCodec中注冊(cè)WMADecoder的相關(guān)信息:
在創(chuàng)建WMADecoder時(shí),把之前創(chuàng)建的WMASource傳給WMADecoder。在WMADecoder構(gòu)造函數(shù)中,WMADecoder從WMASource中獲取Metadata,并從Metadata獲取sampleRate、numChannels、duration等。在WMADecoder的start函數(shù)中,通過(guò)調(diào)用avcodec_open函數(shù),來(lái)分配解碼所需的空間、創(chuàng)建并初始化解碼所需的相關(guān)參數(shù)。在WMADecoder析構(gòu)函數(shù)中會(huì)調(diào)用WMADecoder的Stop函數(shù)。在Stop函數(shù)中會(huì)釋放所有相關(guān)空間。
c++相關(guān)文章:c++教程
評(píng)論