blob: 31b28d9f379bd0350e11fc3c95e68ba4b3724552 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 2008 PacketVideo
*
* 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.
* -------------------------------------------------------------------
*/
#include "aac_dec.h"
OmxAacDecoder::OmxAacDecoder()
{
iAacInitFlag = 0;
iInputUsedLength = 0;
}
OMX_BOOL OmxAacDecoder::AacDecInit(OMX_U32 aDesiredChannels)
{
Int Status;
iMemReq = PVMP4AudioDecoderGetMemRequirements();
ipMem = oscl_malloc(iMemReq);
if (0 == ipMem)
{
return OMX_FALSE;
}
oscl_memset(&iExt, 0, sizeof(tPVMP4AudioDecoderExternal));
iExt.inputBufferCurrentLength = 0;
iExt.remainderBits = 0; // Not needed anymore.
iExt.inputBufferMaxLength = PVMP4AUDIODECODER_INBUFSIZE;
iExt.outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
iExt.desiredChannels = aDesiredChannels;
iExt.aacPlusEnabled = TRUE;
iAacInitFlag = 0;
iInputUsedLength = 0;
//This var is required to do init again inbetween
iNumOfChannels = aDesiredChannels;
Status = PVMP4AudioDecoderInitLibrary(&iExt, ipMem);
return OMX_TRUE;
}
void OmxAacDecoder::AacDecDeinit()
{
oscl_free(ipMem);
}
void OmxAacDecoder::ResetDecoder()
{
if (ipMem && (iAacInitFlag != 0))
{
PVMP4AudioDecoderResetBuffer(ipMem);
}
}
Int OmxAacDecoder::AacDecodeFrames(OMX_S16* aOutputBuffer,
OMX_U32* aOutputLength, OMX_U8** aInBuffer,
OMX_U32* aInBufSize, OMX_S32* aIsFirstBuffer,
OMX_AUDIO_PARAM_PCMMODETYPE* aAudioPcmParam,
OMX_AUDIO_PARAM_AACPROFILETYPE* aAudioAacParam,
OMX_S32* aSamplesPerFrame,
OMX_BOOL* aResizeFlag)
{
Int Status;
Int32 StreamType;
static Int32 ConfigUpSamplingFactor;
*aResizeFlag = OMX_FALSE;
if (0 == iAacInitFlag)
{
//Initialization is required again when the client inbetween rewinds the input bitstream
//Added to pass khronous conformance tests
if (*aIsFirstBuffer != 0)
{
/* When the input file is reset to the begining by the client,
* this module should again be called.
*/
oscl_memset(ipMem, 0, iMemReq);
oscl_memset(&iExt, 0, sizeof(tPVMP4AudioDecoderExternal));
iExt.inputBufferCurrentLength = 0;
iExt.remainderBits = 0;
iExt.inputBufferMaxLength = PVMP4AUDIODECODER_INBUFSIZE;
iExt.outputFormat = OUTPUTFORMAT_16PCM_INTERLEAVED;
iExt.desiredChannels = iNumOfChannels;
iExt.aacPlusEnabled = TRUE;
iInputUsedLength = 0;
PVMP4AudioDecoderInitLibrary(&iExt, ipMem);
}
}
iExt.pInputBuffer = *aInBuffer + iInputUsedLength;
iExt.pOutputBuffer = &aOutputBuffer[0];
#ifdef AAC_PLUS
iExt.pOutputBuffer_plus = &aOutputBuffer[2048];
#endif
iExt.inputBufferCurrentLength = *aInBufSize;
//Decode the config buffer
if (0 == iAacInitFlag)
{
iAacInitFlag = 1;
Status = PVMP4AudioDecoderConfig(&iExt, ipMem);
ConfigUpSamplingFactor = iExt.aacPlusUpsamplingFactor;
if (2 == iExt.aacPlusUpsamplingFactor)
{
*aSamplesPerFrame = 2 * AACDEC_PCM_FRAME_SAMPLE_SIZE;
}
else
{
*aSamplesPerFrame = AACDEC_PCM_FRAME_SAMPLE_SIZE;
}
*aInBufSize -= iExt.inputBufferUsedLength;
if (0 == *aInBufSize)
{
iInputUsedLength = 0;
}
else
{
iInputUsedLength = iExt.inputBufferUsedLength;
}
return Status;
}
iExt.inputBufferUsedLength = 0;
Status = PVMP4AudioDecodeFrame(&iExt, ipMem);
if (MP4AUDEC_SUCCESS == Status || SUCCESS == Status)
{
*aInBufSize -= iExt.inputBufferUsedLength;
if (0 == *aInBufSize)
{
iInputUsedLength = 0;
}
else
{
iInputUsedLength += iExt.inputBufferUsedLength;
}
*aOutputLength = iExt.frameLength * iExt.desiredChannels;
#ifdef AAC_PLUS
if (2 == iExt.aacPlusUpsamplingFactor)
{
if (1 == iExt.desiredChannels)
{
oscl_memcpy(&aOutputBuffer[1024], &aOutputBuffer[2048], (*aOutputLength * 2));
}
*aOutputLength *= 2;
}
#endif
(*aIsFirstBuffer)++;
//After decoding the first frame, modify all the input & output port settings
if (1 == *aIsFirstBuffer)
{
StreamType = (Int32) RetrieveDecodedStreamType();
if ((0 == StreamType) && (2 == ConfigUpSamplingFactor))
{
PVMP4AudioDecoderDisableAacPlus(&iExt, &ipMem);
*aSamplesPerFrame = AACDEC_PCM_FRAME_SAMPLE_SIZE;
aAudioAacParam->eAACProfile = OMX_AUDIO_AACObjectMain;
}
//Output Port Parameters
aAudioPcmParam->nSamplingRate = iExt.samplingRate;
aAudioPcmParam->nChannels = iExt.desiredChannels;
//Input Port Parameters
aAudioAacParam->nSampleRate = iExt.samplingRate;
//Set the Resize flag to send the port settings changed callback
*aResizeFlag = OMX_TRUE;
}
return Status;
}
else if (MP4AUDEC_INCOMPLETE_FRAME == Status)
{
*aInBuffer += iInputUsedLength;
iInputUsedLength = 0;
}
else
{
*aInBufSize = 0;
iInputUsedLength = 0;
}
return Status;
}
Int OmxAacDecoder::RetrieveDecodedStreamType()
{
if ((iExt.extendedAudioObjectType == MP4AUDIO_AAC_LC) ||
(iExt.extendedAudioObjectType == MP4AUDIO_LTP))
{
return AAC; /* AAC */
}
else if (iExt.extendedAudioObjectType == MP4AUDIO_SBR)
{
return AACPLUS; /* AAC+ */
}
else if (iExt.extendedAudioObjectType == MP4AUDIO_PS)
{
return ENH_AACPLUS; /* AAC++ */
}
return -1; /* Error evaluating the stream type */
}
void OmxAacDecoder::UpdateAACPlusEnabled(OMX_BOOL flag)
{
//Mark this flag as false if client sets any non HE AAC profile in SetParameter call
iExt.aacPlusEnabled = flag;
}