| /* |
| * Copyright (C) 2011 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. |
| */ |
| /** |
| ************************************************************************* |
| * @file VideoEditorAudioDecoder.cpp |
| * @brief StageFright shell Audio Decoder |
| ************************************************************************* |
| */ |
| |
| #define LOG_NDEBUG 1 |
| #define LOG_TAG "VIDEOEDITOR_AUDIODECODER" |
| |
| #include "M4OSA_Debug.h" |
| #include "VideoEditorAudioDecoder.h" |
| #include "VideoEditorUtils.h" |
| #include "M4MCS_InternalTypes.h" |
| |
| #include "utils/Log.h" |
| #include "utils/Vector.h" |
| #include <media/stagefright/foundation/ADebug.h> |
| #include <media/stagefright/MediaSource.h> |
| #include <media/stagefright/MediaDefs.h> |
| #include <media/stagefright/MetaData.h> |
| #include <media/stagefright/OMXClient.h> |
| #include <media/stagefright/OMXCodec.h> |
| |
| /******************** |
| * DEFINITIONS * |
| ********************/ |
| // Version |
| #define VIDEOEDITOR_AUDIO_DECODER_VERSION_MAJOR 1 |
| #define VIDEOEDITOR_AUDIO_DECODER_VERSION_MINOR 0 |
| #define VIDEOEDITOR_AUDIO_DECODER_VERSION_REV 0 |
| |
| // Force using software decoder as engine does not support prefetch |
| #define VIDEOEDITOR_FORCECODEC kSoftwareCodecsOnly |
| |
| namespace android { |
| |
| struct VideoEditorAudioDecoderSource : public MediaSource { |
| public: |
| static sp<VideoEditorAudioDecoderSource> Create( |
| const sp<MetaData>& format, void *decoderShellContext); |
| virtual status_t start(MetaData *params = NULL); |
| virtual status_t stop(); |
| virtual sp<MetaData> getFormat(); |
| virtual status_t read(MediaBuffer **buffer, |
| const ReadOptions *options = NULL); |
| virtual void storeBuffer(MediaBuffer *buffer); |
| |
| protected: |
| virtual ~VideoEditorAudioDecoderSource(); |
| |
| private: |
| enum State { |
| CREATED, |
| STARTED, |
| ERROR |
| }; |
| VideoEditorAudioDecoderSource(const sp<MetaData>& format, |
| void *decoderShellContext); |
| sp<MetaData> mFormat; |
| Vector<MediaBuffer*> mBuffers; |
| Mutex mLock; // protects mBuffers |
| bool mIsEOS; |
| State mState; |
| void* mDecShellContext; |
| // Don't call me. |
| VideoEditorAudioDecoderSource(const VideoEditorAudioDecoderSource&); |
| VideoEditorAudioDecoderSource& operator=( |
| const VideoEditorAudioDecoderSource &); |
| }; |
| |
| /** |
| ****************************************************************************** |
| * structure VideoEditorAudioDecoder_Context |
| * @brief This structure defines the context of the StageFright audio decoder |
| * shell |
| ****************************************************************************** |
| */ |
| |
| typedef struct { |
| M4AD_Type mDecoderType; |
| M4_AudioStreamHandler* mAudioStreamHandler; |
| sp<VideoEditorAudioDecoderSource> mDecoderSource; |
| OMXClient mClient; |
| sp<MediaSource> mDecoder; |
| int32_t mNbOutputChannels; |
| uint32_t mNbInputFrames; |
| uint32_t mNbOutputFrames; |
| M4READER_DataInterface *m_pReader; |
| M4_AccessUnit* m_pNextAccessUnitToDecode; |
| M4OSA_ERR readerErrCode; |
| int32_t timeStampMs; |
| |
| } VideoEditorAudioDecoder_Context; |
| |
| sp<VideoEditorAudioDecoderSource> VideoEditorAudioDecoderSource::Create( |
| const sp<MetaData>& format, void *decoderShellContext) { |
| |
| sp<VideoEditorAudioDecoderSource> aSource = |
| new VideoEditorAudioDecoderSource(format, decoderShellContext); |
| |
| return aSource; |
| } |
| |
| VideoEditorAudioDecoderSource::VideoEditorAudioDecoderSource( |
| const sp<MetaData>& format, void* decoderShellContext): |
| mFormat(format), |
| mIsEOS(false), |
| mState(CREATED), |
| mDecShellContext(decoderShellContext) { |
| } |
| |
| VideoEditorAudioDecoderSource::~VideoEditorAudioDecoderSource() { |
| |
| if( STARTED == mState ) { |
| stop(); |
| } |
| } |
| |
| status_t VideoEditorAudioDecoderSource::start(MetaData *meta) { |
| status_t err = OK; |
| |
| if( CREATED != mState ) { |
| ALOGV("VideoEditorAudioDecoderSource::start: invalid state %d", mState); |
| return UNKNOWN_ERROR; |
| } |
| |
| mState = STARTED; |
| |
| cleanUp: |
| ALOGV("VideoEditorAudioDecoderSource::start END (0x%x)", err); |
| return err; |
| } |
| |
| status_t VideoEditorAudioDecoderSource::stop() { |
| Mutex::Autolock autolock(mLock); |
| status_t err = OK; |
| |
| ALOGV("VideoEditorAudioDecoderSource::stop begin"); |
| |
| if( STARTED != mState ) { |
| ALOGV("VideoEditorAudioDecoderSource::stop: invalid state %d", mState); |
| return UNKNOWN_ERROR; |
| } |
| |
| if (!mBuffers.empty()) { |
| int n = mBuffers.size(); |
| for (int i = 0; i < n; i++) { |
| mBuffers.itemAt(i)->release(); |
| } |
| ALOGW("VideoEditorAudioDecoderSource::stop : %d buffer remained", n); |
| mBuffers.clear(); |
| } |
| |
| mState = CREATED; |
| |
| ALOGV("VideoEditorAudioDecoderSource::stop END (0x%x)", err); |
| return err; |
| } |
| |
| sp<MetaData> VideoEditorAudioDecoderSource::getFormat() { |
| |
| ALOGV("VideoEditorAudioDecoderSource::getFormat"); |
| return mFormat; |
| } |
| |
| static MediaBuffer* readBufferFromReader( |
| VideoEditorAudioDecoder_Context* pDecContext) { |
| M4OSA_ERR lerr = M4NO_ERROR; |
| M4_AccessUnit* pAccessUnit = pDecContext->m_pNextAccessUnitToDecode; |
| |
| // Get next AU from reader. |
| lerr = pDecContext->m_pReader->m_pFctGetNextAu( |
| pDecContext->m_pReader->m_readerContext, |
| (M4_StreamHandler*)pDecContext->mAudioStreamHandler, |
| pAccessUnit); |
| |
| if (lerr == M4WAR_NO_MORE_AU) { |
| ALOGV("readBufferFromReader : EOS"); |
| return NULL; |
| } |
| |
| pDecContext->timeStampMs = pAccessUnit->m_CTS; |
| |
| MediaBuffer* newBuffer = new MediaBuffer((size_t)pAccessUnit->m_size); |
| memcpy((void *)((M4OSA_Int8*)newBuffer->data() + newBuffer->range_offset()), |
| (void *)pAccessUnit->m_dataAddress, pAccessUnit->m_size); |
| newBuffer->meta_data()->setInt64(kKeyTime, (pAccessUnit->m_CTS * 1000LL)); |
| return newBuffer; |
| } |
| |
| status_t VideoEditorAudioDecoderSource::read(MediaBuffer **buffer, |
| const ReadOptions *options) { |
| Mutex::Autolock autolock(mLock); |
| MediaSource::ReadOptions readOptions; |
| |
| VideoEditorAudioDecoder_Context* pDecContext = |
| (VideoEditorAudioDecoder_Context *)mDecShellContext; |
| |
| if ( STARTED != mState ) { |
| ALOGV("VideoEditorAudioDecoderSource::read invalid state %d", mState); |
| return UNKNOWN_ERROR; |
| } |
| |
| // Get a buffer from the reader if we don't have any |
| if(mBuffers.empty()) { |
| MediaBuffer* newBuffer = readBufferFromReader(pDecContext); |
| if (!newBuffer) { |
| *buffer = NULL; |
| pDecContext->readerErrCode = M4WAR_NO_MORE_AU; |
| return ERROR_END_OF_STREAM; |
| } |
| mBuffers.push(newBuffer); |
| } |
| *buffer = mBuffers.itemAt(0); |
| mBuffers.removeAt(0); |
| |
| return OK; |
| } |
| |
| void VideoEditorAudioDecoderSource::storeBuffer(MediaBuffer *buffer) { |
| Mutex::Autolock autolock(mLock); |
| VideoEditorAudioDecoder_Context* pDecContext = |
| (VideoEditorAudioDecoder_Context *)mDecShellContext; |
| |
| ALOGV("VideoEditorAudioDecoderSource::storeBuffer begin"); |
| |
| // If the user didn't give us a buffer, get it from the reader. |
| if(buffer == NULL) { |
| MediaBuffer* newBuffer = readBufferFromReader(pDecContext); |
| if (!newBuffer) { |
| pDecContext->readerErrCode = M4WAR_NO_MORE_AU; |
| return; |
| } |
| buffer = newBuffer; |
| } |
| |
| mBuffers.push(buffer); |
| ALOGV("VideoEditorAudioDecoderSource::storeBuffer END"); |
| } |
| |
| /******************** |
| * TOOLS * |
| ********************/ |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getBits(M4OSA_Int8* pData, |
| M4OSA_UInt32 dataSize, M4OSA_UInt8 nbBits, M4OSA_Int32* pResult, |
| M4OSA_UInt32* pOffset) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| M4OSA_UInt32 startByte = 0; |
| M4OSA_UInt32 startBit = 0; |
| M4OSA_UInt32 endByte = 0; |
| M4OSA_UInt32 endBit = 0; |
| M4OSA_UInt32 currentByte = 0; |
| M4OSA_UInt32 result = 0; |
| M4OSA_UInt32 ui32Tmp = 0; |
| M4OSA_UInt32 ui32Mask = 0; |
| |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pData, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pOffset, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK(32 >= nbBits, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK((*pOffset + nbBits) <= 8*dataSize, M4ERR_PARAMETER); |
| |
| ALOGV("VideoEditorAudioDecoder_getBits begin"); |
| |
| startByte = (*pOffset) >> 3; |
| endByte = (*pOffset + nbBits) >> 3; |
| startBit = (*pOffset) % 8; |
| endBit = (*pOffset + nbBits) % 8; |
| currentByte = startByte; |
| |
| // Extract the requested nunber of bits from memory |
| while( currentByte <= endByte) { |
| ui32Mask = 0x000000FF; |
| if( currentByte == startByte ) { |
| ui32Mask >>= startBit; |
| } |
| ui32Tmp = ui32Mask & ((M4OSA_UInt32)pData[currentByte]); |
| if( currentByte == endByte ) { |
| ui32Tmp >>= (8-endBit); |
| result <<= endBit; |
| } else { |
| result <<= 8; |
| } |
| result |= ui32Tmp; |
| currentByte++; |
| } |
| |
| *pResult = result; |
| *pOffset += nbBits; |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_getBits no error"); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_getBits ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_getBits end"); |
| return err; |
| } |
| |
| |
| #define FREQ_TABLE_SIZE 16 |
| const M4OSA_UInt32 AD_AAC_FREQ_TABLE[FREQ_TABLE_SIZE] = |
| {96000, 88200, 64000, 48000, 44100, |
| 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0}; |
| |
| |
| M4OSA_ERR VideoEditorAudioDecoder_parse_AAC_DSI(M4OSA_Int8* pDSI, |
| M4OSA_UInt32 dsiSize, AAC_DEC_STREAM_PROPS* pProperties) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| M4OSA_UInt32 offset = 0; |
| M4OSA_Int32 result = 0; |
| |
| ALOGV("VideoEditorAudioDecoder_parse_AAC_DSI begin"); |
| |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pDSI, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pProperties, M4ERR_PARAMETER); |
| |
| // Get the object type |
| err = VideoEditorAudioDecoder_getBits(pDSI, dsiSize, 5, &result, &offset); |
| VIDEOEDITOR_CHECK(M4NO_ERROR == err, err); |
| switch( result ) { |
| case 2: |
| /* Audio Object Type is 2 (AAC Low Complexity) */ |
| pProperties->aPSPresent = 0; |
| pProperties->aSBRPresent = 0; |
| break; |
| case 5: |
| /* Audio Object Type is 5 (Spectral Band Replication) */ |
| pProperties->aPSPresent = 0; |
| pProperties->aSBRPresent = 1; |
| break; |
| case 29: |
| /* Audio Object Type is 29 (Parametric Stereo) */ |
| pProperties->aPSPresent = 1; |
| pProperties->aSBRPresent = 1; |
| break; |
| default: |
| ALOGV("parse_AAC_DSI ERROR : object type %d is not supported", |
| result); |
| VIDEOEDITOR_CHECK(!"invalid AAC object type", M4ERR_BAD_OPTION_ID); |
| break; |
| } |
| pProperties->aAudioObjectType = (M4OSA_Int32)result; |
| |
| // Get the frequency index |
| err = VideoEditorAudioDecoder_getBits(pDSI, dsiSize, 4, &result, &offset); |
| VIDEOEDITOR_CHECK(M4NO_ERROR == err, err); |
| VIDEOEDITOR_CHECK((0 <= result) && (FREQ_TABLE_SIZE > result), |
| M4ERR_PARAMETER); |
| pProperties->aSampFreq = AD_AAC_FREQ_TABLE[result]; |
| pProperties->aExtensionSampFreq = 0; |
| |
| // Get the number of channels |
| err = VideoEditorAudioDecoder_getBits(pDSI, dsiSize, 4, &result, &offset); |
| VIDEOEDITOR_CHECK(M4NO_ERROR == err, err); |
| pProperties->aNumChan = (M4OSA_UInt32)result; |
| |
| // Set the max PCM samples per channel |
| pProperties->aMaxPCMSamplesPerCh = (pProperties->aSBRPresent) ? 2048 : 1024; |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_parse_AAC_DSI no error"); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_parse_AAC_DSI ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_parse_AAC_DSI end"); |
| return err; |
| } |
| |
| /******************** |
| * ENGINE INTERFACE * |
| ********************/ |
| |
| M4OSA_ERR VideoEditorAudioDecoder_destroy(M4AD_Context pContext) { |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL; |
| |
| ALOGV("VideoEditorAudioDecoder_destroy begin"); |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); |
| |
| pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext; |
| |
| // Stop the graph |
| if( M4OSA_NULL != pDecoderContext->mDecoder.get() ) { |
| pDecoderContext->mDecoder->stop(); |
| } |
| |
| // Destroy the graph |
| pDecoderContext->mDecoderSource.clear(); |
| pDecoderContext->mDecoder.clear(); |
| pDecoderContext->mClient.disconnect(); |
| |
| SAFE_FREE(pDecoderContext); |
| pContext = M4OSA_NULL; |
| ALOGV("VideoEditorAudioDecoder_destroy : DONE"); |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_destroy no error"); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_destroy ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_destroy : end"); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_create(M4AD_Type decoderType, |
| M4AD_Context* pContext, M4_AudioStreamHandler* pStreamHandler, |
| void* pUserData) { |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL; |
| AAC_DEC_STREAM_PROPS aacProperties; |
| status_t result = OK; |
| sp<MetaData> decoderMetaData = NULL; |
| const char* mime = NULL; |
| uint32_t codecFlags = 0; |
| |
| ALOGV("VideoEditorAudioDecoder_create begin: decoderType %d", decoderType); |
| |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pStreamHandler, M4ERR_PARAMETER); |
| |
| // Context allocation & initialization |
| SAFE_MALLOC(pDecoderContext, VideoEditorAudioDecoder_Context, 1, |
| "AudioDecoder"); |
| pDecoderContext->mDecoderType = decoderType; |
| pDecoderContext->mAudioStreamHandler = pStreamHandler; |
| |
| pDecoderContext->mNbInputFrames = 0; |
| pDecoderContext->mNbOutputFrames = 0; |
| pDecoderContext->readerErrCode = M4NO_ERROR; |
| pDecoderContext->timeStampMs = -1; |
| |
| ALOGV("VideoEditorAudioDecoder_create : maxAUSize %d", |
| pDecoderContext->mAudioStreamHandler->m_basicProperties.m_maxAUSize); |
| |
| // Create the meta data for the decoder |
| decoderMetaData = new MetaData; |
| switch( pDecoderContext->mDecoderType ) { |
| case M4AD_kTypeAMRNB: |
| // StageFright parameters |
| mime = MEDIA_MIMETYPE_AUDIO_AMR_NB; |
| // Engine parameters |
| pDecoderContext->mAudioStreamHandler->m_byteFrameLength = 160; |
| // Number of bytes per sample |
| pDecoderContext->mAudioStreamHandler->m_byteSampleSize = 2; |
| pDecoderContext->mAudioStreamHandler->m_samplingFrequency = 8000; |
| pDecoderContext->mAudioStreamHandler->m_nbChannels = 1; |
| break; |
| |
| case M4AD_kTypeAMRWB: |
| // StageFright parameters |
| mime = MEDIA_MIMETYPE_AUDIO_AMR_WB; |
| |
| pDecoderContext->mAudioStreamHandler->m_byteFrameLength = 160; |
| // Number of bytes per sample |
| pDecoderContext->mAudioStreamHandler->m_byteSampleSize = 2; |
| pDecoderContext->mAudioStreamHandler->m_samplingFrequency = 16000; |
| pDecoderContext->mAudioStreamHandler->m_nbChannels = 1; |
| break; |
| |
| case M4AD_kTypeAAC: |
| // Reject ADTS & ADIF (or any incorrect type) |
| VIDEOEDITOR_CHECK(M4DA_StreamTypeAudioAac == |
| pDecoderContext->mAudioStreamHandler->\ |
| m_basicProperties.m_streamType,M4ERR_PARAMETER); |
| |
| // StageFright parameters |
| mime = MEDIA_MIMETYPE_AUDIO_AAC; |
| |
| decoderMetaData->setData(kKeyESDS, kTypeESDS, |
| pStreamHandler->m_basicProperties.m_pESDSInfo, |
| pStreamHandler->m_basicProperties.m_ESDSInfoSize); |
| |
| // Engine parameters |
| // Retrieve sampling frequency and number of channels from the DSI |
| err = VideoEditorAudioDecoder_parse_AAC_DSI( |
| (M4OSA_Int8*)pStreamHandler->m_basicProperties.\ |
| m_pDecoderSpecificInfo, |
| pStreamHandler->m_basicProperties.m_decoderSpecificInfoSize, |
| &aacProperties); |
| |
| VIDEOEDITOR_CHECK(M4NO_ERROR == err, err); |
| pDecoderContext->mAudioStreamHandler->m_byteFrameLength = 1024; |
| // Number of bytes per sample |
| pDecoderContext->mAudioStreamHandler->m_byteSampleSize = 2; |
| pDecoderContext->mAudioStreamHandler->m_samplingFrequency = |
| aacProperties.aSampFreq; |
| pDecoderContext->mAudioStreamHandler->m_nbChannels = |
| aacProperties.aNumChan; |
| |
| // Copy the stream properties into userdata |
| if( M4OSA_NULL != pUserData ) { |
| memcpy((void *)pUserData, |
| (void *)&aacProperties, |
| sizeof(AAC_DEC_STREAM_PROPS)); |
| } |
| break; |
| |
| case M4AD_kTypeMP3: |
| // StageFright parameters |
| mime = MEDIA_MIMETYPE_AUDIO_MPEG; |
| break; |
| |
| default: |
| VIDEOEDITOR_CHECK(!"AudioDecoder_open : incorrect input format", |
| M4ERR_STATE); |
| break; |
| } |
| decoderMetaData->setCString(kKeyMIMEType, mime); |
| decoderMetaData->setInt32(kKeySampleRate, |
| (int32_t)pDecoderContext->mAudioStreamHandler->m_samplingFrequency); |
| decoderMetaData->setInt32(kKeyChannelCount, |
| pDecoderContext->mAudioStreamHandler->m_nbChannels); |
| decoderMetaData->setInt64(kKeyDuration, |
| (int64_t)pDecoderContext->mAudioStreamHandler->\ |
| m_basicProperties.m_duration); |
| |
| // Create the decoder source |
| pDecoderContext->mDecoderSource = VideoEditorAudioDecoderSource::Create( |
| decoderMetaData, (void *)pDecoderContext); |
| VIDEOEDITOR_CHECK(NULL != pDecoderContext->mDecoderSource.get(), |
| M4ERR_STATE); |
| |
| // Connect to the OMX client |
| result = pDecoderContext->mClient.connect(); |
| VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE); |
| |
| // Create the OMX codec |
| #ifdef VIDEOEDITOR_FORCECODEC |
| codecFlags |= OMXCodec::VIDEOEDITOR_FORCECODEC; |
| #endif /* VIDEOEDITOR_FORCECODEC */ |
| |
| pDecoderContext->mDecoder = OMXCodec::Create(pDecoderContext->\ |
| mClient.interface(), |
| decoderMetaData, false, pDecoderContext->mDecoderSource, NULL, |
| codecFlags); |
| VIDEOEDITOR_CHECK(NULL != pDecoderContext->mDecoder.get(), M4ERR_STATE); |
| |
| // Get the output channels, the decoder might overwrite the input metadata |
| pDecoderContext->mDecoder->getFormat()->findInt32(kKeyChannelCount, |
| &pDecoderContext->mNbOutputChannels); |
| ALOGV("VideoEditorAudioDecoder_create : output chan %d", |
| pDecoderContext->mNbOutputChannels); |
| |
| // Start the decoder |
| result = pDecoderContext->mDecoder->start(); |
| VIDEOEDITOR_CHECK(OK == result, M4ERR_STATE); |
| |
| *pContext = pDecoderContext; |
| ALOGV("VideoEditorAudioDecoder_create : DONE"); |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_create no error"); |
| } else { |
| VideoEditorAudioDecoder_destroy(pDecoderContext); |
| *pContext = M4OSA_NULL; |
| ALOGV("VideoEditorAudioDecoder_create ERROR 0x%X", err); |
| } |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_create_AAC(M4AD_Context* pContext, |
| M4_AudioStreamHandler* pStreamHandler, void* pUserData) { |
| |
| return VideoEditorAudioDecoder_create( |
| M4AD_kTypeAAC, pContext, pStreamHandler,pUserData); |
| } |
| |
| |
| M4OSA_ERR VideoEditorAudioDecoder_create_AMRNB(M4AD_Context* pContext, |
| M4_AudioStreamHandler* pStreamHandler, void* pUserData) { |
| |
| return VideoEditorAudioDecoder_create( |
| M4AD_kTypeAMRNB, pContext, pStreamHandler, pUserData); |
| } |
| |
| |
| M4OSA_ERR VideoEditorAudioDecoder_create_AMRWB(M4AD_Context* pContext, |
| M4_AudioStreamHandler* pStreamHandler, void* pUserData) { |
| |
| return VideoEditorAudioDecoder_create( |
| M4AD_kTypeAMRWB, pContext, pStreamHandler, pUserData); |
| } |
| |
| |
| M4OSA_ERR VideoEditorAudioDecoder_create_MP3(M4AD_Context* pContext, |
| M4_AudioStreamHandler* pStreamHandler, void* pUserData) { |
| |
| return VideoEditorAudioDecoder_create( |
| M4AD_kTypeMP3, pContext, pStreamHandler, pUserData); |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_processInputBuffer( |
| M4AD_Context pContext, M4AD_Buffer* pInputBuffer) { |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL; |
| MediaBuffer* buffer = NULL; |
| |
| ALOGV("VideoEditorAudioDecoder_processInputBuffer begin"); |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); |
| |
| |
| pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext; |
| |
| if( M4OSA_NULL != pInputBuffer ) { |
| buffer = new MediaBuffer((size_t)pInputBuffer->m_bufferSize); |
| memcpy((void *)((M4OSA_Int8*)buffer->data() + buffer->range_offset()), |
| (void *)pInputBuffer->m_dataAddress, pInputBuffer->m_bufferSize); |
| buffer->meta_data()->setInt64(kKeyTime, pInputBuffer->m_timeStampUs); |
| } |
| pDecoderContext->mDecoderSource->storeBuffer(buffer); |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_processInputBuffer no error"); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_processInputBuffer ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_processInputBuffer end"); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_processOutputBuffer(M4AD_Context pContext, |
| MediaBuffer* buffer, M4AD_Buffer* pOuputBuffer) { |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL; |
| int32_t i32Tmp = 0; |
| int64_t i64Tmp = 0; |
| status_t result = OK; |
| |
| ALOGV("VideoEditorAudioDecoder_processOutputBuffer begin"); |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK(M4OSA_NULL != buffer, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pOuputBuffer, M4ERR_PARAMETER); |
| |
| pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext; |
| |
| // Process the returned data |
| if( 0 == buffer->range_length() ) { |
| // Decoder has no data yet, nothing unusual |
| goto cleanUp; |
| } |
| |
| pDecoderContext->mNbOutputFrames++; |
| |
| if( pDecoderContext->mAudioStreamHandler->m_nbChannels == |
| (M4OSA_UInt32)pDecoderContext->mNbOutputChannels ) { |
| // Just copy the PCMs |
| pOuputBuffer->m_bufferSize = (M4OSA_UInt32)buffer->range_length(); |
| memcpy((void *)pOuputBuffer->m_dataAddress, |
| (void *)(((M4OSA_MemAddr8)buffer->data())+buffer->range_offset()), |
| buffer->range_length()); |
| } else if( pDecoderContext->mAudioStreamHandler->m_nbChannels < |
| (M4OSA_UInt32)pDecoderContext->mNbOutputChannels ) { |
| // The decoder forces stereo output, downsample |
| pOuputBuffer->m_bufferSize = (M4OSA_UInt32)(buffer->range_length()/2); |
| M4OSA_Int16* pDataIn = ((M4OSA_Int16*)buffer->data()) + |
| buffer->range_offset(); |
| M4OSA_Int16* pDataOut = (M4OSA_Int16*)pOuputBuffer->m_dataAddress; |
| M4OSA_Int16* pDataEnd = pDataIn + \ |
| (buffer->range_length()/sizeof(M4OSA_Int16)); |
| while( pDataIn < pDataEnd ) { |
| *pDataOut = *pDataIn; |
| pDataIn+=2; |
| pDataOut++; |
| } |
| } else { |
| // The decoder forces mono output, not supported |
| VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER); |
| } |
| |
| cleanUp: |
| // Release the buffer |
| buffer->release(); |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_processOutputBuffer no error"); |
| } else { |
| pOuputBuffer->m_bufferSize = 0; |
| ALOGV("VideoEditorAudioDecoder_processOutputBuffer ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_processOutputBuffer end"); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_step(M4AD_Context pContext, |
| M4AD_Buffer* pInputBuffer, M4AD_Buffer* pOutputBuffer, |
| M4OSA_Bool bJump) { |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL; |
| status_t result = OK; |
| MediaBuffer* outputBuffer = NULL; |
| |
| ALOGV("VideoEditorAudioDecoder_step begin"); |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); |
| |
| pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext; |
| pDecoderContext->mNbInputFrames++; |
| |
| // Push the input buffer to the decoder source |
| err = VideoEditorAudioDecoder_processInputBuffer(pDecoderContext, |
| pInputBuffer); |
| VIDEOEDITOR_CHECK(M4NO_ERROR == err, err); |
| |
| // Read |
| result = pDecoderContext->mDecoder->read(&outputBuffer, NULL); |
| if (INFO_FORMAT_CHANGED == result) { |
| ALOGV("VideoEditorAudioDecoder_step: Audio decoder \ |
| returned INFO_FORMAT_CHANGED"); |
| CHECK(outputBuffer == NULL); |
| sp<MetaData> meta = pDecoderContext->mDecoder->getFormat(); |
| int32_t sampleRate, channelCount; |
| |
| CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); |
| CHECK(meta->findInt32(kKeyChannelCount, &channelCount)); |
| ALOGV("VideoEditorAudioDecoder_step: samplingFreq = %d", sampleRate); |
| ALOGV("VideoEditorAudioDecoder_step: channelCnt = %d", channelCount); |
| pDecoderContext->mAudioStreamHandler->m_samplingFrequency = |
| (uint32_t)sampleRate; |
| pDecoderContext->mAudioStreamHandler->m_nbChannels = |
| (uint32_t)channelCount; |
| pDecoderContext->mNbOutputChannels = channelCount; |
| |
| return M4WAR_INFO_FORMAT_CHANGE; |
| } else if (ERROR_END_OF_STREAM == result) { |
| ALOGV("VideoEditorAudioDecoder_step: Audio decoder \ |
| returned ERROR_END_OF_STREAM"); |
| pDecoderContext->readerErrCode = M4WAR_NO_MORE_AU; |
| return M4WAR_NO_MORE_AU; |
| } else if (OK != result) { |
| return M4ERR_STATE; |
| } |
| |
| // Convert the PCM buffer |
| err = VideoEditorAudioDecoder_processOutputBuffer(pDecoderContext, |
| outputBuffer, pOutputBuffer); |
| VIDEOEDITOR_CHECK(M4NO_ERROR == err, err); |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_step no error"); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_step ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_step end"); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getVersion(M4_VersionInfo* pVersionInfo) { |
| M4OSA_ERR err = M4NO_ERROR; |
| |
| ALOGV("VideoEditorAudioDecoder_getVersion begin"); |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pVersionInfo, M4ERR_PARAMETER); |
| |
| pVersionInfo->m_major = VIDEOEDITOR_AUDIO_DECODER_VERSION_MAJOR; |
| pVersionInfo->m_minor = VIDEOEDITOR_AUDIO_DECODER_VERSION_MINOR; |
| pVersionInfo->m_revision = VIDEOEDITOR_AUDIO_DECODER_VERSION_REV; |
| pVersionInfo->m_structSize = sizeof(M4_VersionInfo); |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_getVersion no error"); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_getVersion ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_getVersion end"); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_setOption(M4AD_Context pContext, |
| M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL; |
| |
| ALOGV("VideoEditorAudioDecoder_setOption begin 0x%X", optionID); |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); |
| |
| pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext; |
| |
| switch( optionID ) { |
| case static_cast<M4OSA_UInt32>(M4AD_kOptionID_UserParam): |
| ALOGV("VideoEditorAudioDecodersetOption UserParam is not supported"); |
| err = M4ERR_NOT_IMPLEMENTED; |
| break; |
| |
| case M4AD_kOptionID_3gpReaderInterface: |
| ALOGV("VideoEditorAudioDecodersetOption 3gpReaderInterface"); |
| pDecoderContext->m_pReader = |
| (M4READER_DataInterface *)optionValue; |
| break; |
| |
| case M4AD_kOptionID_AudioAU: |
| ALOGV("VideoEditorAudioDecodersetOption AudioAU"); |
| pDecoderContext->m_pNextAccessUnitToDecode = |
| (M4_AccessUnit *)optionValue; |
| break; |
| |
| default: |
| ALOGV("VideoEditorAudioDecoder_setOption unsupported optionId 0x%X", |
| optionID); |
| VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID); |
| break; |
| } |
| |
| cleanUp: |
| if( ((M4OSA_UInt32)M4NO_ERROR == err) || ((M4OSA_UInt32)M4ERR_NOT_IMPLEMENTED == err) ) { |
| ALOGV("VideoEditorAudioDecoder_setOption error 0x%X", err); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_setOption ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_setOption end"); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getOption(M4AD_Context pContext, |
| M4OSA_UInt32 optionID, M4OSA_DataOption optionValue) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| VideoEditorAudioDecoder_Context* pDecoderContext = M4OSA_NULL; |
| |
| ALOGV("VideoEditorAudioDecoder_getOption begin: optionID 0x%X", optionID); |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pContext, M4ERR_PARAMETER); |
| |
| pDecoderContext = (VideoEditorAudioDecoder_Context*)pContext; |
| |
| switch( optionID ) { |
| |
| case M4AD_kOptionID_GetAudioAUErrCode: |
| *(uint32_t *)optionValue = pDecoderContext->readerErrCode; |
| break; |
| |
| case M4AD_kOptionID_AudioNbChannels: |
| *(uint32_t *)optionValue = |
| pDecoderContext->mAudioStreamHandler->m_nbChannels; |
| break; |
| |
| case M4AD_kOptionID_AudioSampFrequency: |
| *(uint32_t *)optionValue = |
| pDecoderContext->mAudioStreamHandler->m_samplingFrequency; |
| break; |
| |
| case M4AD_kOptionID_AuCTS: |
| *(uint32_t *)optionValue = pDecoderContext->timeStampMs; |
| break; |
| |
| default: |
| ALOGV("VideoEditorAudioDecoder_getOption unsupported optionId 0x%X", |
| optionID); |
| VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_BAD_OPTION_ID); |
| break; |
| } |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_getOption no error"); |
| } else { |
| ALOGV("VideoEditorAudioDecoder_getOption ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_getOption end"); |
| return err; |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getInterface(M4AD_Type decoderType, |
| M4AD_Type* pDecoderType, M4AD_Interface** pDecoderInterface) { |
| |
| M4OSA_ERR err = M4NO_ERROR; |
| |
| // Input parameters check |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pDecoderType, M4ERR_PARAMETER); |
| VIDEOEDITOR_CHECK(M4OSA_NULL != pDecoderInterface, M4ERR_PARAMETER); |
| |
| ALOGV("VideoEditorAudioDecoder_getInterface begin %d 0x%x 0x%x", |
| decoderType, pDecoderType, pDecoderInterface); |
| |
| SAFE_MALLOC(*pDecoderInterface, M4AD_Interface, 1, |
| "VideoEditorAudioDecoder"); |
| |
| *pDecoderType = decoderType; |
| |
| switch( decoderType ) { |
| case M4AD_kTypeAMRNB: |
| (*pDecoderInterface)->m_pFctCreateAudioDec = |
| VideoEditorAudioDecoder_create_AMRNB; |
| break; |
| case M4AD_kTypeAMRWB: |
| (*pDecoderInterface)->m_pFctCreateAudioDec = |
| VideoEditorAudioDecoder_create_AMRWB; |
| break; |
| case M4AD_kTypeAAC: |
| (*pDecoderInterface)->m_pFctCreateAudioDec = |
| VideoEditorAudioDecoder_create_AAC; |
| break; |
| case M4AD_kTypeMP3: |
| (*pDecoderInterface)->m_pFctCreateAudioDec = |
| VideoEditorAudioDecoder_create_MP3; |
| break; |
| default: |
| ALOGV("VEAD_getInterface ERROR: unsupported type %d", decoderType); |
| VIDEOEDITOR_CHECK(M4OSA_FALSE, M4ERR_PARAMETER); |
| break; |
| } |
| (*pDecoderInterface)->m_pFctDestroyAudioDec = |
| VideoEditorAudioDecoder_destroy; |
| (*pDecoderInterface)->m_pFctResetAudioDec = M4OSA_NULL; |
| (*pDecoderInterface)->m_pFctStartAudioDec = M4OSA_NULL; |
| (*pDecoderInterface)->m_pFctStepAudioDec = |
| VideoEditorAudioDecoder_step; |
| (*pDecoderInterface)->m_pFctGetVersionAudioDec = |
| VideoEditorAudioDecoder_getVersion; |
| (*pDecoderInterface)->m_pFctSetOptionAudioDec = |
| VideoEditorAudioDecoder_setOption; |
| (*pDecoderInterface)->m_pFctGetOptionAudioDec = |
| VideoEditorAudioDecoder_getOption; |
| |
| cleanUp: |
| if( M4NO_ERROR == err ) { |
| ALOGV("VideoEditorAudioDecoder_getInterface no error"); |
| } else { |
| *pDecoderInterface = M4OSA_NULL; |
| ALOGV("VideoEditorAudioDecoder_getInterface ERROR 0x%X", err); |
| } |
| ALOGV("VideoEditorAudioDecoder_getInterface end"); |
| return err; |
| } |
| |
| |
| extern "C" { |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getInterface_AAC(M4AD_Type* pDecoderType, |
| M4AD_Interface** pDecoderInterface) { |
| ALOGV("TEST: AAC VideoEditorAudioDecoder_getInterface no error"); |
| return VideoEditorAudioDecoder_getInterface( |
| M4AD_kTypeAAC, pDecoderType, pDecoderInterface); |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getInterface_AMRNB(M4AD_Type* pDecoderType, |
| M4AD_Interface** pDecoderInterface) { |
| ALOGV("TEST: AMR VideoEditorAudioDecoder_getInterface no error"); |
| return VideoEditorAudioDecoder_getInterface( |
| M4AD_kTypeAMRNB, pDecoderType, pDecoderInterface); |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getInterface_AMRWB(M4AD_Type* pDecoderType, |
| M4AD_Interface** pDecoderInterface) { |
| |
| return VideoEditorAudioDecoder_getInterface( |
| M4AD_kTypeAMRWB, pDecoderType, pDecoderInterface); |
| } |
| |
| M4OSA_ERR VideoEditorAudioDecoder_getInterface_MP3(M4AD_Type* pDecoderType, |
| M4AD_Interface** pDecoderInterface) { |
| |
| return VideoEditorAudioDecoder_getInterface( |
| M4AD_kTypeMP3, pDecoderType, pDecoderInterface); |
| } |
| |
| } // extern "C" |
| |
| } // namespace android |