/*
 ** 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_core.c

	Content:	aac encoder core functions

*******************************************************************************/

#include "typedef.h"
#include "aacenc_core.h"
#include "bitenc.h"

#include "psy_configuration.h"
#include "psy_main.h"
#include "qc_main.h"
#include "psy_main.h"
#include "channel_map.h"
#include "aac_rom.h"

/********************************************************************************
*
* function name: AacInitDefaultConfig
* description:  gives reasonable default configuration
*
**********************************************************************************/
void AacInitDefaultConfig(AACENC_CONFIG *config)
{
  /* default configurations */
  config->adtsUsed        = 1;
  config->nChannelsIn     = 2;
  config->nChannelsOut    = 2;
  config->bitRate         = 128000;
  config->bandWidth       = 0;
}

/********************************************************************************
*
* function name: AacEncOpen
* description:  allocate and initialize a new encoder instance
* returns:      0 if success
*
**********************************************************************************/
Word16  AacEncOpen(  AAC_ENCODER*      hAacEnc,        /* pointer to an encoder handle, initialized on return */
                     const  AACENC_CONFIG     config   /* pre-initialized config struct */
                     )
{
  Word32 error = 0;
  Word16 profile = 1;

  ELEMENT_INFO *elInfo = NULL;

  if (hAacEnc==0) {
    error=1;
  }

  if (!error) {
    hAacEnc->config = config;
  }

  if (!error) {
    error = InitElementInfo (config.nChannelsOut,
                             &hAacEnc->elInfo);
  }

  if (!error) {
    elInfo = &hAacEnc->elInfo;
  }

  if (!error) {
    /* use or not tns tool for long and short block */
	 Word16 tnsMask=3;

	/* init encoder psychoacoustic */
    error = psyMainInit(&hAacEnc->psyKernel,
                        config.sampleRate,
                        config.bitRate,
                        elInfo->nChannelsInEl,
                        tnsMask,
                        hAacEnc->config.bandWidth);
  }

 /* use or not adts header */
  if(!error) {
	  hAacEnc->qcOut.qcElement.adtsUsed = config.adtsUsed;
  }

  /* init encoder quantization */
  if (!error) {
    struct QC_INIT qcInit;

    /*qcInit.channelMapping = &hAacEnc->channelMapping;*/
    qcInit.elInfo = &hAacEnc->elInfo;

    qcInit.maxBits = (Word16) (MAXBITS_COEF*elInfo->nChannelsInEl);
    qcInit.bitRes = qcInit.maxBits;
    qcInit.averageBits = (Word16) ((config.bitRate * FRAME_LEN_LONG) / config.sampleRate);

    qcInit.padding.paddingRest = config.sampleRate;

    qcInit.meanPe = (Word16) ((10 * FRAME_LEN_LONG * hAacEnc->config.bandWidth) /
                                              (config.sampleRate>>1));

    qcInit.maxBitFac = (Word16) ((100 * (MAXBITS_COEF-MINBITS_COEF)* elInfo->nChannelsInEl)/
                                                 (qcInit.averageBits?qcInit.averageBits:1));

    qcInit.bitrate = config.bitRate;

    error = QCInit(&hAacEnc->qcKernel, &qcInit);
  }

  /* init bitstream encoder */
  if (!error) {
    hAacEnc->bseInit.nChannels   = elInfo->nChannelsInEl;
    hAacEnc->bseInit.bitrate     = config.bitRate;
    hAacEnc->bseInit.sampleRate  = config.sampleRate;
    hAacEnc->bseInit.profile     = profile;
  }

  return error;
}

/********************************************************************************
*
* function name: AacEncEncode
* description:  encode pcm to aac data core function
* returns:      0 if success
*
**********************************************************************************/
Word16 AacEncEncode(AAC_ENCODER *aacEnc,		/*!< an encoder handle */
                    Word16 *timeSignal,         /*!< BLOCKSIZE*nChannels audio samples, interleaved */
                    const UWord8 *ancBytes,     /*!< pointer to ancillary data bytes */
                    Word16 *numAncBytes,		/*!< number of ancillary Data Bytes */
                    UWord8 *outBytes,           /*!< pointer to output buffer (must be large MINBITS_COEF/8*MAX_CHANNELS bytes) */
                    VO_U32 *numOutBytes         /*!< number of bytes in output buffer after processing */
                    )
{
  ELEMENT_INFO *elInfo = &aacEnc->elInfo;
  Word16 globUsedBits;
  Word16 ancDataBytes, ancDataBytesLeft;

  ancDataBytes = ancDataBytesLeft = *numAncBytes;

  /* init output aac data buffer and length */
  aacEnc->hBitStream = CreateBitBuffer(&aacEnc->bitStream, outBytes, *numOutBytes);

  /* psychoacoustic process */
  psyMain(aacEnc->config.nChannelsOut,
          elInfo,
          timeSignal,
          &aacEnc->psyKernel.psyData[elInfo->ChannelIndex[0]],
          &aacEnc->psyKernel.tnsData[elInfo->ChannelIndex[0]],
          &aacEnc->psyKernel.psyConfLong,
          &aacEnc->psyKernel.psyConfShort,
          &aacEnc->psyOut.psyOutChannel[elInfo->ChannelIndex[0]],
          &aacEnc->psyOut.psyOutElement,
          aacEnc->psyKernel.pScratchTns,
		  aacEnc->config.sampleRate);

  /* adjust bitrate and frame length */
  AdjustBitrate(&aacEnc->qcKernel,
                aacEnc->config.bitRate,
                aacEnc->config.sampleRate);

  /* quantization and coding process */
  QCMain(&aacEnc->qcKernel,
         &aacEnc->qcKernel.elementBits,
         &aacEnc->qcKernel.adjThr.adjThrStateElem,
         &aacEnc->psyOut.psyOutChannel[elInfo->ChannelIndex[0]],
         &aacEnc->psyOut.psyOutElement,
         &aacEnc->qcOut.qcChannel[elInfo->ChannelIndex[0]],
         &aacEnc->qcOut.qcElement,
         elInfo->nChannelsInEl,
		 min(ancDataBytesLeft,ancDataBytes));

  ancDataBytesLeft = ancDataBytesLeft - ancDataBytes;

  globUsedBits = FinalizeBitConsumption(&aacEnc->qcKernel,
                         &aacEnc->qcOut);

  /* write bitstream process */
  WriteBitstream(aacEnc->hBitStream,
                 *elInfo,
                 &aacEnc->qcOut,
                 &aacEnc->psyOut,
                 &globUsedBits,
                 ancBytes,
				 aacEnc->psyKernel.sampleRateIdx);

  updateBitres(&aacEnc->qcKernel,
               &aacEnc->qcOut);

  /* write out the bitstream */
  *numOutBytes = GetBitsAvail(aacEnc->hBitStream) >> 3;

  return 0;
}


/********************************************************************************
*
* function name:AacEncClose
* description: deallocate an encoder instance
*
**********************************************************************************/
void AacEncClose (AAC_ENCODER* hAacEnc, VO_MEM_OPERATOR *pMemOP)
{
  if (hAacEnc) {
    QCDelete(&hAacEnc->qcKernel, pMemOP);

    QCOutDelete(&hAacEnc->qcOut, pMemOP);

    PsyDelete(&hAacEnc->psyKernel, pMemOP);

    PsyOutDelete(&hAacEnc->psyOut, pMemOP);

    DeleteBitBuffer(&hAacEnc->hBitStream);

	if(hAacEnc->intbuf)
	{
		mem_free(pMemOP, hAacEnc->intbuf, VO_INDEX_ENC_AAC);
		hAacEnc->intbuf = NULL;
	}
  }
}
