注:文章都是通过阅读各位前辈总结的资料 Android 8.x && Linux(kernel 4.x)Qualcomm平台源码、加上自己的思考分析总结出来的,其中难免有理解不对的地方,欢迎大家批评指正。文章为个人学习、研究、欣赏之用,图文内容整理自互联网(◕‿◕),如有侵权,请联系删除,禁止转载(©Qualcomm ©Android @Linux 版权所有),谢谢。
首先感谢:
AAC音频格式分析与解码 android ACodec MediaCodec NuPlayer flow
正是由于前人的分析和总结,帮助我节约了大量的时间和精力,再次感谢!!!
Google Pixel、Pixel XL 内核代码(==文章基于 Kernel-3.x ==): Kernel source for Pixel 2 (walleye) and Pixel 2 XL (taimen) - GitHub
AOSP 源码(==文章基于 Android 7.x ==): Android 系统全套源代码分享 (更新到 8.1.0_r1)
1 2 3 4 5 6 \frameworks\av\media\libstagefright\omx\SoftOMXPlugin.cpp kComponents[] = { { "OMX.google.aac.decoder" , "aacdec" , "audio_decoder.aac" }, { "OMX.google.aac.encoder" , "aacenc" , "audio_encoder.aac" }, ...... };
==源码(部分)==:
PATH : \frameworks\av\media\libstagefright\codecs (Android Codecs)
\external\aac(libFraunhoferAAC 库)
libAACdec
libAACenc
libFDK
documentation\aacDecoder.pdf
documentation\aacEncoder.pdf
\cts\tests\tests\media\res\raw(资源文件)
Log:AAC-DEcorder-Google-Log.md AAC-Encorder-Google-Log.md
(一)、AAC音频格式分析(概览) 1.1、AAC概述 wiki/進階音訊編碼 高级音频编码(英语:Advanced Audio Coding,AAC),出现于1997年,为一种基于MPEG-2的有损数字音频压缩的专利音频编码标准,由Fraunhofer IIS、杜比实验室、AT&T、Sony、Nokia等公司共同开发。2000年,MPEG-4标准在原本的基础上加上了PNS(Perceptual Noise Substitution)等技术,并提供了多种扩展工具。为了区别于传统的MPEG-2 AAC又称为MPEG-4 AAC。其作为MP3的后继者而被设计出来,在相同的比特率之下,AAC相较于MP3通常可以达到更好的声音品质[2]。
AAC由国际标准化组织及国际电工委员会标准化为MPEG-2及MPEG-4规格的一部分。[3][4]部分的AAC、HE-AAC(AAC+)为MPEG-4音频的一部分,并且被采用在数字声音广播、世界数字广播两个数字广播标准中以及DVB-H、ATSC-M/H两个移动电视标准中。
AAC支持包含一个流中48个最高至96 kHz的全带宽声道,加上16个120 Hz的低频声道(LFE)、不多于16个耦合声道及数据流。在joint stereo模式下,要使立体声的品质达到可接受的程度仅需96 kbps的比特率,若要达到Hi-fi则最少需要在可变码率下128 kbps。
AAC 被YouTube、iPhone、iPod、 iPad、 任天堂DSi、任天堂3DS、iTunes、DivX、PlayStation 3和多款Nokia 40系列手机采用为默认的音频编码格式,并且被PlayStation Vita、Wii、Sony Walkman MP3系列及随后的Android、BlackBerry等移动操作系统支持。
AAC编码的主要扩展名有三种:
.aac - 使用MPEG-2 Audio Transport Stream(ADTS,参见MPEG-2)容器,区别于使用MPEG-4容器的MP4/M4A格式,属于传统的AAC编码(FAAC默认的封装,但FAAC亦可输出MPEG-4封装的AAC)。 .mp4 - 使用了MPEG-4 Part 14(第14部分)的简化版即3GPP Media Release 6 Basic(3gp6,参见3GP)进行封装的AAC编码(Nero AAC编码器仅能输出MPEG-4封装的AAC)。 .m4a - 为了区别纯音频MP4文件和包含视频的MP4文件而由苹果(Apple)公司使用的扩展名,Apple iTunes对纯音频MP4文件采用了”.m4a”命名。M4A的本质和音频MP4相同,故音频MP4文件亦可直接更改扩展名为M4A。
1.2、AAC音频格式分析 AAC音频格式有ADIF和ADTS:
ADIF:Audio Data Interchange Format 音频数据交换格式。这种格式的特征是可以确定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明确定义的开始处进行。故这种格式常用在磁盘文件中。
ADTS:Audio Data Transport Stream 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。
简单说,ADTS可以在任意帧解码,也就是说它每一帧都有头信息。ADIF只有一个统一的头,所以必须得到所有的数据后解码。且这两种的header的格式也是不同的,目前一般编码后的和抽取出的都是ADTS格式的音频流。
语音系统对实时性要求较高,基本是这样一个流程,采集音频数据,本地编码,数据上传,服务器处理,数据下发,本地解码
ADTS是帧序列,本身具备流特征,在音频流的传输与处理方面更加合适。
ADTS是AAC音频文件常见的传输格式。当你编码AAC裸流的时候,会遇到写出来的AAC文件并不能在PC和手机上播放,很大的可能就是AAC文件的每一帧里缺少了ADTS头信息文件的包装拼接。只需要加入头文件ADTS即可。一个AAC原始数据块长度是可变的,对原始帧加上ADTS头进行ADTS的封装,就形成了ADTS帧。
图中表示出了ADTS一帧的简明结构,其两边的空白矩形表示一帧前后的数据。
(二)、Android AAC音频 解码 前面的文章已经分析过音视频录制和播放流程了,首先回忆一下播放流程:android ACodec MediaCodec NuPlayer flow
AAC播放流程基本一致,所以这里专注于分析下Android AAC编解码流程,首先看看时序图:
2.1、initDecoder() 从打印Log 可以看出,在初始化解码器的时候是用的Google的aac.decoder解码:
1 2 3 4 5 6 7 8 9 10 12 -25 23 :12 :00.176 : V/ACodec(795 ): Now uninitialized12 -25 23 :12 :00.176 : V/ACodec(795 ): onAllocateComponent12 -25 23 :12 :00.178 : I/MediaPlayerService(795 ): MediaPlayerService::getOMX12 -25 23 :12 :00.182 : I/OMXClient(795 ): MuxOMX ctor12-25 23:12:00.182: V/MediaCodecList(795): matching 'OMX.google.aac.decoder' 12 -25 23 :12 :00.183 : V/OMXNodeInstance(785 ): debug level for OMX.google.aac.decoder is 0 12 -25 23 :12 :00.183 : I/OMXMaster(785 ): makeComponentInstance(OMX.google.aac.decoder) in mediacodec process12-25 23:12:00.184: V/SoftOMXPlugin(785): makeComponentInstance 'OMX.google.aac.decoder' 12 -25 23 :12 :00.188 : V/SoftAAC2(785 ): initDecoder()
主要是调用libFraunhoferAAC 库完成一些参数初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Z:\MediaLearing\frameworks\av\media\libstagefright\codecs\aacdec\SoftAAC2.cpp status_t SoftAAC2::initDecoder () { ALOGV("initDecoder()" ); status_t status = UNKNOWN_ERROR; mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, 1 ); ..... mDrcWrap.setDecoderHandle(mAACDecoder); mDrcWrap.submitStreamData(mStreamInfo); .... aacDecoder_SetParam(mAACDecoder, AAC_PCM_MAX_OUTPUT_CHANNELS, -1 ); return status; }
我们看看打开过程,只贴出代码,不做具体分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 Z:\MediaLearing\external\aac\libAACdec\src\aacdecoder_lib.cpp LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open (TRANSPORT_TYPE transportFmt, UINT nrOfLayers) { AAC_DECODER_INSTANCE *aacDec = NULL ; HANDLE_TRANSPORTDEC pIn; int err = 0 ; pIn = transportDec_Open(transportFmt, TP_FLAG_MPEG4); ...... transportDec_SetParam(pIn, TPDEC_PARAM_IGNORE_BUFFERFULLNESS, 1 ); aacDec = CAacDecoder_Open(transportFmt); ...... aacDec->hInput = pIn; aacDec->nrOfLayers = nrOfLayers; aacDec->channelOutputMapping = channelMappingTableWAV; transportDec_RegisterAscCallback(pIn, aacDecoder_ConfigCallback, (void *)aacDec); if ( SBRDEC_OK != sbrDecoder_Open ( &aacDec->hSbrDecoder )) { ...... } aacDec->qmfModeUser = NOT_DEFINED; transportDec_RegisterSbrCallback(aacDec->hInput, (cbSbr_t)sbrDecoder_Header, (void *)aacDec->hSbrDecoder); ...... pcmDmx_Open( &aacDec->hPcmUtils ); ...... aacDec->hLimiter = createLimiter(TDL_ATTACK_DEFAULT_MS, TDL_RELEASE_DEFAULT_MS, SAMPLE_MAX, (8 ), 96000 ); ...... aacDec->limiterEnableUser = (UCHAR)-1 ; aacDec->limiterEnableCurr = 0 ; ...... return aacDec; }
具体的就不深入分析了,等有具体问题再来研究。
2.2、fillThisBuffer() 使用ACodec填充数据的时候,会一直调用到SoftAAC2::onQueueFilled()函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 Z:\MediaLearing\frameworks\av\media\libstagefright\codecs\aacdec\SoftAAC2.cpp void SoftAAC2::onQueueFilled (OMX_U32 ) { ...... UCHAR* inBuffer[FILEREAD_MAX_LAYERS]; UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0 }; UINT bytesValid[FILEREAD_MAX_LAYERS] = {0 }; List<BufferInfo *> &inQueue = getPortQueue(0 ); List<BufferInfo *> &outQueue = getPortQueue(1 ); while ((!inQueue.empty() || mEndOfInput) && !outQueue.empty()) { if (!inQueue.empty()) { INT_PCM tmpOutBuffer[2048 * MAX_CHANNEL_COUNT]; BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; mEndOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0 ; ...... if (mIsADTS) { size_t adtsHeaderSize = 0 ; const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; bool signalError = false ; ...... mBufferSizes.add(inBufferLength[0 ]); ....... } else { inBuffer[0 ] = inHeader->pBuffer + inHeader->nOffset; inBufferLength[0 ] = inHeader->nFilledLen; mLastInHeader = inHeader; updateTimeStamp(inHeader->nTimeStamp); mBufferSizes.add(inHeader->nFilledLen); } bytesValid[0 ] = inBufferLength[0 ]; INT prevSampleRate = mStreamInfo->sampleRate; INT prevNumChannels = mStreamInfo->numChannels; aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); mDrcWrap.submitStreamData(mStreamInfo); mDrcWrap.update(); UINT inBufferUsedLength = inBufferLength[0 ] - bytesValid[0 ]; inHeader->nFilledLen -= inBufferUsedLength; inHeader->nOffset += inBufferUsedLength; AAC_DECODER_ERROR decoderErr; int numLoops = 0 ; do { if (outputDelayRingBufferSpaceLeft() < (mStreamInfo->frameSize * mStreamInfo->numChannels)) { ALOGV("skipping decode: not enough space left in ringbuffer" ); break ; } int numConsumed = mStreamInfo->numTotalBytes; decoderErr = aacDecoder_DecodeFrame(mAACDecoder, tmpOutBuffer, 2048 * MAX_CHANNEL_COUNT, 0 ); numConsumed = mStreamInfo->numTotalBytes - numConsumed; numLoops++; mDecodedSizes.add(numConsumed); size_t numOutBytes = mStreamInfo->frameSize * sizeof (int16_t ) * mStreamInfo->numChannels; } while (decoderErr == AAC_DEC_OK); } while (!outQueue.empty() && outputDelayRingBufferSamplesAvailable() >= mStreamInfo->frameSize * mStreamInfo->numChannels) { BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; INT_PCM *outBuffer = reinterpret_cast <INT_PCM *>(outHeader->pBuffer + outHeader->nOffset); int samplesize = mStreamInfo->numChannels * sizeof (int16_t ); ...... int available = outputDelayRingBufferSamplesAvailable(); int numSamples = outHeader->nAllocLen / sizeof (int16_t ); if (numSamples > available) { numSamples = available; } int64_t currentTime = 0 ; if (available) { int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels); numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels); ALOGV("%d samples available (%d), or %d frames" , numSamples, available, numFrames); int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0 ); currentTime = *nextTimeStamp; int32_t *currentBufLeft = &mBufferSizes.editItemAt(0 ); for (int i = 0 ; i < numFrames; i++) { int32_t decodedSize = mDecodedSizes.itemAt(0 ); mDecodedSizes.removeAt(0 ); ALOGV("decoded %d of %d" , decodedSize, *currentBufLeft); if (*currentBufLeft > decodedSize) { *currentBufLeft -= decodedSize; *nextTimeStamp += mStreamInfo->aacSamplesPerFrame * 1000000l l / mStreamInfo->aacSampleRate; mNextOutBufferTimeUs = *nextTimeStamp; ALOGV("adjusted nextTimeStamp/size to %lld/%d" , (long long ) *nextTimeStamp, *currentBufLeft); } else { if (mBufferTimestamps.size() > 0 ) { mBufferTimestamps.removeAt(0 ); nextTimeStamp = &mBufferTimestamps.editItemAt(0 ); mNextOutBufferTimeUs = *nextTimeStamp; mBufferSizes.removeAt(0 ); currentBufLeft = &mBufferSizes.editItemAt(0 ); ALOGV("moved to next time/size: %lld/%d" , (long long ) *nextTimeStamp, *currentBufLeft); } numFrames = i + 1 ; numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels; break ; } } ALOGV("getting %d from ringbuffer" , numSamples); int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples); } outHeader->nFilledLen = numSamples * sizeof (int16_t ); outHeader->nTimeStamp = currentTime; mOutputBufferCount++; outInfo->mOwnedByUs = false ; outQueue.erase(outQueue.begin()); outInfo = NULL ; ALOGV("out timestamp %lld / %d" , outHeader->nTimeStamp, outHeader->nFilledLen); notifyFillBufferDone(outHeader); outHeader = NULL ; } if (mEndOfInput) { int ringBufAvail = outputDelayRingBufferSamplesAvailable(); if (!outQueue.empty() && ringBufAvail < mStreamInfo->frameSize * mStreamInfo->numChannels) { if (!mEndOfOutput) { mEndOfOutput = true ; BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; INT_PCM *outBuffer = reinterpret_cast <INT_PCM *>(outHeader->pBuffer + outHeader->nOffset); int32_t ns = outputDelayRingBufferGetSamples(outBuffer, ringBufAvail); if (ns < 0 ) { ns = 0 ; } outHeader->nFilledLen = ns; outHeader->nFlags = OMX_BUFFERFLAG_EOS; outHeader->nTimeStamp = mBufferTimestamps.itemAt(0 ); mBufferTimestamps.clear(); mBufferSizes.clear(); mDecodedSizes.clear(); mOutputBufferCount++; outInfo->mOwnedByUs = false ; outQueue.erase(outQueue.begin()); outInfo = NULL ; notifyFillBufferDone(outHeader); outHeader = NULL ; } break ; } } } }
这段代码主要作用是将数据inBuffer送到解码库libFraunhoferAAC解码(aacDecoder_Fill) 从Log可以看出此音频是属于adts 格式的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 12-25 23:12:00.161: V/NuPlayerDecoder(795): [decoder] onMessage: AMessage(what = 'conf', target = 28) = { 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): AMessage format = AMessage(what = 0x00000000 ) = {12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): string mime = "audio/mp4a-latm" 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int64_t durationUs = 9936000 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t channel-count = 1 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t sample-rate = 44100 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t is-adts = 1 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t aac-profile = 2 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t max-input-size = 262144 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): Buffer csd-0 = {12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): 00000000 : 12 08 ..12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): }12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): string file-format = "audio/aac" 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t aac-format-adif = 0 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t is-byte-stream-mode = 1 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t priority = 0 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): int32_t pcm-encoding = 2 12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): }12 -25 23 :12 :00.161 : V/NuPlayerDecoder(795 ): }
然后循环解码数据(aacDecoder_DecodeFrame),最后数据解码完成后通知IOMX(notifyFillBufferDone(outHeader))。 Log:
1 2 3 4 5 6 12 -25 23 :12 :00.420 : V/SoftAAC2(785 ): inHeader->nFilledLen = 50360 12 -25 23 :12 :00.420 : V/SoftAAC2(785 ): 1024 samples available (1387 ), or 1 frames12 -25 23 :12 :00.420 : V/SoftAAC2(785 ): decoded 115 of 115 12 -25 23 :12 :00.420 : V/SoftAAC2(785 ): moved to next time/size: 116095 /112 12 -25 23 :12 :00.420 : V/SoftAAC2(785 ): getting 1024 from ringbuffer12 -25 23 :12 :00.420 : V/SoftAAC2(785 ): out timestamp 92876 / 2048
最后经过NuPlayerRenderer的onDrainAudioQueue函数经由AudioSink 将数据写入到底层,最后经由硬件播放声音。
1 2 12 -25 23 :12 :08.293 : V/NuPlayerRenderer(795 ): onDrainAudioQueue: rendering audio at media time 8.36 secs12 -25 23 :12 :08.294 : V/NuPlayerRenderer(795 ): AudioSink write short frame count 296 < 2048
(三)、Android AAC音频 编码 首先看看时序图:
编码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 Z:\MediaLearing\frameworks\av\media\libstagefright\codecs\aacenc\SoftAACEncoder2.cpp void SoftAACEncoder2::onQueueFilled (OMX_U32 ) { ....... List<BufferInfo *> &inQueue = getPortQueue(0 ); List<BufferInfo *> &outQueue = getPortQueue(1 ); if (!mSentCodecSpecificData) { ...... if (AACENC_OK != aacEncEncode(mAACEncoder, NULL , NULL , NULL , NULL )) { } OMX_U32 actualBitRate = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE); ...... AACENC_InfoStruct encInfo; if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) { } BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; if (outHeader->nOffset + encInfo.confSize > outHeader->nAllocLen) { } outHeader->nFilledLen = encInfo.confSize; outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG; uint8_t *out = outHeader->pBuffer + outHeader->nOffset; memcpy (out, encInfo.confBuf, encInfo.confSize); outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false ; notifyFillBufferDone(outHeader); mSentCodecSpecificData = true ; } size_t numBytesPerInputFrame = mNumChannels * kNumSamplesPerFrame * sizeof (int16_t ); for (;;) { while (mInputSize < numBytesPerInputFrame) { ...... BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; const void *inData = inHeader->pBuffer + inHeader->nOffset; size_t copy = numBytesPerInputFrame - mInputSize; if (copy > inHeader->nFilledLen) { copy = inHeader->nFilledLen; } ...... memcpy ((uint8_t *)mInputFrame + mInputSize, inData, copy); mInputSize += copy; inHeader->nOffset += copy; inHeader->nFilledLen -= copy; inHeader->nTimeStamp += (copy * 1000000l l / mSampleRate) / (mNumChannels * sizeof (int16_t )); if (inHeader->nFilledLen == 0 ) { if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { mSawInputEOS = true ; memset ((uint8_t *)mInputFrame + mInputSize, 0 , numBytesPerInputFrame - mInputSize); mInputSize = numBytesPerInputFrame; } inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false ; notifyEmptyBufferDone(inHeader); inData = NULL ; inHeader = NULL ; inInfo = NULL ; } } BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset; size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset; AACENC_InArgs inargs; AACENC_OutArgs outargs; memset (&inargs, 0 , sizeof (inargs)); memset (&outargs, 0 , sizeof (outargs)); inargs.numInSamples = numBytesPerInputFrame / sizeof (int16_t ); void * inBuffer[] = { (unsigned char *)mInputFrame }; INT inBufferIds[] = { IN_AUDIO_DATA }; INT inBufferSize[] = { (INT)numBytesPerInputFrame }; INT inBufferElSize[] = { sizeof (int16_t ) }; AACENC_BufDesc inBufDesc; inBufDesc.numBufs = sizeof (inBuffer) / sizeof (void *); inBufDesc.bufs = (void **)&inBuffer; inBufDesc.bufferIdentifiers = inBufferIds; inBufDesc.bufSizes = inBufferSize; inBufDesc.bufElSizes = inBufferElSize; void * outBuffer[] = { outPtr }; INT outBufferIds[] = { OUT_BITSTREAM_DATA }; INT outBufferSize[] = { 0 }; INT outBufferElSize[] = { sizeof (UCHAR) }; AACENC_BufDesc outBufDesc; outBufDesc.numBufs = sizeof (outBuffer) / sizeof (void *); outBufDesc.bufs = (void **)&outBuffer; outBufDesc.bufferIdentifiers = outBufferIds; outBufDesc.bufSizes = outBufferSize; outBufDesc.bufElSizes = outBufferElSize; AACENC_ERROR encoderErr = AACENC_OK; size_t nOutputBytes = 0 ; do { memset (&outargs, 0 , sizeof (outargs)); outBuffer[0 ] = outPtr; outBufferSize[0 ] = outAvailable - nOutputBytes; encoderErr = aacEncEncode(mAACEncoder, &inBufDesc, &outBufDesc, &inargs, &outargs); ...... } while (encoderErr == AACENC_OK && inargs.numInSamples > 0 ); outHeader->nFilledLen = nOutputBytes; outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME; ...... outHeader->nTimeStamp = mInputTimeUs; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false ; notifyFillBufferDone(outHeader); outHeader = NULL ; outInfo = NULL ; mInputSize = 0 ; } }
这段代码主要使用aacEncEncode函数来对原始音频数据编码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 Z:\MediaLearing\external\aac\libAACenc\src\aacenc_lib.cpp AACENC_ERROR aacEncEncode ( const HANDLE_AACENCODER hAacEncoder, const AACENC_BufDesc *inBufDesc, const AACENC_BufDesc *outBufDesc, const AACENC_InArgs *inargs, AACENC_OutArgs *outargs ) { AACENC_ERROR err = AACENC_OK; INT i, nBsBytes = 0 ; INT outBytes[(1 )]; int nExtensions = 0 ; int ancDataExtIdx = -1 ; ...... if (hAacEncoder->InitFlags!=0 ) { err = aacEncInit(hAacEncoder, hAacEncoder->InitFlags, &hAacEncoder->extParam); hAacEncoder->InitFlags = AACENC_INIT_NONE; } ...... if ( (inargs->numInSamples > 0 ) && (getBufDescIdx(inBufDesc,IN_AUDIO_DATA) != -1 ) ) { INT idx = getBufDescIdx(inBufDesc,IN_AUDIO_DATA); INT newSamples = fixMax(0 ,fixMin(inargs->numInSamples, hAacEncoder->nSamplesToRead-hAacEncoder->nSamplesRead)); INT_PCM *pIn = hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset+hAacEncoder->nSamplesRead; if (inBufDesc->bufElSizes[idx]==(INT)sizeof (INT_PCM)) { FDKmemcpy(pIn, (INT_PCM*)inBufDesc->bufs[idx], newSamples*sizeof (INT_PCM)); } else if (inBufDesc->bufElSizes[idx]>(INT)sizeof (INT_PCM)) { for (i=0 ; i<newSamples; i++) { pIn[i] = (INT_PCM)(((LONG*)inBufDesc->bufs[idx])[i]>>16 ); } } else { for (i=0 ; i<newSamples; i++) { pIn[i] = ((INT_PCM)(((SHORT*)inBufDesc->bufs[idx])[i]))<<16 ; } } hAacEncoder->nSamplesRead += newSamples; outargs->numInSamples = newSamples; } if (hAacEncoder->nSamplesRead < hAacEncoder->nSamplesToRead) { if (inargs->numInSamples==-1 ) { if ( (hAacEncoder->nZerosAppended < hAacEncoder->nDelay) ) { int nZeros = hAacEncoder->nSamplesToRead - hAacEncoder->nSamplesRead; FDK_ASSERT(nZeros >= 0 ); if (nZeros) { FDKmemclear(hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset+hAacEncoder->nSamplesRead, sizeof (INT_PCM)*nZeros ); hAacEncoder->nZerosAppended += nZeros; hAacEncoder->nSamplesRead = hAacEncoder->nSamplesToRead; } } else { err = AACENC_ENCODE_EOF; goto bail; } } else { goto bail; } } FDKmemclear(hAacEncoder->extPayload, sizeof (AACENC_EXT_PAYLOAD) * MAX_TOTAL_EXT_PAYLOADS); for (i = 0 ; i < MAX_TOTAL_EXT_PAYLOADS; i++) { hAacEncoder->extPayload[i].associatedChElement = -1 ; } FDKmemclear(hAacEncoder->extPayloadData, sizeof (hAacEncoder->extPayloadData)); FDKmemclear(hAacEncoder->extPayloadSize, sizeof (hAacEncoder->extPayloadSize)); if ( (hAacEncoder->hMetadataEnc!=NULL ) && (hAacEncoder->metaDataAllowed!=0 ) ) { const AACENC_MetaData *pMetaData = NULL ; AACENC_EXT_PAYLOAD *pMetaDataExtPayload = NULL ; UINT nMetaDataExtensions = 0 ; INT matrix_mixdown_idx = 0 ; if ( getBufDescIdx(inBufDesc,IN_METADATA_SETUP) != -1 ) { pMetaData = (AACENC_MetaData*)inBufDesc->bufs[getBufDescIdx(inBufDesc,IN_METADATA_SETUP)]; } FDK_MetadataEnc_Process(hAacEncoder->hMetadataEnc, hAacEncoder->inputBuffer+hAacEncoder->inputBufferOffset, hAacEncoder->nSamplesRead, pMetaData, &pMetaDataExtPayload, &nMetaDataExtensions, &matrix_mixdown_idx ); for (i=0 ; i<(INT)nMetaDataExtensions; i++) { hAacEncoder->extPayload[nExtensions++] = pMetaDataExtPayload[i]; } if ( (matrix_mixdown_idx!=-1 ) && ((hAacEncoder->extParam.userChannelMode==MODE_1_2_2)||(hAacEncoder->extParam.userChannelMode==MODE_1_2_2_1)) ) { UINT pceValue = (UINT)( (0 <<3 ) | ((matrix_mixdown_idx&0x3 )<<1 ) | 1 ); if (hAacEncoder->extParam.userPceAdditions != pceValue) { hAacEncoder->extParam.userPceAdditions = pceValue; hAacEncoder->InitFlags |= AACENC_INIT_TRANSPORT; } } } if ( isSbrActive(&hAacEncoder->aacConfig) ) { INT nPayload = 0 ; if (sbrEncoder_EncodeFrame(hAacEncoder->hEnvEnc, hAacEncoder->inputBuffer, hAacEncoder->extParam.nChannels, hAacEncoder->extPayloadSize[nPayload], hAacEncoder->extPayloadData[nPayload] #if defined(EVAL_PACKAGE_SILENCE) || defined(EVAL_PACKAGE_SBR_SILENCE) ,hAacEncoder->hAacEnc->clearOutput #endif )) { err = AACENC_ENCODE_ERROR; goto bail; } else { for (i = 0 ; i < (8 ); i++) { if (hAacEncoder->extPayloadSize[nPayload][i] > 0 ) { hAacEncoder->extPayload[nExtensions].pData = hAacEncoder->extPayloadData[nPayload][i]; { hAacEncoder->extPayload[nExtensions].dataSize = hAacEncoder->extPayloadSize[nPayload][i]; hAacEncoder->extPayload[nExtensions].associatedChElement = i; } hAacEncoder->extPayload[nExtensions].dataType = EXT_SBR_DATA; nExtensions++; FDK_ASSERT(nExtensions<=MAX_TOTAL_EXT_PAYLOADS); } } nPayload++; } } if ( (inargs->numAncBytes > 0 ) && ( getBufDescIdx(inBufDesc,IN_ANCILLRY_DATA)!=-1 ) ) { INT idx = getBufDescIdx(inBufDesc,IN_ANCILLRY_DATA); hAacEncoder->extPayload[nExtensions].dataSize = inargs->numAncBytes * 8 ; hAacEncoder->extPayload[nExtensions].pData = (UCHAR*)inBufDesc->bufs[idx]; hAacEncoder->extPayload[nExtensions].dataType = EXT_DATA_ELEMENT; hAacEncoder->extPayload[nExtensions].associatedChElement = -1 ; ancDataExtIdx = nExtensions; nExtensions++; } if ( FDKaacEnc_EncodeFrame( hAacEncoder->hAacEnc, hAacEncoder->hTpEnc, hAacEncoder->inputBuffer, outBytes, hAacEncoder->extPayload ) != AAC_ENC_OK ) { err = AACENC_ENCODE_ERROR; goto bail; } if (ancDataExtIdx >= 0 ) { outargs->numAncBytes = inargs->numAncBytes - (hAacEncoder->extPayload[ancDataExtIdx].dataSize>>3 ); } hAacEncoder->nSamplesRead -= hAacEncoder->nSamplesToRead; if (isSbrActive(&hAacEncoder->aacConfig)) { sbrEncoder_UpdateBuffers(hAacEncoder->hEnvEnc, hAacEncoder->inputBuffer); } if (outBufDesc->numBufs>=1 ) { INT bsIdx = getBufDescIdx(outBufDesc,OUT_BITSTREAM_DATA); INT auIdx = getBufDescIdx(outBufDesc,OUT_AU_SIZES); for (i=0 ,nBsBytes=0 ; i<hAacEncoder->aacConfig.nSubFrames; i++) { nBsBytes += outBytes[i]; if (auIdx!=-1 ) { ((INT*)outBufDesc->bufs[auIdx])[i] = outBytes[i]; } } if ( (bsIdx!=-1 ) && (outBufDesc->bufSizes[bsIdx]>=nBsBytes) ) { FDKmemcpy(outBufDesc->bufs[bsIdx], hAacEncoder->outBuffer, sizeof (UCHAR)*nBsBytes); outargs->numOutBytes = nBsBytes; } else { err = AACENC_ENCODE_ERROR; goto bail; } } return err; }
进一步调用了sbrEncoder_EncodeFrame 和 FDKaacEnc_EncodeFrame 进行编码。
(四)、libFraunhoferAAC库分析 Todo—
\external\aac(libFraunhoferAAC 库)