2012-10-17 13 views
11

Próbuję użyć API MediaCodec na Androida do odkodowania strumienia AAC. (To jest surowy AAC.) Próbowałem użyć MediaFormat.createAudioFormat(), aby utworzyć obiekt formatu, który ma być przekazany do MediaCodec.configure(), ale ciągle otrzymywałem błędy podczas korzystania z AAC (audio/mp4a-latm). (Działa z MP3 (audio/mpeg) chociaż ...)Dekodowanie AAC przy użyciu MediaCodec API na Androidzie

W końcu stworzyłem MediaExtractor dla pliku AAC i przyjrzałem się obiektowi formatu, który on tworzył. Zobaczyłem, że zawiera on klucz "csd-0" dla ByteBuffer złożonego z dwóch bajtów o wartości 0x12. Jeśli uwzględnię ten klucz i wartość w obiekcie formatu, który użyłem do skonfigurowania kodeka AAC, wszystko działa.

Czy ktoś ma pojęcie, co się dzieje? Dokumentacja stwierdza, że ​​nie powinienem konfigurować tego klucza. Czy ktoś ma wskaźnik do przykładów MediaCodec do dekodowania plików AAC bez użycia MediaExtractor do generowania obiektu formatu?

+1

Dalsze dochodzenie doprowadziło mnie do przypuszczenia, że ​​CSD-0 zawiera ESDS (Elementary Stream deskryptora). Patrząc na MakeAACCodecSpecificData w avc_utils.cpp w źródłach Androida widzę, że pierwsze 5 bitów to typ obiektu (2), następne 4 to indeks częstotliwości (4 = 48000), następne 4 to konfiguracja kanału (2). [Ta strona wiki] (http://wiki.multimedia.cx/index.php?title=Understanding_AAC) wskazuje, że pozostałe bity dotyczą długości ramki, zależą od dekodera rdzenia i flagi rozszerzenia. Używam MediaFormat.createAudioFormat(), który powinien skonfigurować ważne elementy ESDS. –

Odpowiedz

4

Tak, konfiguracja kodeków 2 bajty są pierwszym, który otrzymasz. I tak, to bloki danych surowych aac. Możesz zobaczyć, jak wyprowadzam poniższy format podczas kodowania. Początkowo próbowałem postępować zgodnie z dokumentacją, która mówi, że są w formacie latm i próbowałem to przeanalizować. Znalazłem trochę "różnicy" na dokumentacji Androida, która mówi, że dane wyjściowe były rzeczywiście surowymi blokami. Wiedząc, że to było po prostu kwestia wyboru pojemnika na moje potrzeby. W szczególności potrzebowałem kontenera adts zamiast flv lub mp4.

Kopiowanie danych użytkowych do tablicy, która jest wystarczająco duża dla kontenera, wystarczy dodać do swoich bitów. Tak więc po przejrzeniu internet dla mojego roztworu I produkowane następujący kod:

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; 

Korzystanie coś takiego:

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

Mam pytanie uzupełniające: jaka jest powyższa wartość "configParams"? Czy jest to wartość config = xxxx z linii a = fmtp: nn w komunikacie SDP (dla strumieni RTSP)? –

+0

Parametry konfiguracyjne to specyficzna konfiguracja audio, a zazwyczaj pierwsze dwa bajty są wysyłane za pomocą kodera latm. Obiekt BufferINfo powinien mieć ustawiony znacznik Codec_info. –

2

użyłem kodu śledzenia i dodać ES który usuwa ADTS nagłówek, to może dobrze działać , ale ja naprawdę nie wiem, dlaczego należy ustawić „CSD-0” lub codec nastąpi error

 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

miałem żadnych problemów dekodowanie/odtwarzanie zawartości AAC na kilku urządzeniach testowałem. Moje podejście polegało na tym, aby najpierw użyć MediaExtractor do ustawienia źródła danych, następnie zainicjować MediaFormat i wreszcie wykonać pracę w pętli z buforami wysłanymi do/z MediaCodec. Dla powierzchni użyłem null, ponieważ jest to tylko odtwarzacz audio, więc nie ma nic do wyświetlenia.

ja również ułożyła przykładowy kod jak Android biblioteki, który jest dostępny na moim blogu: http://www.pocketmagic.net/2014/06/android-audio-player-using-mediacodec-mediaextractor/

Powiązane problemy