/* ** Copyright 2003-2010, VisualOn, Inc. ** ** 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: aacenc.c Content: aac encoder interface functions *******************************************************************************/ #include "voAAC.h" #include "typedef.h" #include "aacenc_core.h" #include "aac_rom.h" #include "cmnMemory.h" #include "memalign.h" #define UNUSED(x) (void)(x) /** * Init the audio codec module and return codec handle * \param phCodec [OUT] Return the video codec handle * \param vType [IN] The codec type if the module support multi codec. * \param pUserData [IN] The init param. It is memory operator or alloced memory * \retval VO_ERR_NONE Succeeded. */ VO_U32 VO_API voAACEncInit(VO_HANDLE * phCodec,VO_AUDIO_CODINGTYPE vType, VO_CODEC_INIT_USERDATA *pUserData) { AAC_ENCODER*hAacEnc; int error; #ifdef USE_DEAULT_MEM VO_MEM_OPERATOR voMemoprator; #endif VO_MEM_OPERATOR *pMemOP; #ifdef USE_DEAULT_MEM int interMem; interMem = 0; #endif UNUSED(vType); error = 0; /* init the memory operator */ if(pUserData == NULL || pUserData->memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL ) { #ifdef USE_DEAULT_MEM voMemoprator.Alloc = cmnMemAlloc; voMemoprator.Copy = cmnMemCopy; voMemoprator.Free = cmnMemFree; voMemoprator.Set = cmnMemSet; voMemoprator.Check = cmnMemCheck; interMem = 1; pMemOP = &voMemoprator; #else *phCodec = NULL; return VO_ERR_INVALID_ARG; #endif } else { pMemOP = (VO_MEM_OPERATOR *)pUserData->memData; } /* init the aac encoder handle */ hAacEnc = (AAC_ENCODER*)mem_malloc(pMemOP, sizeof(AAC_ENCODER), 32, VO_INDEX_ENC_AAC); if(NULL == hAacEnc) { error = 1; } if(!error) { /* init the aac encoder intra memory */ hAacEnc->intbuf = (short *)mem_malloc(pMemOP, AACENC_BLOCKSIZE*MAX_CHANNELS*sizeof(short), 32, VO_INDEX_ENC_AAC); if(NULL == hAacEnc->intbuf) { error = 1; } } if (!error) { /* init the aac encoder psychoacoustic */ error = (PsyNew(&hAacEnc->psyKernel, MAX_CHANNELS, pMemOP) || PsyOutNew(&hAacEnc->psyOut, pMemOP)); } if (!error) { /* init the aac encoder quantization elements */ error = QCOutNew(&hAacEnc->qcOut,MAX_CHANNELS, pMemOP); } if (!error) { /* init the aac encoder quantization state */ error = QCNew(&hAacEnc->qcKernel, pMemOP); } /* uninit the aac encoder if error is nozero */ if(error) { AacEncClose(hAacEnc, pMemOP); if(hAacEnc) { mem_free(pMemOP, hAacEnc, VO_INDEX_ENC_AAC); hAacEnc = NULL; } *phCodec = NULL; return VO_ERR_OUTOF_MEMORY; } /* init the aac encoder memory operator */ #ifdef USE_DEAULT_MEM if(interMem) { hAacEnc->voMemoprator.Alloc = cmnMemAlloc; hAacEnc->voMemoprator.Copy = cmnMemCopy; hAacEnc->voMemoprator.Free = cmnMemFree; hAacEnc->voMemoprator.Set = cmnMemSet; hAacEnc->voMemoprator.Check = cmnMemCheck; pMemOP = &hAacEnc->voMemoprator; } #endif /* init the aac encoder default parameter */ if(hAacEnc->initOK == 0) { AACENC_CONFIG config; config.adtsUsed = 1; config.bitRate = 128000; config.nChannelsIn = 2; config.nChannelsOut = 2; config.sampleRate = 44100; config.bandWidth = 20000; AacEncOpen(hAacEnc, config); } hAacEnc->voMemop = pMemOP; *phCodec = hAacEnc; return VO_ERR_NONE; } /** * Set input audio data. * \param hCodec [IN]] The Codec Handle which was created by Init function. * \param pInput [IN] The input buffer param. * \param pOutBuffer [OUT] The output buffer info. * \retval VO_ERR_NONE Succeeded. */ VO_U32 VO_API voAACEncSetInputData(VO_HANDLE hCodec, VO_CODECBUFFER * pInput) { AAC_ENCODER *hAacEnc; int length; if(NULL == hCodec || NULL == pInput || NULL == pInput->Buffer) { return VO_ERR_INVALID_ARG; } hAacEnc = (AAC_ENCODER *)hCodec; /* init input pcm buffer and length*/ hAacEnc->inbuf = (short *)pInput->Buffer; hAacEnc->inlen = pInput->Length / sizeof(short); hAacEnc->uselength = 0; hAacEnc->encbuf = hAacEnc->inbuf; hAacEnc->enclen = hAacEnc->inlen; /* rebuild intra pcm buffer and length*/ if(hAacEnc->intlen) { length = min(hAacEnc->config.nChannelsIn*AACENC_BLOCKSIZE - hAacEnc->intlen, hAacEnc->inlen); hAacEnc->voMemop->Copy(VO_INDEX_ENC_AAC, hAacEnc->intbuf + hAacEnc->intlen, hAacEnc->inbuf, length*sizeof(short)); hAacEnc->encbuf = hAacEnc->intbuf; hAacEnc->enclen = hAacEnc->intlen + length; hAacEnc->inbuf += length; hAacEnc->inlen -= length; } return VO_ERR_NONE; } /** * Get the outut audio data * \param hCodec [IN]] The Codec Handle which was created by Init function. * \param pOutBuffer [OUT] The output audio data * \param pOutInfo [OUT] The dec module filled audio format and used the input size. * pOutInfo->InputUsed is total used the input size. * \retval VO_ERR_NONE Succeeded. * VO_ERR_INPUT_BUFFER_SMALL. The input was finished or the input data was not enought. */ VO_U32 VO_API voAACEncGetOutputData(VO_HANDLE hCodec, VO_CODECBUFFER * pOutput, VO_AUDIO_OUTPUTINFO * pOutInfo) { AAC_ENCODER* hAacEnc = (AAC_ENCODER*)hCodec; Word16 numAncDataBytes=0; Word32 inbuflen; int length; if(NULL == hAacEnc) return VO_ERR_INVALID_ARG; inbuflen = AACENC_BLOCKSIZE*hAacEnc->config.nChannelsIn; /* check the input pcm buffer and length*/ if(NULL == hAacEnc->encbuf || hAacEnc->enclen < inbuflen) { length = hAacEnc->enclen; if(hAacEnc->intlen == 0) { hAacEnc->voMemop->Copy(VO_INDEX_ENC_AAC, hAacEnc->intbuf, hAacEnc->encbuf, length*sizeof(short)); hAacEnc->uselength += length*sizeof(short); } else { hAacEnc->uselength += (length - hAacEnc->intlen)*sizeof(short); } hAacEnc->intlen = length; pOutput->Length = 0; if(pOutInfo) pOutInfo->InputUsed = hAacEnc->uselength; return VO_ERR_INPUT_BUFFER_SMALL; } /* check the output aac buffer and length*/ if(NULL == pOutput || NULL == pOutput->Buffer || pOutput->Length < (6144/8)*hAacEnc->config.nChannelsOut/(sizeof(Word32))) return VO_ERR_OUTPUT_BUFFER_SMALL; /* aac encoder core function */ AacEncEncode( hAacEnc, (Word16*)hAacEnc->encbuf, NULL, &numAncDataBytes, pOutput->Buffer, &pOutput->Length); /* update the input pcm buffer and length*/ if(hAacEnc->intlen) { length = inbuflen - hAacEnc->intlen; hAacEnc->encbuf = hAacEnc->inbuf; hAacEnc->enclen = hAacEnc->inlen; hAacEnc->uselength += length*sizeof(short); hAacEnc->intlen = 0; } else { hAacEnc->encbuf = hAacEnc->encbuf + inbuflen; hAacEnc->enclen = hAacEnc->enclen - inbuflen; hAacEnc->uselength += inbuflen*sizeof(short); } /* update the output aac information */ if(pOutInfo) { pOutInfo->Format.Channels = hAacEnc->config.nChannelsOut; pOutInfo->Format.SampleRate = hAacEnc->config.sampleRate; pOutInfo->Format.SampleBits = 16; pOutInfo->InputUsed = hAacEnc->uselength; } return VO_ERR_NONE; } /** * Uninit the Codec. * \param hCodec [IN]] The Codec Handle which was created by Init function. * \retval VO_ERR_NONE Succeeded. */ VO_U32 VO_API voAACEncUninit(VO_HANDLE hCodec) { AAC_ENCODER* hAacEnc = (AAC_ENCODER*)hCodec; if(NULL != hAacEnc) { /* close the aac encoder */ AacEncClose(hAacEnc, hAacEnc->voMemop); /* free the aac encoder handle*/ mem_free(hAacEnc->voMemop, hAacEnc, VO_INDEX_ENC_AAC); hAacEnc = NULL; } return VO_ERR_NONE; } /** * Set the param for special target. * \param hCodec [IN]] The Codec Handle which was created by Init function. * \param uParamID [IN] The param ID. * \param pData [IN] The param value depend on the ID> * \retval VO_ERR_NONE Succeeded. */ VO_U32 VO_API voAACEncSetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData) { AACENC_CONFIG config; AACENC_PARAM* pAAC_param; VO_AUDIO_FORMAT *pWAV_Format; AAC_ENCODER* hAacEnc = (AAC_ENCODER*)hCodec; int ret, i, bitrate, tmp; int SampleRateIdx; if(NULL == hAacEnc) return VO_ERR_INVALID_ARG; switch(uParamID) { case VO_PID_AAC_ENCPARAM: /* init aac encoder parameter*/ AacInitDefaultConfig(&config); if(pData == NULL) return VO_ERR_INVALID_ARG; pAAC_param = (AACENC_PARAM*)pData; config.adtsUsed = pAAC_param->adtsUsed; config.bitRate = pAAC_param->bitRate; config.nChannelsIn = pAAC_param->nChannels; config.nChannelsOut = pAAC_param->nChannels; config.sampleRate = pAAC_param->sampleRate; /* check the channel */ if(config.nChannelsIn< 1 || config.nChannelsIn > MAX_CHANNELS || config.nChannelsOut < 1 || config.nChannelsOut > MAX_CHANNELS || config.nChannelsIn < config.nChannelsOut) return VO_ERR_AUDIO_UNSCHANNEL; /* check the samplerate */ ret = -1; for(i = 0; i < NUM_SAMPLE_RATES; i++) { if(config.sampleRate == sampRateTab[i]) { ret = 0; break; } } if(ret < 0) return VO_ERR_AUDIO_UNSSAMPLERATE; SampleRateIdx = i; tmp = 441; if(config.sampleRate%8000 == 0) tmp =480; /* check the bitrate */ if(config.bitRate!=0 && ((config.bitRate/config.nChannelsOut < 4000) || (config.bitRate/config.nChannelsOut > 160000) || (config.bitRate > config.sampleRate*6*config.nChannelsOut))) { config.bitRate = 640*config.sampleRate/tmp*config.nChannelsOut; if(config.bitRate/config.nChannelsOut < 4000) config.bitRate = 4000 * config.nChannelsOut; else if(config.bitRate > config.sampleRate*6*config.nChannelsOut) config.bitRate = config.sampleRate*6*config.nChannelsOut; else if(config.bitRate/config.nChannelsOut > 160000) config.bitRate = config.nChannelsOut*160000; } /* check the bandwidth */ bitrate = config.bitRate / config.nChannelsOut; bitrate = bitrate * tmp / config.sampleRate; for (i = 0; rates[i]; i++) { if (rates[i] >= bitrate) break; } config.bandWidth = BandwithCoefTab[i][SampleRateIdx]; /* init aac encoder core */ ret = AacEncOpen(hAacEnc, config); if(ret) return VO_ERR_AUDIO_UNSFEATURE; break; case VO_PID_AUDIO_FORMAT: /* init pcm channel and samplerate*/ AacInitDefaultConfig(&config); if(pData == NULL) return VO_ERR_INVALID_ARG; pWAV_Format = (VO_AUDIO_FORMAT*)pData; config.adtsUsed = 1; config.nChannelsIn = pWAV_Format->Channels; config.nChannelsOut = pWAV_Format->Channels; config.sampleRate = pWAV_Format->SampleRate; /* check the channel */ if(config.nChannelsIn< 1 || config.nChannelsIn > MAX_CHANNELS || config.nChannelsOut < 1 || config.nChannelsOut > MAX_CHANNELS || config.nChannelsIn < config.nChannelsOut) return VO_ERR_AUDIO_UNSCHANNEL; /* check the samplebits */ if(pWAV_Format->SampleBits != 16) { return VO_ERR_AUDIO_UNSFEATURE; } /* check the samplerate */ ret = -1; for(i = 0; i < NUM_SAMPLE_RATES; i++) { if(config.sampleRate == sampRateTab[i]) { ret = 0; break; } } if(ret < 0) return VO_ERR_AUDIO_UNSSAMPLERATE; SampleRateIdx = i; /* update the bitrates */ tmp = 441; if(config.sampleRate%8000 == 0) tmp =480; config.bitRate = 640*config.sampleRate/tmp*config.nChannelsOut; if(config.bitRate/config.nChannelsOut < 4000) config.bitRate = 4000 * config.nChannelsOut; else if(config.bitRate > config.sampleRate*6*config.nChannelsOut) config.bitRate = config.sampleRate*6*config.nChannelsOut; else if(config.bitRate/config.nChannelsOut > 160000) config.bitRate = config.nChannelsOut*160000; /* check the bandwidth */ bitrate = config.bitRate / config.nChannelsOut; bitrate = bitrate * tmp / config.sampleRate; for (i = 0; rates[i]; i++) { if (rates[i] >= bitrate) break; } config.bandWidth = BandwithCoefTab[i][SampleRateIdx]; /* init aac encoder core */ ret = AacEncOpen(hAacEnc, config); if(ret) return VO_ERR_AUDIO_UNSFEATURE; break; default: return VO_ERR_WRONG_PARAM_ID; } return VO_ERR_NONE; } /** * Get the param for special target. * \param hCodec [IN]] The Codec Handle which was created by Init function. * \param uParamID [IN] The param ID. * \param pData [IN] The param value depend on the ID> * \retval VO_ERR_NONE Succeeded. */ VO_U32 VO_API voAACEncGetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData) { UNUSED(hCodec); UNUSED(uParamID); UNUSED(pData); return VO_ERR_NONE; } /** * Get audio codec API interface * \param pEncHandle [out] Return the AAC Encoder handle. * \retval VO_ERR_OK Succeeded. */ VO_S32 VO_API voGetAACEncAPI(VO_AUDIO_CODECAPI * pDecHandle) { if(pDecHandle == NULL) return VO_ERR_INVALID_ARG; pDecHandle->Init = voAACEncInit; pDecHandle->SetInputData = voAACEncSetInputData; pDecHandle->GetOutputData = voAACEncGetOutputData; pDecHandle->SetParam = voAACEncSetParam; pDecHandle->GetParam = voAACEncGetParam; pDecHandle->Uninit = voAACEncUninit; return VO_ERR_NONE; }