blob: e4c7ea1c6d2dc665b2d361aa3e9da63241432ac0 [file] [log] [blame]
/*
* 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