目录
主要流程:
mediacode解码aac:
mediacode参数?"csd-0",如何设定?
这里手动解析 aac文件,如果只是本地播放aac文件那么android已经有完善的方法:MediaExtractor + MediaCoddec 或者直接是MediaPlayer, 但有的时候我们有自己的aac帧数据,想利用Mediacode进行解码,里面就有些坑。 完整app源码:github?https://github.com/Canok7/openScreen/tree/main/clientAndroid/AACPlayer
主要流程:
1.这里写了个aac文件的解析类,解析aac-adts文件,从中读取 音频信息如:通道,采样率,编码等级等信息。2.然后从aac文件中逐步取出aac raw (去掉adts头的数据),送到mediacode解码(ndk),3.再将解码的pcm数据调用java的audioTrack(也可以采用opensl 直接在native层渲染,只是ndk还没有开放提供audioTrack的接口,所以这里使用native反过来调用java的audioTrack接口。vlc也是如此)
解析aac源文件: 有很多的blog介绍其组成,这里不赘述,源码中有完整的解析流程:
int64_t iheader=MAKE64_LEFT(headers[0],headers[1],headers[2],headers[3],
headers[4],headers[5],headers[6],0);
//ALOGD("[%s%d]%#lx",__FUNCTION__ ,__LINE__,iheader);
int id = GET64BIT_LEFT(iheader,12,1);
int layer = GET64BIT_LEFT(iheader,13,2);
int protection_absent = GET64BIT_LEFT(iheader,15,1);
int profile = GET64BIT_LEFT(iheader,16,2);
int sampling_frequency_index = GET64BIT_LEFT(iheader,18,4);
int private_bt = GET64BIT_LEFT(iheader,22,1);
int channel_configuration = GET64BIT_LEFT(iheader,23,3);
int original_copy = GET64BIT_LEFT(iheader,26,1);
int home = GET64BIT_LEFT(iheader,27,1);
//adts_variable_header
int copyright_identification_bit = GET64BIT_LEFT(iheader,28,1);
int copyright_identification_start=GET64BIT_LEFT(iheader,29,1);
int aac_frame_length =GET64BIT_LEFT(iheader,30,13);
int adts_buffer_fullness=GET64BIT_LEFT(iheader,33,11);
int number_of_raw_data_blocks_in_frame=GET64BIT_LEFT(iheader,44,2);
一直想找个官方的标准文档看看,就是没找着,大部分文章都是雷同一句话:AAC音频格式在MPEG-2(ISO-13318-7 2003)中有定义,可是没人提及这个文档哪里有,?这个标准据说是收费的,而且很贵,MPEG官网也没找着。 抄一个网络上常见的图记录下:
?
?其中有一个参数,"csd-0", 很难找到这个参数的官方完整说明,因为这个参数和AAC格式本身无关,在ffmpeg软解中也没有找到该参数,只是MediaCode(也有可能是omx的)自己使用的一个特殊参数,全称:Codec specific data,? 可以在android源码中找到其相关信息,android 源码中: frameworks/av/media/libstagefight/MetaDataUtils.cpp :: 里面函数: MakeAVCCodecSpecificData() MakeAACCodecSpecificData()
bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration) {
if(sampling_freq_index > 11u) {
return false;
}
uint8_t csd[2];
csd[0] = ((profile + 1) << 3) | (sampling_freq_index >> 1);
csd[1] = ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
static const int32_t kSamplingFreq[] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000
};
int32_t sampleRate = kSamplingFreq[sampling_freq_index];
AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd, sizeof(csd));
AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_configuration);
return true;
}
所以这个参数只是 Mediacode 自定的,和aac文件自身格式无关,没什么好研究的,既然要用Mediacode,就遵循它的设定,直接套用上面函数即可(可以看到这个数据也只是包含了profie, sampleFrequency, channel 三个信息,而这三个参数明明有单独的设置接口,还要重复这么一个信息,真是对它无语)。 ?
|