2012-10-17 33 views
11

Tôi đang cố gắng sử dụng API MediaCodec trên Android để giải mã luồng AAC. (Đó là AAC thô.) Tôi đã thử sử dụng MediaFormat.createAudioFormat() để tạo đối tượng định dạng để chuyển tới MediaCodec.configure(), nhưng tôi vẫn gặp lỗi khi sử dụng AAC (audio/mp4a-latm). (Nó hoạt động với MP3 (audio/mpeg) mặc dù ...)Giải mã AAC bằng API MediaCodec trên Android

Cuối cùng tôi đã tạo MediaExtractor cho một tệp AAC và xem đối tượng định dạng mà nó đang tạo. Tôi thấy rằng nó bao gồm khóa "csd-0" cho một ByteBuffer bao gồm hai byte cả với giá trị 0x12. Nếu tôi bao gồm khóa và giá trị đó trong đối tượng định dạng mà tôi đã sử dụng để định cấu hình codec AAC, mọi thứ hoạt động.

Có ai có ý tưởng gì đang xảy ra không? Tài liệu nói rằng tôi không nên cấu hình khóa đó. Có ai có một con trỏ để MediaCodec ví dụ để giải mã tập tin AAC mà không sử dụng MediaExtractor để tạo ra các đối tượng định dạng?

+1

Tiếp tục điều tra đã dẫn tôi để tin rằng csd-0 chứa ESDS (Tiểu Suối Descriptor). Nhìn vào MakeAACCodecSpecificData trong avc_utils.cpp trong các nguồn Android tôi thấy rằng 5 bit đầu tiên là kiểu đối tượng (2), 4 tiếp theo là chỉ số tần số (4 = 48000), 4 tiếp theo là cấu hình kênh (2). [Trang wiki này] (http://wiki.multimedia.cx/index.php?title=Understanding_AAC) chỉ ra rằng các bit còn lại là chiều dài khung, phụ thuộc vào bộ giải mã lõi và cờ mở rộng. Tôi đang sử dụng MediaFormat.createAudioFormat() mà nên thiết lập các yếu tố quan trọng của ESDS. –

Trả lời

4

Có, cấu hình codec 2 byte là bản gốc bạn nhận được. Và có nó là khối dữ liệu aac thô. Bạn có thể thấy cách tôi lấy được định dạng bên dưới trong khi mã hóa. Ban đầu tôi đã cố gắng làm theo tài liệu hướng dẫn, cho biết chúng có định dạng latm và cố gắng phân tích cú pháp đó. Sau đó tôi tìm thấy một số 'khác biệt' trên tài liệu android cho biết đầu ra thực sự là các khối thô. Biết rằng sau đó, nó chỉ đơn giản là một vấn đề của việc lựa chọn một container cho các nhu cầu của tôi. Đặc biệt, tôi cần hộp mực quảng cáo thay vì flv hoặc mp4.

Sao chép dữ liệu tải trọng vào một mảng đủ lớn cho vùng chứa của bạn, chỉ cần thêm vào các bit của bạn. Vì vậy, sau khi sục sạo trên Internet cho giải pháp của tôi, tôi tạo ra đoạn mã sau:

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; 

Sử dụng một cái gì đó như thế này:

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

Tôi có một câu hỏi tiếp theo: giá trị "configParams" ở trên là gì? Đây có phải là giá trị config = xxxx từ dòng a = fmtp: nn trong thông báo SDP (đối với luồng RTSP) không? –

+0

Thông số cấu hình là cấu hình âm thanh cụ thể và thường là đầu ra hai byte đầu tiên bằng bộ giải mã phương tiện latm. Đối tượng BufferINfo phải có bộ cờ Codec_info. –

2

tôi đã sử dụng mã sau và thêm ES trong đó loại bỏ ADTS tiêu đề, nó có thể làm việc tốt , nhưng tôi thực sự không biết lý do tại sao nên thiết lập "csd-0", hoặc bộ giải mã sẽ xảy ra lỗi

 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

tôi không có vấn đề giải mã/chơi nội dung AAC trên vài các thiết bị tôi thử nghiệm. Cách tiếp cận của tôi là sử dụng MediaExtractor đầu tiên để thiết lập nguồn dữ liệu, sau đó khởi tạo MediaFormat và cuối cùng làm công việc trong một vòng lặp với các bộ đệm được gửi vào/ra đến/từ MediaCodec. Đối với bề mặt tôi sử dụng null, vì đây chỉ là một máy nghe nhạc nên không có gì để hiển thị.

Tôi cũng đặt cùng một mẫu mã như một thư viện Android, đó là có sẵn trên blog của tôi: http://www.pocketmagic.net/2014/06/android-audio-player-using-mediacodec-mediaextractor/

Các vấn đề liên quan