androidandroid-mediacodecaacmediaextractor

Identify HE-AAC audio on Android for proper decoding and playback


I use the MediaExtractor / MediaCodec combo on Android (target API level >= 16) to decode audio streams. Now I have a subtle problem when playing back mp4/m4a containers that contain MPEG-4 HE-AAC audio data.

When querying track's MediaFormat for the MediaFormat.KEY_SAMPLE_RATE I actually get only half of the expected size, e.g for a track that needs a playback sample rate of 44100 the MediaFormat returns 22050. After reading some documentation on HE-AAC I understand that this is "correct" in terms of how that codec works.

Still, to play back the audio track on an AudioTrack instance I have to configure it with the correct (playback) samplerate which is 44100 and not 22050.

Therefore, I am looking for a way to know for sure when the audio is HE-AAC encoded with API target level >= 16 so I can set the sample rate of the AudioTrack to two times the reported sample rate.

Edit: I do check the MediaFormat when MediaCodec return with MediaCodec.INFO_OUTPUT_FORMAT_CHANGED. The format will look like this:

max-input-size=946, 
aac-profile=2, 
mime=audio/mp4a-latm, 
durationUs=158499410,
csd-0=java.nio.ByteArrayBuffer[position=0,limit=5,capacity=5], 
channel-count=2, 
sample-rate=22050

To get a proper playback on the AudioTrack I need to set the sample rate to 2 * sample-rate = 44100.

I wonder if the csd-0 contains more information to deduce the profile/format/etc. For the above example the 5 bytes from the csd-0 buffer looks like this:

0x13 0xffffff90 0x56 0xffffffe5 0xffffffa0

Now I'm wondering about the concrete structure of this "codec specific data"


Solution

  • You should only treat the MediaFormat returned by MediaExtractor as a hint; you need to look at what MediaCodec returns with INFO_OUTPUT_FORMAT_CHANGED, this should return the real samplerate. This means that you can only configure AudioTrack once decoding of the content has started.