2012-10-17 180 views
11

我試圖在Android上使用MediaCodec API來解碼AAC流。 (這是原始的AAC。)我嘗試使用MediaFormat.createAudioFormat()創建傳遞給MediaCodec.configure()的格式對象,但是在使用AAC(audio/mp4a-latm)時我一直收到錯誤。 (它與MP3(音頻/ mpeg)雖然...)在Android上使用MediaCodec API解碼AAC

最後,我創建了AAC文件的MediaExtractor,並查看它正在生產的格式對象。我看到它包含了由兩個字節組成的ByteBuffer的鍵「csd-0」,兩個字節的值均爲0x12。如果我在用於配置AAC編解碼器的格式對象中包含該鍵和值,則一切正常。

有沒有人有一個想法是怎麼回事?該文檔聲明我不應該配置該密鑰。有沒有人有一個指向MediaCodec示例的指針來解碼AAC文件,而不使用MediaExtractor生成格式對象?

+1

進一步的研究使我相信,CSD-0包含ESDS(基本流描述符)。查看Android源代碼中的avc_utils.cpp中的MakeAACCodecSpecificData,我發現前5位是對象類型(2),接下來的4位是頻率索引(4 = 48000),接下來的4位是通道配置(2)。 [此wiki頁面](http://wiki.multimedia.cx/index.php?title=Understanding_AAC)表示剩餘的比特是幀長度,取決於核心解碼器和擴展標誌。我正在使用MediaFormat.createAudioFormat(),它應該設置ESDS的重要元素。 –

回答

4

是的,編解碼器配置2個字節是您收到的初始值。是的,它是原始數據塊。你可以看到如何在編碼時導出下面的格式。我最初試圖按照文檔說,他們是在拉姆格式,並試圖解析。然後我在android文檔中發現了一些'diff',表示輸出確實是原始塊。那麼知道,這只是爲我的需求選擇一個容器的問題。特別是,我需要adts容器而不是flv或mp4。

將有效載荷數據複製到足夠容量的數組中,只需添加您的位。所以在網上淘了我的解決方案後,我產生了以下代碼:

profile = (configParams[0]>>3)&0x1f; 

frequency_index = (this.configParams[0]&0x7) <<1 | (this.configParams[1]>>7) &0x1; 

channel_config = (this.configParams[1]>>3) &0xf; 

int finallength = encoded_length + 7;  
ENCodedByteArray[0] = (byte) 0xff; 
ENCodedByteArray[1] = (byte) 0xf1; 
ENCodedByteArray[2] = (byte) (((profile - 1) << 6) + (frequency_index << 2) +(channel_config >> 2)); 
ENCodedByteArray[3] = (byte) (((channel_config & 0x3) << 6) + (finallength >> 11)); 
ENCodedByteArray[4] = (byte)((finallength & 0x7ff) >> 3); 
ENCodedByteArray[5] = (byte) (((finallength & 7) << 5) + 0x1f) ; 
ENCodedByteArray[6] = (byte) 0xfc; 

使用這樣的事情:

byte chunkADTS[]=new byte[info.size + 7]; 
fillInADTSHeader(chunkADTS,info.size); 
outputBuffers[bR].get(chunkADTS,7,info.size); 
buffer.pushData(chunkADTS); 
+0

我有一個後續問題:上面的「configParams」值是什麼?這是來自SDP消息中的a = fmtp:nn行的配置= xxxx值(對於RTSP流)? –

+0

配置參數是特定的音頻配置,通常是latm媒體編解碼器輸出的前兩個字節。 BufferINfo對象應該設置了Codec_info標誌。 –

2

我用瞭如下代碼,並添加ES可以除去ADTS頭,它可以很好地工作,但我真的不知道爲什麼要設置「CSD-0」,或編解碼器會出現錯誤

 decoder = MediaCodec.createDecoderByType("audio/mp4a-latm"); 
     mMediaFormat = MediaFormat.createAudioFormat("audio/mp4a-latm", 44100,2); 
     byte[] bytes = new byte[]{(byte) 0x12, (byte)0x12}; 
     ByteBuffer bb = ByteBuffer.wrap(bytes); 
     mMediaFormat.setByteBuffer("csd-0", bb); 
0

我沒有問題解碼/對我測試了幾個設備上播放AAC內容。我的方法是首先使用MediaExtractor設置數據源,然後初始化MediaFormat,最後在循環中執行工作,並將緩衝區傳入/傳出MediaCodec。對於我使用null的表面,因爲這只是一個音頻播放器,所以沒有什麼可顯示的。

我也把一個示例代碼爲Android庫,可用在我的博客:http://www.pocketmagic.net/2014/06/android-audio-player-using-mediacodec-mediaextractor/

相關問題