使用libfdk-aac解码AAC-ELD格式的音频

本文介绍了如何在Linux环境下,使用libfdk-aac库解码AAC-ELD格式的音频,特别是在处理流媒体RTSP/RTP传输的裸数据时的处理方法。通过ffmpeg进行AAC-ELD音频文件转换,并提供了参考代码示例展示解码流程。文章还提及了解码AAC-ELD音频需要AudioSpecificConfig配置的重要性。

前段时间尝试在XBMC的框架中添加对Airplay Screen Mirror的功能,有关Airplay的协议可以参考(当然是第三方破解的)

http://nto.github.com/AirPlay.html

本文指针对AAC-ELD音频的解析做一定说明,对于Airplay Screen Mirror本身暂不扩展。


如果是普通的AAC音频,自然可以使用FAAD的库进行解码,或者直接使用ffmpeg,网上有很多的资料,不过FAAD解不了AAC-ELD等级的AAC音频。

但问题有两点,第一是流媒体的格式的音频,也就是没有文件封装格式,流媒体本身是通过RTSP来传递一些配置信息,再利用RTP来传输数据。

第二,AAC-ELD的编码格式,目前能参考的资料不多,不过最新版的ffmepg(>ffmpeg-1.0)或者libav,已经支持了AAC-ELD格式的编码,可以

查看libavcodec目录下是否有libfdk-aacenc.c文件,其实本质是添加了对libfdk-aac音频库的支持,不过遗憾的是没有提供解码的代码。


其实,有关libfdk-aac解码的代码是有的,只是ffmepg没有将其吸纳进来,可以参考github上第三方修改的libav库,地址是

https://github.com/Arcen/libav

同时fdk-aac的库地址是

https://github.com/Arcen/fdk-aac

可以看出libavcodec目录下已经有了libfdk-aacdec.c文件,网友可以自行下载编译,找一个音频文件,先将其转换成AAC-ELD格式的音频,然后在尝试解码。

编码的命令可以参考这种格式

ffmpeg -y -i test.wav -c libfdk_aac -profile:a aac_eld test.mp4

(注意:ffmpeg对于编码一般都采用第三方的库,例如x264等,但解码,ffmpeg本身会调用自己重写的解码代码,所以不一定就能够调用到libfdk-aac来解码

AAC-ELD格式的音频,我当时是修改了ffmpeg的注册模块,强制利用fdk-aac来解码aac的音频来验证的)


以上解决的是文件封装的AAC-ELD音频,可以很容易验证,但对于RTP过来的裸音频数据,就要了解一下AAC的知识了,其中最最重要的是MPEG标准中规定,AAC

格式的音频需要一个AudioSpecificConfig配置,如果你上面生成了mp4文件,就可以利用mp4info.exe这个工具查看esds字段(路径大概在trac->media->

->minf->stbl->stsd->m4a->esds),然后可以参照esds的语法查找相应的AudioSpecificConfig字段。

下面贴一段参考代码,直接利用的fdk-aac的库,在ubuntu上运行的代码

(大概的流程是,有个线程在往队列里面填充数据,然后通过SDL播放,SDL的回调函数会去队列中取音频数据,然后调用fdk-aac解码,然后播放)

/*
 * decode AAC-ELD audio data from mac by XBMC, and play it by SDL
 *
 * modify:
 * 2012-10-31   first version (ffmpeg tutorial03.c)
 *
 */
 
#include <stdio.h
<think>好的,我现在需要回答用户关于在安卓平台上解码AAC-ELD音频格式的问题。首先,我要理解AAC-ELD是什么。根据用户提供的引用[1],FDK-AAC支持包括HE-AACAAC-ELD格式,说明AAC-ELD是一种高效的低延迟音频解码格式,常用于实时通信。 接下来,用户想知道如何在安卓上进行解码。安卓的音频解码通常使用MediaCodec API,这一点在引用[2]和[4]中都有提到。例如,引用[2]详细介绍了使用MediaCodec进行硬解码的步骤,包括初始化、配置和数据处理。引用[4]中的代码示例展示了如何通过MediaExtractor提取音频轨道,并获取MediaFormat,这可能用于配置解码器。 然后,我需要考虑AAC-ELD是否被安卓原生支持。根据安卓开发者文档,MediaCodec从某个版本开始支持AAC-ELD,但可能需要检查设备兼容性。如果原生不支持,可能需要使用第三方库如FFmpeg或者FDK-AAC。但用户的问题集中在安卓平台的教程或API使用,所以重点应放在MediaCodec上。 步骤方面,首先需要设置权限,如引用[3]中的录音和存储权限。然后使用MediaExtractor提取音频数据,配置MediaCodec时需指定MIME类型为"audio/mp4a-latm",并设置正确的CSD参数,如引用[2]中提到的音频解码的CSD参数配置。 此外,需要注意AAC-ELD可能需要特定的配置参数,比如profile和采样率。在代码示例中,需要正确设置MediaFormat的KEY_AAC_PROFILE等参数。处理数据时,需要处理输入输出缓冲区,并处理可能的格式变化,如引用[2]中的onOutputFormatChanged方法。 最后,测试不同设备的兼容性很重要,因为某些设备可能不支持AAC-ELD解码。如果遇到问题,可能需要使用软件解码库。总结步骤,给出代码示例的关键部分,并提醒用户注意兼容性问题。</think>### 安卓平台解码 AAC-ELD 音频格式的实现步骤 #### 1. **确认 AAC-ELD 支持性** AAC-ELD(Enhanced Low Delay AAC)是低延迟音频编码格式,适用于实时通信场景。安卓的 `MediaCodec` 从 **Android 4.1(API 16)** 开始支持 `audio/mp4a-latm` MIME 类型[^1],但需验证设备是否支持该格式: ```java MediaCodecList codecList = new MediaCodecList(MediaCodecList.ALL_CODECS); for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) { if (codecInfo.isEncoder()) continue; for (String mimeType : codecInfo.getSupportedTypes()) { if (mimeType.equalsIgnoreCase("audio/mp4a-latm")) { // 支持 AAC 解码,需进一步检查是否包含 ELD Profile MediaCodecInfo.CodecCapabilities caps = codecInfo.getCapabilitiesForType(mimeType); for (MediaCodecInfo.CodecProfileLevel profile : caps.profileLevels) { if (profile.profile == MediaCodecInfo.CodecProfileLevel.AACObjectELD) { Log.d("AAC-ELD", "设备支持解码"); } } } } } ``` #### 2. **使用 MediaExtractor 提取音频数据** 从文件或流中分离音频轨道,并获取格式信息: ```java MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(inputFile); int audioTrack = -1; for (int i = 0; i < extractor.getTrackCount(); i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("audio/")) { audioTrack = i; extractor.selectTrack(i); break; } } ``` #### 3. **配置 MediaCodec 解码器** 创建解码器并配置参数,**需显式指定 AAC-ELD Profile**: ```java MediaFormat format = extractor.getTrackFormat(audioTrack); // 关键参数:AAC Profile 和采样率 format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectELD); format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100); // 根据实际音频设置 MediaCodec decoder = MediaCodec.createDecoderByType("audio/mp4a-latm"); decoder.configure(format, null, null, 0); decoder.start(); ``` #### 4. **处理解码数据流** 循环读取输入缓冲区并写入解码器,同时从输出缓冲区获取 PCM 数据: ```java ByteBuffer[] inputBuffers = decoder.getInputBuffers(); ByteBuffer[] outputBuffers = decoder.getOutputBuffers(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); boolean isEOS = false; while (!isEOS) { int inIndex = decoder.dequeueInputBuffer(10000); if (inIndex >= 0) { ByteBuffer buffer = inputBuffers[inIndex]; int sampleSize = extractor.readSampleData(buffer, 0); if (sampleSize < 0) { decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); isEOS = true; } else { decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0); extractor.advance(); } } int outIndex = decoder.dequeueOutputBuffer(info, 10000); if (outIndex >= 0) { ByteBuffer outputBuffer = outputBuffers[outIndex]; // 处理 PCM 数据(例如保存到文件或播放) decoder.releaseOutputBuffer(outIndex, false); } } ``` #### 5. **处理 CSD(Codec Specific Data)** AAC 流可能包含 `CSD-0` 参数,需在 `MediaFormat` 中设置: ```java byte[] csd = format.getByteBuffer("csd-0").array(); // 从容器中提取 format.setByteBuffer("csd-0", ByteBuffer.wrap(csd)); ``` #### 6. **低延迟优化** - 使用 `MediaCodec` 的 **异步模式**(API 21+)减少线程阻塞 - 缩短缓冲区超时时间(如 `dequeueInputBuffer(1000)`) - 启用 `KEY_OPERATING_RATE` 和 `KEY_PRIORITY` 提升实时性 --- ### 关键问题与解决方案 1. **解码失败:`MediaCodec.CodecException`** - **原因**:设备不支持 AAC-ELD 或 Profile 配置错误 - **解决**: - 降级为 AAC-LC 格式(修改 `KEY_AAC_PROFILE`) - 使用软件解码库(如 FFmpeg + `libfdk-aac`) 2. **音频不同步** - **原因**:时间戳处理不当 - **解决**:根据 `info.presentationTimeUs` 对齐 PCM 输出 --- ### 示例代码(关键片段) 完整 Demo 可参考引用[^2][^4]中的实现,重点关注: ```java // 配置解码器时显式声明 ELD Profile format.setInteger( MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectELD ); // 处理 CSD 数据(例如从 MP4 的 esds 盒中提取) format.setByteBuffer("csd-0", ByteBuffer.wrap(csdData)); ``` ---
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值