Loading media/libstagefright/codecs/aacdec/Android.mk +205 −172 Original line number Diff line number Diff line LOCAL_PATH:= $(call my-dir) AAC_LIBRARY = pv ifeq ($(AAC_LIBRARY), fraunhofer) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ SoftAAC2.cpp LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ frameworks/native/include/media/openmax \ external/aac/libAACdec/include \ external/aac/libCDK/include \ external/aac/libMpegTPDec/include \ external/aac/libSBRdec/include \ external/aac/libSYS/include LOCAL_CFLAGS := LOCAL_STATIC_LIBRARIES := \ libAACdec libMpegTPDec libSBRdec libCDK libSYS LOCAL_SHARED_LIBRARIES := \ libstagefright_omx libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_aacdec LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) else # pv LOCAL_SRC_FILES := \ analysis_sub_band.cpp \ apply_ms_synt.cpp \ Loading Loading @@ -178,3 +209,5 @@ LOCAL_MODULE := libstagefright_soft_aacdec LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) endif # $(AAC_LIBRARY) media/libstagefright/codecs/aacdec/SoftAAC2.cpp 0 → 100644 +492 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "SoftAAC2" #include <utils/Log.h> #include "SoftAAC2.h" #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/hexdump.h> #define FILEREAD_MAX_LAYERS 2 namespace android { static Mutex gAACLibraryLock; static int gAACLibraryCount = 0; void initializeAACLibrary() { Mutex::Autolock autoLock(gAACLibraryLock); if (gAACLibraryCount++ == 0) { CDKprolog(); } } void cleanupAACLibrary() { Mutex::Autolock autoLock(gAACLibraryLock); if (--gAACLibraryCount == 0) { CDKepilog(); } } template<class T> static void InitOMXParams(T *params) { params->nSize = sizeof(T); params->nVersion.s.nVersionMajor = 1; params->nVersion.s.nVersionMinor = 0; params->nVersion.s.nRevision = 0; params->nVersion.s.nStep = 0; } SoftAAC2::SoftAAC2( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) : SimpleSoftOMXComponent(name, callbacks, appData, component), mAACDecoder(NULL), mStreamInfo(NULL), mIsADTS(false), mInputBufferCount(0), mSignalledError(false), mAnchorTimeUs(0), mNumSamplesOutput(0), mOutputPortSettingsChange(NONE) { initializeAACLibrary(); initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); } SoftAAC2::~SoftAAC2() { aacDecoder_Close(mAACDecoder); cleanupAACLibrary(); } void SoftAAC2::initPorts() { OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = 0; def.eDir = OMX_DirInput; def.nBufferCountMin = kNumBuffers; def.nBufferCountActual = def.nBufferCountMin; def.nBufferSize = 8192; def.bEnabled = OMX_TRUE; def.bPopulated = OMX_FALSE; def.eDomain = OMX_PortDomainAudio; def.bBuffersContiguous = OMX_FALSE; def.nBufferAlignment = 1; def.format.audio.cMIMEType = const_cast<char *>("audio/aac"); def.format.audio.pNativeRender = NULL; def.format.audio.bFlagErrorConcealment = OMX_FALSE; def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; addPort(def); def.nPortIndex = 1; def.eDir = OMX_DirOutput; def.nBufferCountMin = kNumBuffers; def.nBufferCountActual = def.nBufferCountMin; def.nBufferSize = 8192; def.bEnabled = OMX_TRUE; def.bPopulated = OMX_FALSE; def.eDomain = OMX_PortDomainAudio; def.bBuffersContiguous = OMX_FALSE; def.nBufferAlignment = 2; def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); def.format.audio.pNativeRender = NULL; def.format.audio.bFlagErrorConcealment = OMX_FALSE; def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; addPort(def); } status_t SoftAAC2::initDecoder() { status_t status = UNKNOWN_ERROR; mAACDecoder = aacDecoder_Open(TT_MP4_RAW, /* num layers */ 1); if (mAACDecoder != NULL) { mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder); if (mStreamInfo != NULL) { status = OK; } } return status; } OMX_ERRORTYPE SoftAAC2::internalGetParameter( OMX_INDEXTYPE index, OMX_PTR params) { switch (index) { case OMX_IndexParamAudioAac: { OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; if (aacParams->nPortIndex != 0) { return OMX_ErrorUndefined; } aacParams->nBitRate = 0; aacParams->nAudioBandWidth = 0; aacParams->nAACtools = 0; aacParams->nAACERtools = 0; aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; aacParams->eAACStreamFormat = mIsADTS ? OMX_AUDIO_AACStreamFormatMP4ADTS : OMX_AUDIO_AACStreamFormatMP4FF; aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; if (!isConfigured()) { aacParams->nChannels = 1; aacParams->nSampleRate = 44100; aacParams->nFrameLength = 0; } else { aacParams->nChannels = mStreamInfo->channelConfig; aacParams->nSampleRate = mStreamInfo->aacSampleRate; aacParams->nFrameLength = mStreamInfo->aacSamplesPerFrame; } return OMX_ErrorNone; } case OMX_IndexParamAudioPcm: { OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params; if (pcmParams->nPortIndex != 1) { return OMX_ErrorUndefined; } pcmParams->eNumData = OMX_NumericalDataSigned; pcmParams->eEndian = OMX_EndianBig; pcmParams->bInterleaved = OMX_TRUE; pcmParams->nBitPerSample = 16; pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; if (!isConfigured()) { pcmParams->nChannels = 1; pcmParams->nSamplingRate = 44100; } else { pcmParams->nChannels = mStreamInfo->channelConfig; pcmParams->nSamplingRate = mStreamInfo->sampleRate; } return OMX_ErrorNone; } default: return SimpleSoftOMXComponent::internalGetParameter(index, params); } } OMX_ERRORTYPE SoftAAC2::internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params) { switch (index) { case OMX_IndexParamStandardComponentRole: { const OMX_PARAM_COMPONENTROLETYPE *roleParams = (const OMX_PARAM_COMPONENTROLETYPE *)params; if (strncmp((const char *)roleParams->cRole, "audio_decoder.aac", OMX_MAX_STRINGNAME_SIZE - 1)) { return OMX_ErrorUndefined; } return OMX_ErrorNone; } case OMX_IndexParamAudioAac: { const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params; if (aacParams->nPortIndex != 0) { return OMX_ErrorUndefined; } if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) { mIsADTS = false; } else if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4ADTS) { mIsADTS = true; } else { return OMX_ErrorUndefined; } return OMX_ErrorNone; } case OMX_IndexParamAudioPcm: { const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params; if (pcmParams->nPortIndex != 1) { return OMX_ErrorUndefined; } return OMX_ErrorNone; } default: return SimpleSoftOMXComponent::internalSetParameter(index, params); } } bool SoftAAC2::isConfigured() const { return mInputBufferCount > 0; } void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } UCHAR* inBuffer[FILEREAD_MAX_LAYERS]; UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0}; UINT bytesValid[FILEREAD_MAX_LAYERS] = {0}; AAC_DECODER_ERROR decoderErr; List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); if (portIndex == 0 && mInputBufferCount == 0) { ++mInputBufferCount; BufferInfo *info = *inQueue.begin(); OMX_BUFFERHEADERTYPE *header = info->mHeader; inBuffer[0] = header->pBuffer + header->nOffset; inBufferLength[0] = header->nFilledLen; AAC_DECODER_ERROR decoderErr = aacDecoder_ConfigRaw(mAACDecoder, inBuffer, inBufferLength); if (decoderErr != AAC_DEC_OK) { mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } inQueue.erase(inQueue.begin()); info->mOwnedByUs = false; notifyEmptyBufferDone(header); notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; return; } while (!inQueue.empty() && !outQueue.empty()) { BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); return; } if (inHeader->nOffset == 0) { mAnchorTimeUs = inHeader->nTimeStamp; mNumSamplesOutput = 0; } if (mIsADTS) { // skip 30 bits, aac_frame_length follows. // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; CHECK_GE(inHeader->nFilledLen, 7); bool protectionAbsent = (adtsHeader[1] & 1); unsigned aac_frame_length = ((adtsHeader[3] & 3) << 11) | (adtsHeader[4] << 3) | (adtsHeader[5] >> 5); CHECK_GE(inHeader->nFilledLen, aac_frame_length); size_t headerSize = (protectionAbsent ? 7 : 9); inBuffer[0] = (UCHAR *)adtsHeader + headerSize; inBufferLength[0] = aac_frame_length - headerSize; inHeader->nOffset += headerSize; inHeader->nFilledLen -= headerSize; } else { inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; inBufferLength[0] = inHeader->nFilledLen; } // Fill and decode INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset); bytesValid[0] = inBufferLength[0]; int prevSampleRate = mStreamInfo->sampleRate; decoderErr = aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); decoderErr = aacDecoder_DecodeFrame(mAACDecoder, outBuffer, outHeader->nAllocLen, /* flags */ 0); /* * AAC+/eAAC+ streams can be signalled in two ways: either explicitly * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual * rate system and the sampling rate in the final output is actually * doubled compared with the core AAC decoder sampling rate. * * Explicit signalling is done by explicitly defining SBR audio object * type in the bitstream. Implicit signalling is done by embedding * SBR content in AAC extension payload specific to SBR, and hence * requires an AAC decoder to perform pre-checks on actual audio frames. * * Thus, we could not say for sure whether a stream is * AAC+/eAAC+ until the first data frame is decoded. */ if (decoderErr == AAC_DEC_OK && mInputBufferCount <= 2) { if (mStreamInfo->sampleRate != prevSampleRate) { notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; return; } } size_t numOutBytes = mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; if (decoderErr == AAC_DEC_OK) { UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; inHeader->nFilledLen -= inBufferUsedLength; inHeader->nOffset += inBufferUsedLength; } else { ALOGW("AAC decoder returned error %d, substituting silence", decoderErr); memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes); // Discard input buffer. inHeader->nFilledLen = 0; // fall through } if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) { // We'll only output data if we successfully decoded it or // we've previously decoded valid data, in the latter case // (decode failed) we'll output a silent frame. outHeader->nFilledLen = numOutBytes; outHeader->nFlags = 0; outHeader->nTimeStamp = mAnchorTimeUs + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate; mNumSamplesOutput += mStreamInfo->frameSize; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } if (inHeader->nFilledLen == 0) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } if (decoderErr == AAC_DEC_OK) { ++mInputBufferCount; } } } void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { if (portIndex == 0) { // Make sure that the next buffer output does not still // depend on fragments from the last one decoded. aacDecoder_DecodeFrame(mAACDecoder, NULL, 0, AACDEC_FLUSH); } } void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { if (portIndex != 1) { return; } switch (mOutputPortSettingsChange) { case NONE: break; case AWAITING_DISABLED: { CHECK(!enabled); mOutputPortSettingsChange = AWAITING_ENABLED; break; } default: { CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); CHECK(enabled); mOutputPortSettingsChange = NONE; break; } } } } // namespace android android::SoftOMXComponent *createSoftOMXComponent( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) { return new android::SoftAAC2(name, callbacks, appData, component); } media/libstagefright/codecs/aacdec/SoftAAC2.h 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SOFT_AAC_2_H_ #define SOFT_AAC_2_H_ #include "SimpleSoftOMXComponent.h" #include "aacdecoder_lib.h" namespace android { struct SoftAAC2 : public SimpleSoftOMXComponent { SoftAAC2(const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component); protected: virtual ~SoftAAC2(); virtual OMX_ERRORTYPE internalGetParameter( OMX_INDEXTYPE index, OMX_PTR params); virtual OMX_ERRORTYPE internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params); virtual void onQueueFilled(OMX_U32 portIndex); virtual void onPortFlushCompleted(OMX_U32 portIndex); virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); private: enum { kNumBuffers = 4 }; HANDLE_AACDECODER mAACDecoder; CStreamInfo *mStreamInfo; bool mIsADTS; size_t mInputBufferCount; bool mSignalledError; int64_t mAnchorTimeUs; int64_t mNumSamplesOutput; enum { NONE, AWAITING_DISABLED, AWAITING_ENABLED } mOutputPortSettingsChange; void initPorts(); status_t initDecoder(); bool isConfigured() const; DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2); }; } // namespace android #endif // SOFT_AAC_2_H_ Loading
media/libstagefright/codecs/aacdec/Android.mk +205 −172 Original line number Diff line number Diff line LOCAL_PATH:= $(call my-dir) AAC_LIBRARY = pv ifeq ($(AAC_LIBRARY), fraunhofer) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ SoftAAC2.cpp LOCAL_C_INCLUDES := \ frameworks/av/media/libstagefright/include \ frameworks/native/include/media/openmax \ external/aac/libAACdec/include \ external/aac/libCDK/include \ external/aac/libMpegTPDec/include \ external/aac/libSBRdec/include \ external/aac/libSYS/include LOCAL_CFLAGS := LOCAL_STATIC_LIBRARIES := \ libAACdec libMpegTPDec libSBRdec libCDK libSYS LOCAL_SHARED_LIBRARIES := \ libstagefright_omx libstagefright_foundation libutils LOCAL_MODULE := libstagefright_soft_aacdec LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) else # pv LOCAL_SRC_FILES := \ analysis_sub_band.cpp \ apply_ms_synt.cpp \ Loading Loading @@ -178,3 +209,5 @@ LOCAL_MODULE := libstagefright_soft_aacdec LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) endif # $(AAC_LIBRARY)
media/libstagefright/codecs/aacdec/SoftAAC2.cpp 0 → 100644 +492 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "SoftAAC2" #include <utils/Log.h> #include "SoftAAC2.h" #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/hexdump.h> #define FILEREAD_MAX_LAYERS 2 namespace android { static Mutex gAACLibraryLock; static int gAACLibraryCount = 0; void initializeAACLibrary() { Mutex::Autolock autoLock(gAACLibraryLock); if (gAACLibraryCount++ == 0) { CDKprolog(); } } void cleanupAACLibrary() { Mutex::Autolock autoLock(gAACLibraryLock); if (--gAACLibraryCount == 0) { CDKepilog(); } } template<class T> static void InitOMXParams(T *params) { params->nSize = sizeof(T); params->nVersion.s.nVersionMajor = 1; params->nVersion.s.nVersionMinor = 0; params->nVersion.s.nRevision = 0; params->nVersion.s.nStep = 0; } SoftAAC2::SoftAAC2( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) : SimpleSoftOMXComponent(name, callbacks, appData, component), mAACDecoder(NULL), mStreamInfo(NULL), mIsADTS(false), mInputBufferCount(0), mSignalledError(false), mAnchorTimeUs(0), mNumSamplesOutput(0), mOutputPortSettingsChange(NONE) { initializeAACLibrary(); initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); } SoftAAC2::~SoftAAC2() { aacDecoder_Close(mAACDecoder); cleanupAACLibrary(); } void SoftAAC2::initPorts() { OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = 0; def.eDir = OMX_DirInput; def.nBufferCountMin = kNumBuffers; def.nBufferCountActual = def.nBufferCountMin; def.nBufferSize = 8192; def.bEnabled = OMX_TRUE; def.bPopulated = OMX_FALSE; def.eDomain = OMX_PortDomainAudio; def.bBuffersContiguous = OMX_FALSE; def.nBufferAlignment = 1; def.format.audio.cMIMEType = const_cast<char *>("audio/aac"); def.format.audio.pNativeRender = NULL; def.format.audio.bFlagErrorConcealment = OMX_FALSE; def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; addPort(def); def.nPortIndex = 1; def.eDir = OMX_DirOutput; def.nBufferCountMin = kNumBuffers; def.nBufferCountActual = def.nBufferCountMin; def.nBufferSize = 8192; def.bEnabled = OMX_TRUE; def.bPopulated = OMX_FALSE; def.eDomain = OMX_PortDomainAudio; def.bBuffersContiguous = OMX_FALSE; def.nBufferAlignment = 2; def.format.audio.cMIMEType = const_cast<char *>("audio/raw"); def.format.audio.pNativeRender = NULL; def.format.audio.bFlagErrorConcealment = OMX_FALSE; def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; addPort(def); } status_t SoftAAC2::initDecoder() { status_t status = UNKNOWN_ERROR; mAACDecoder = aacDecoder_Open(TT_MP4_RAW, /* num layers */ 1); if (mAACDecoder != NULL) { mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder); if (mStreamInfo != NULL) { status = OK; } } return status; } OMX_ERRORTYPE SoftAAC2::internalGetParameter( OMX_INDEXTYPE index, OMX_PTR params) { switch (index) { case OMX_IndexParamAudioAac: { OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = (OMX_AUDIO_PARAM_AACPROFILETYPE *)params; if (aacParams->nPortIndex != 0) { return OMX_ErrorUndefined; } aacParams->nBitRate = 0; aacParams->nAudioBandWidth = 0; aacParams->nAACtools = 0; aacParams->nAACERtools = 0; aacParams->eAACProfile = OMX_AUDIO_AACObjectMain; aacParams->eAACStreamFormat = mIsADTS ? OMX_AUDIO_AACStreamFormatMP4ADTS : OMX_AUDIO_AACStreamFormatMP4FF; aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo; if (!isConfigured()) { aacParams->nChannels = 1; aacParams->nSampleRate = 44100; aacParams->nFrameLength = 0; } else { aacParams->nChannels = mStreamInfo->channelConfig; aacParams->nSampleRate = mStreamInfo->aacSampleRate; aacParams->nFrameLength = mStreamInfo->aacSamplesPerFrame; } return OMX_ErrorNone; } case OMX_IndexParamAudioPcm: { OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params; if (pcmParams->nPortIndex != 1) { return OMX_ErrorUndefined; } pcmParams->eNumData = OMX_NumericalDataSigned; pcmParams->eEndian = OMX_EndianBig; pcmParams->bInterleaved = OMX_TRUE; pcmParams->nBitPerSample = 16; pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; if (!isConfigured()) { pcmParams->nChannels = 1; pcmParams->nSamplingRate = 44100; } else { pcmParams->nChannels = mStreamInfo->channelConfig; pcmParams->nSamplingRate = mStreamInfo->sampleRate; } return OMX_ErrorNone; } default: return SimpleSoftOMXComponent::internalGetParameter(index, params); } } OMX_ERRORTYPE SoftAAC2::internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params) { switch (index) { case OMX_IndexParamStandardComponentRole: { const OMX_PARAM_COMPONENTROLETYPE *roleParams = (const OMX_PARAM_COMPONENTROLETYPE *)params; if (strncmp((const char *)roleParams->cRole, "audio_decoder.aac", OMX_MAX_STRINGNAME_SIZE - 1)) { return OMX_ErrorUndefined; } return OMX_ErrorNone; } case OMX_IndexParamAudioAac: { const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams = (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params; if (aacParams->nPortIndex != 0) { return OMX_ErrorUndefined; } if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) { mIsADTS = false; } else if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4ADTS) { mIsADTS = true; } else { return OMX_ErrorUndefined; } return OMX_ErrorNone; } case OMX_IndexParamAudioPcm: { const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params; if (pcmParams->nPortIndex != 1) { return OMX_ErrorUndefined; } return OMX_ErrorNone; } default: return SimpleSoftOMXComponent::internalSetParameter(index, params); } } bool SoftAAC2::isConfigured() const { return mInputBufferCount > 0; } void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { if (mSignalledError || mOutputPortSettingsChange != NONE) { return; } UCHAR* inBuffer[FILEREAD_MAX_LAYERS]; UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0}; UINT bytesValid[FILEREAD_MAX_LAYERS] = {0}; AAC_DECODER_ERROR decoderErr; List<BufferInfo *> &inQueue = getPortQueue(0); List<BufferInfo *> &outQueue = getPortQueue(1); if (portIndex == 0 && mInputBufferCount == 0) { ++mInputBufferCount; BufferInfo *info = *inQueue.begin(); OMX_BUFFERHEADERTYPE *header = info->mHeader; inBuffer[0] = header->pBuffer + header->nOffset; inBufferLength[0] = header->nFilledLen; AAC_DECODER_ERROR decoderErr = aacDecoder_ConfigRaw(mAACDecoder, inBuffer, inBufferLength); if (decoderErr != AAC_DEC_OK) { mSignalledError = true; notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); return; } inQueue.erase(inQueue.begin()); info->mOwnedByUs = false; notifyEmptyBufferDone(header); notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; return; } while (!inQueue.empty() && !outQueue.empty()) { BufferInfo *inInfo = *inQueue.begin(); OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; BufferInfo *outInfo = *outQueue.begin(); OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { inQueue.erase(inQueue.begin()); inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); outHeader->nFilledLen = 0; outHeader->nFlags = OMX_BUFFERFLAG_EOS; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; notifyFillBufferDone(outHeader); return; } if (inHeader->nOffset == 0) { mAnchorTimeUs = inHeader->nTimeStamp; mNumSamplesOutput = 0; } if (mIsADTS) { // skip 30 bits, aac_frame_length follows. // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll????? const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset; CHECK_GE(inHeader->nFilledLen, 7); bool protectionAbsent = (adtsHeader[1] & 1); unsigned aac_frame_length = ((adtsHeader[3] & 3) << 11) | (adtsHeader[4] << 3) | (adtsHeader[5] >> 5); CHECK_GE(inHeader->nFilledLen, aac_frame_length); size_t headerSize = (protectionAbsent ? 7 : 9); inBuffer[0] = (UCHAR *)adtsHeader + headerSize; inBufferLength[0] = aac_frame_length - headerSize; inHeader->nOffset += headerSize; inHeader->nFilledLen -= headerSize; } else { inBuffer[0] = inHeader->pBuffer + inHeader->nOffset; inBufferLength[0] = inHeader->nFilledLen; } // Fill and decode INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset); bytesValid[0] = inBufferLength[0]; int prevSampleRate = mStreamInfo->sampleRate; decoderErr = aacDecoder_Fill(mAACDecoder, inBuffer, inBufferLength, bytesValid); decoderErr = aacDecoder_DecodeFrame(mAACDecoder, outBuffer, outHeader->nAllocLen, /* flags */ 0); /* * AAC+/eAAC+ streams can be signalled in two ways: either explicitly * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual * rate system and the sampling rate in the final output is actually * doubled compared with the core AAC decoder sampling rate. * * Explicit signalling is done by explicitly defining SBR audio object * type in the bitstream. Implicit signalling is done by embedding * SBR content in AAC extension payload specific to SBR, and hence * requires an AAC decoder to perform pre-checks on actual audio frames. * * Thus, we could not say for sure whether a stream is * AAC+/eAAC+ until the first data frame is decoded. */ if (decoderErr == AAC_DEC_OK && mInputBufferCount <= 2) { if (mStreamInfo->sampleRate != prevSampleRate) { notify(OMX_EventPortSettingsChanged, 1, 0, NULL); mOutputPortSettingsChange = AWAITING_DISABLED; return; } } size_t numOutBytes = mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels; if (decoderErr == AAC_DEC_OK) { UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0]; inHeader->nFilledLen -= inBufferUsedLength; inHeader->nOffset += inBufferUsedLength; } else { ALOGW("AAC decoder returned error %d, substituting silence", decoderErr); memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes); // Discard input buffer. inHeader->nFilledLen = 0; // fall through } if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) { // We'll only output data if we successfully decoded it or // we've previously decoded valid data, in the latter case // (decode failed) we'll output a silent frame. outHeader->nFilledLen = numOutBytes; outHeader->nFlags = 0; outHeader->nTimeStamp = mAnchorTimeUs + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate; mNumSamplesOutput += mStreamInfo->frameSize; outInfo->mOwnedByUs = false; outQueue.erase(outQueue.begin()); outInfo = NULL; notifyFillBufferDone(outHeader); outHeader = NULL; } if (inHeader->nFilledLen == 0) { inInfo->mOwnedByUs = false; inQueue.erase(inQueue.begin()); inInfo = NULL; notifyEmptyBufferDone(inHeader); inHeader = NULL; } if (decoderErr == AAC_DEC_OK) { ++mInputBufferCount; } } } void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) { if (portIndex == 0) { // Make sure that the next buffer output does not still // depend on fragments from the last one decoded. aacDecoder_DecodeFrame(mAACDecoder, NULL, 0, AACDEC_FLUSH); } } void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) { if (portIndex != 1) { return; } switch (mOutputPortSettingsChange) { case NONE: break; case AWAITING_DISABLED: { CHECK(!enabled); mOutputPortSettingsChange = AWAITING_ENABLED; break; } default: { CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED); CHECK(enabled); mOutputPortSettingsChange = NONE; break; } } } } // namespace android android::SoftOMXComponent *createSoftOMXComponent( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) { return new android::SoftAAC2(name, callbacks, appData, component); }
media/libstagefright/codecs/aacdec/SoftAAC2.h 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SOFT_AAC_2_H_ #define SOFT_AAC_2_H_ #include "SimpleSoftOMXComponent.h" #include "aacdecoder_lib.h" namespace android { struct SoftAAC2 : public SimpleSoftOMXComponent { SoftAAC2(const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component); protected: virtual ~SoftAAC2(); virtual OMX_ERRORTYPE internalGetParameter( OMX_INDEXTYPE index, OMX_PTR params); virtual OMX_ERRORTYPE internalSetParameter( OMX_INDEXTYPE index, const OMX_PTR params); virtual void onQueueFilled(OMX_U32 portIndex); virtual void onPortFlushCompleted(OMX_U32 portIndex); virtual void onPortEnableCompleted(OMX_U32 portIndex, bool enabled); private: enum { kNumBuffers = 4 }; HANDLE_AACDECODER mAACDecoder; CStreamInfo *mStreamInfo; bool mIsADTS; size_t mInputBufferCount; bool mSignalledError; int64_t mAnchorTimeUs; int64_t mNumSamplesOutput; enum { NONE, AWAITING_DISABLED, AWAITING_ENABLED } mOutputPortSettingsChange; void initPorts(); status_t initDecoder(); bool isConfigured() const; DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2); }; } // namespace android #endif // SOFT_AAC_2_H_