简体   繁体   English

在 Android 上使用 MediaCodec API 解码 AAC

[英]Decoding AAC using MediaCodec API on Android

I'm trying to used the MediaCodec API on Android to decode an AAC stream.我正在尝试在 Android 上使用 MediaCodec API 来解码 AAC 流。 (It's raw AAC.) I tried using the MediaFormat.createAudioFormat() to create the format object to pass to MediaCodec.configure(), but I kept getting errors when using AAC (audio/mp4a-latm). (它是原始 AAC。)我尝试使用 MediaFormat.createAudioFormat() 创建要传递给 MediaCodec.configure() 的格式对象,但是在使用 AAC (audio/mp4a-latm) 时我不断收到错误消息。 (It works with MP3 (audio/mpeg) though...) (虽然它适用于 MP3(音频/mpeg)...)

Finally I created a MediaExtractor for an AAC file and looked at the format object it was producing.最后,我为 AAC 文件创建了一个 MediaExtractor,并查看了它生成的格式对象。 I saw that it included the key "csd-0" for a ByteBuffer composed of two bytes both with the value 0x12.我看到它包含一个 ByteBuffer 的键“csd-0”,它由两个字节组成,两个字节的值都是 0x12。 If I include that key and value in the format object that I used to configure the AAC codec, everything works.如果我在用于配置 AAC 编解码器的格式对象中包含该键和值,则一切正常。

Does anyone have an idea what is going on?有谁知道发生了什么? The documentation states that I shouldn't configure that key.文档指出我不应该配置该密钥。 Does anyone have a pointer to MediaCodec examples to decode AAC files without using MediaExtractor to generate the format object?有没有人有指向 MediaCodec 示例的指针来解码 AAC 文件而不使用 MediaExtractor 生成格式对象?

Yes, the codec config 2 bytes are the initial you receive.是的,编解码器配置 2 字节是您收到的初始值。 And yes it is raw aac data blocks.是的,它是原始的 aac 数据块。 You can see how I derive the format below while encoding.您可以看到我在编码时如何导出以下格式。 I initially tried to follow the documentation, which said they are in latm format, and tried to parse that.我最初试图遵循文档,其中说它们是 latm 格式,并试图解析它。 I then found some 'diff' on the android documentation that said the output was indeed raw blocks.然后我在 android 文档上发现了一些“差异”,说输出确实是原始块。 Knowing that then, it was simply a matter of choosing a container for my needs.那时知道了,这只是为我的需要选择一个容器的问题。 In particular, I needed the adts container rather than flv or mp4.特别是,我需要 adts 容器而不是 flv 或 mp4。

Copying the payload data into an array that is large enough for your container, just add on your bits.将有效负载数据复制到一个足以容纳您的容器的数组中,只需添加您的位即可。 So after scouring the internet for my solution I produced the following code:因此,在互联网上搜索我的解决方案后,我生成了以下代码:

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;

Using something like this:使用这样的东西:

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

I used the follow code and add ES which removed ADTS header, it could work well, but I really do not know why should set "csd-0", or codec will occur error我使用了下面的代码并添加删除了ADTS头的ES,它可以正常工作,但我真的不知道为什么要设置“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);

I had no issues decoding/playing AAC content on the few devices I tested.在我测试的少数设备上解码/播放 AAC 内容没有问题。 My approach was to use the MediaExtractor first to set the Data source, then initialise the MediaFormat and finally do the work in a loop with buffers sent in/out to/from the MediaCodec.我的方法是首先使用 MediaExtractor 设置数据源,然后初始化 MediaFormat,最后在循环中完成工作,缓冲区从 MediaCodec 传入/传出。 For the surface I used null, as this is just an audio player so there is nothing to display.对于表面,我使用了 null,因为这只是一个音频播放器,所以没有什么可显示的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM