/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2004 M. Bakker, Ahead Software AG, http://www.nero.com
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
** $Id$
**/

#include "common.h"
#include "structs.h"

#include <stdlib.h>
#include <string.h>

#include "decoder.h"
#include "mp4.h"
#include "syntax.h"
#include "error.h"
/* rockbox: not used
#include "output.h"
*/
#include "filtbank.h"
#include "drc.h"
#ifdef SBR_DEC
#include "sbr_dec.h"
#include "sbr_syntax.h"
#endif
#ifdef SSR_DEC
#include "ssr.h"
#endif

/* Globals */
#ifdef ANALYSIS
uint16_t dbg_count;
#endif

/* static variables */
static NeAACDecStruct s_AACDec;
static real_t s_fb_intermed  [MAX_CHANNELS][1*FRAME_LEN] IBSS_ATTR_FAAD_LARGE_IRAM MEM_ALIGN_ATTR;
static real_t s_time_buf_1024[MAX_CHANNELS][1*FRAME_LEN] IBSS_ATTR_FAAD_LARGE_IRAM MEM_ALIGN_ATTR;
#ifdef SBR_DEC
#ifdef FAAD_STATIC_ALLOC
static real_t s_time_buf_2048[MAX_CHANNELS][2*FRAME_LEN] MEM_ALIGN_ATTR;
#endif
#endif
#ifdef SSR_DEC
static real_t s_ssr_overlap  [MAX_CHANNELS][2*FRAME_LEN] MEM_ALIGN_ATTR;
static real_t s_prev_fmd     [MAX_CHANNELS][2*FRAME_LEN] MEM_ALIGN_ATTR;
#endif
#ifdef MAIN_DEC
static pred_state s_pred_stat[MAX_CHANNELS][1*FRAME_LEN] MEM_ALIGN_ATTR;
#endif
#ifdef LTP_DEC
static int16_t s_lt_pred_stat[MAX_CHANNELS][4*FRAME_LEN] MEM_ALIGN_ATTR;
#endif


/* static function declarations */
static void* aac_frame_decode(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo,
                              uint8_t *buffer, uint32_t buffer_size);
/* not used by rockbox
static void create_channel_config(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo);
*/

char* NEAACDECAPI NeAACDecGetErrorMessage(uint8_t errcode)
{
    if (errcode >= NUM_ERROR_MESSAGES)
        return NULL;
    return err_msg[errcode];
}

/* rockbox: not used */
#if 0
uint32_t NEAACDECAPI NeAACDecGetCapabilities(void)
{
    uint32_t cap = 0;

    /* can't do without it */
    cap += LC_DEC_CAP;

#ifdef MAIN_DEC
    cap += MAIN_DEC_CAP;
#endif
#ifdef LTP_DEC
    cap += LTP_DEC_CAP;
#endif
#ifdef LD_DEC
    cap += LD_DEC_CAP;
#endif
#ifdef ERROR_RESILIENCE
    cap += ERROR_RESILIENCE_CAP;
#endif
#ifdef FIXED_POINT
    cap += FIXED_POINT_CAP;
#endif

    return cap;
}
#endif

NeAACDecHandle NEAACDECAPI NeAACDecOpen(void)
{
    uint8_t i;
    NeAACDecHandle hDecoder = NULL;

    #if defined(CPU_COLDFIRE)
    coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
    #endif

    hDecoder = &s_AACDec;

    memset(hDecoder     , 0, sizeof(NeAACDecStruct));
    memset(s_fb_intermed, 0, sizeof(s_fb_intermed));
#ifdef SSR_DEC
    memset(s_ssr_overlap, 0, sizeof(s_ssr_overlap));
    memset(s_prev_fmd   , 0, sizeof(s_prev_fmd));
#endif
#ifdef LTP_DEC
    memset(s_lt_pred_stat, 0, sizeof(s_s_lt_pred_statpred_stat));
#endif

    hDecoder->config.outputFormat  = FAAD_FMT_16BIT;
    hDecoder->config.defObjectType = MAIN;
    hDecoder->config.defSampleRate = 44100; 
    hDecoder->config.downMatrix = 0;
    hDecoder->adts_header_present = 0;
    hDecoder->adif_header_present = 0;
#ifdef ERROR_RESILIENCE
    hDecoder->aacSectionDataResilienceFlag = 0;
    hDecoder->aacScalefactorDataResilienceFlag = 0;
    hDecoder->aacSpectralDataResilienceFlag = 0;
#endif
    hDecoder->frameLength = FRAME_LEN;

    hDecoder->frame = 0;

    for (i = 0; i < MAX_CHANNELS; i++)
    {
        hDecoder->window_shape_prev[i] = 0;
        hDecoder->time_out[i] = NULL;
        hDecoder->fb_intermed[i] = s_fb_intermed[i];
#ifdef SSR_DEC
        hDecoder->ssr_overlap[i] = s_ssr_overlap[i];
        hDecoder->prev_fmd[i] = s_prev_fmd[i];
        for (int k = 0; k < 2048; k++)
            hDecoder->prev_fmd[i][k] = REAL_CONST(-1);
#endif
#ifdef MAIN_DEC
        hDecoder->pred_stat[i] = s_pred_stat[i];
        reset_all_predictors(hDecoder->pred_stat[channel], FRAME_LEN);
#endif
#ifdef LTP_DEC
        hDecoder->ltp_lag[i] = 0;
        hDecoder->lt_pred_stat[i] = s_lt_pred_stat[i];
#endif
    }

#ifdef SBR_DEC
    for (i = 0; i < MAX_SYNTAX_ELEMENTS; i++)
    {
        hDecoder->sbr[i] = NULL;
    }
#endif

    hDecoder->drc = drc_init(REAL_CONST(1.0), REAL_CONST(1.0));

    return hDecoder;
}

NeAACDecConfigurationPtr NEAACDECAPI NeAACDecGetCurrentConfiguration(NeAACDecHandle hDecoder)
{
    if (hDecoder)
    {
        NeAACDecConfigurationPtr config = &(hDecoder->config);

        return config;
    }

    return NULL;
}

uint8_t NEAACDECAPI NeAACDecSetConfiguration(NeAACDecHandle hDecoder,
                                             NeAACDecConfigurationPtr config)
{
    if (hDecoder && config)
    {
        /* check if we can decode this object type */
        if (can_decode_ot(config->defObjectType) < 0)
            return 0;
        hDecoder->config.defObjectType = config->defObjectType;

        /* samplerate: anything but 0 should be possible */
        if (config->defSampleRate == 0)
            return 0;
        hDecoder->config.defSampleRate = config->defSampleRate;

        /* check output format */
#ifdef FIXED_POINT
        if ((config->outputFormat < 1) || (config->outputFormat > 4))
            return 0;
#else
        if ((config->outputFormat < 1) || (config->outputFormat > 5))
            return 0;
#endif
        hDecoder->config.outputFormat = config->outputFormat;

        if (config->downMatrix > 1)
            return 0;
        hDecoder->config.downMatrix = config->downMatrix;

        /* OK */
        return 1;
    }

    return 0;
}

int32_t NEAACDECAPI NeAACDecInit(NeAACDecHandle hDecoder, uint8_t *buffer,
                                 uint32_t buffer_size,
                                 uint32_t *samplerate, uint8_t *channels)
{
    uint32_t i;
    uint32_t bits = 0;
    bitfile ld;
    adif_header adif;
    adts_header adts;

    if ((hDecoder == NULL) || (samplerate == NULL) || (channels == NULL))
        return -1;

    hDecoder->sf_index = get_sr_index(hDecoder->config.defSampleRate);
    hDecoder->object_type = hDecoder->config.defObjectType;
    *samplerate = get_sample_rate(hDecoder->sf_index);
    *channels = 1;

    if (buffer != NULL)
    {
        faad_initbits(&ld, buffer, buffer_size);

        /* Check if an ADIF header is present */
        if ((buffer[0] == 'A') && (buffer[1] == 'D') &&
            (buffer[2] == 'I') && (buffer[3] == 'F'))
        {
            hDecoder->adif_header_present = 1;

            get_adif_header(&adif, &ld);
            faad_byte_align(&ld);

            hDecoder->sf_index = adif.pce[0].sf_index;
            hDecoder->object_type = adif.pce[0].object_type + 1;

            *samplerate = get_sample_rate(hDecoder->sf_index);
            *channels = adif.pce[0].channels;

            memcpy(&(hDecoder->pce), &(adif.pce[0]), sizeof(program_config));
            hDecoder->pce_set = 1;

            bits = bit2byte(faad_get_processed_bits(&ld));

        /* Check if an ADTS header is present */
        } else if (faad_showbits(&ld, 12) == 0xfff) {
            hDecoder->adts_header_present = 1;

            adts.old_format = hDecoder->config.useOldADTSFormat;
            adts_frame(&adts, &ld);

            hDecoder->sf_index = adts.sf_index;
            hDecoder->object_type = adts.profile + 1;

            *samplerate = get_sample_rate(hDecoder->sf_index);
            *channels = (adts.channel_configuration > 6) ?
                2 : adts.channel_configuration;
        }

        if (ld.error)
        {
            faad_endbits(&ld);
            return -1;
        }
        faad_endbits(&ld);
    }
    hDecoder->channelConfiguration = *channels;

#if (defined(PS_DEC) || defined(DRM_PS))
    /* check if we have a mono file */
    if (*channels == 1)
    {
        /* upMatrix to 2 channels for implicit signalling of PS */
        *channels = 2;
    }
#endif

    /* A maximum of MAX_CHANNELS channels is supported. */
    if (*channels > MAX_CHANNELS)
    {
        return -1;
    }

#ifdef SBR_DEC
    /* implicit signalling */
    if (*samplerate <= 24000 && !(hDecoder->config.dontUpSampleImplicitSBR))
    {
        *samplerate *= 2;
        hDecoder->forceUpSampling = 1;
    } else if (*samplerate > 24000 && !(hDecoder->config.dontUpSampleImplicitSBR)) {
        hDecoder->downSampledSBR = 1;
    }
#endif

    /* must be done before frameLength is divided by 2 for LD */
#ifdef SSR_DEC
    if (hDecoder->object_type == SSR)
        hDecoder->fb = ssr_filter_bank_init(hDecoder->frameLength/SSR_BANDS);
    else
#endif


#ifdef LD_DEC
    if (hDecoder->object_type == LD)
        hDecoder->frameLength >>= 1;
#endif

    for (i=0; i<MAX_CHANNELS; ++i)
    {
#ifdef SBR_DEC
        hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 0;
        if ((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1))
        {
#ifdef FAAD_STATIC_ALLOC
            hDecoder->time_out[i] = s_time_buf_2048[i];
#else
            hDecoder->time_out[i] = (real_t*)faad_malloc(2*FRAME_LEN*sizeof(real_t));
            if (hDecoder->time_out[i] == NULL)
            {
                /* could not allocate memory */
                return -1;
            }
#endif
            memset(hDecoder->time_out[i], 0, 2*FRAME_LEN);
            hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 1;
        }
        else
#endif
        {
            hDecoder->time_out[i] = s_time_buf_1024[i];
            memset(hDecoder->time_out[i], 0, 1*FRAME_LEN);
        }
    }

    if (can_decode_ot(hDecoder->object_type) < 0)
        return -1;

    return bits;
}

/* Init the library using a DecoderSpecificInfo */
int8_t NEAACDECAPI NeAACDecInit2(NeAACDecHandle hDecoder, uint8_t *pBuffer,
                                 uint32_t SizeOfDecoderSpecificInfo,
                                 uint32_t *samplerate, uint8_t *channels)
{
    int8_t rc;
    uint32_t i;
    mp4AudioSpecificConfig mp4ASC;

    if((hDecoder == NULL)
        || (pBuffer == NULL)
        || (SizeOfDecoderSpecificInfo < 2)
        || (samplerate == NULL)
        || (channels == NULL))
    {
        return -1;
    }

    hDecoder->adif_header_present = 0;
    hDecoder->adts_header_present = 0;

    /* decode the audio specific config */
    rc = AudioSpecificConfig2(pBuffer, SizeOfDecoderSpecificInfo, &mp4ASC,
        &(hDecoder->pce));

    /* copy the relevant info to the decoder handle */
    *samplerate = mp4ASC.samplingFrequency;
    if (mp4ASC.channelsConfiguration)
    {
        *channels = mp4ASC.channelsConfiguration;
    } else {
        *channels = hDecoder->pce.channels;
        hDecoder->pce_set = 1;
    }
#if (defined(PS_DEC) || defined(DRM_PS))
    /* check if we have a mono file */
    if (*channels == 1)
    {
        /* upMatrix to 2 channels for implicit signalling of PS */
        *channels = 2;
    }
#endif

    /* A maximum of MAX_CHANNELS channels is supported. */
    if (*channels > MAX_CHANNELS)
    {
        return -1;
    }

    hDecoder->sf_index = mp4ASC.samplingFrequencyIndex;
    hDecoder->object_type = mp4ASC.objectTypeIndex;
#ifdef ERROR_RESILIENCE
    hDecoder->aacSectionDataResilienceFlag = mp4ASC.aacSectionDataResilienceFlag;
    hDecoder->aacScalefactorDataResilienceFlag = mp4ASC.aacScalefactorDataResilienceFlag;
    hDecoder->aacSpectralDataResilienceFlag = mp4ASC.aacSpectralDataResilienceFlag;
#endif
#ifdef SBR_DEC
    hDecoder->sbr_present_flag = mp4ASC.sbr_present_flag;
    hDecoder->downSampledSBR = mp4ASC.downSampledSBR;
    if (hDecoder->config.dontUpSampleImplicitSBR == 0)
        hDecoder->forceUpSampling = mp4ASC.forceUpSampling;
    else
        hDecoder->forceUpSampling = 0;

    /* AAC core decoder samplerate is 2 times as low */
    if (((hDecoder->sbr_present_flag == 1)&&(!hDecoder->downSampledSBR)) || hDecoder->forceUpSampling == 1)
    {
        hDecoder->sf_index = get_sr_index(mp4ASC.samplingFrequency / 2);
    }
#endif

    if (rc != 0)
    {
        return rc;
    }
    hDecoder->channelConfiguration = mp4ASC.channelsConfiguration;
    if (mp4ASC.frameLengthFlag)
#ifdef ALLOW_SMALL_FRAMELENGTH
        hDecoder->frameLength = 960;
#else
        return -1;
#endif

    /* must be done before frameLength is divided by 2 for LD */
#ifdef SSR_DEC
    if (hDecoder->object_type == SSR)
        hDecoder->fb = ssr_filter_bank_init(hDecoder->frameLength/SSR_BANDS);
    else
#endif

#ifdef LD_DEC
    if (hDecoder->object_type == LD)
        hDecoder->frameLength >>= 1;
#endif

    for (i=0; i<MAX_CHANNELS; ++i)
    {
#ifdef SBR_DEC
        hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 0;
        if ((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1))
        {
#ifdef FAAD_STATIC_ALLOC
            hDecoder->time_out[i] = s_time_buf_2048[i];
#else
            hDecoder->time_out[i] = (real_t*)faad_malloc(2*FRAME_LEN*sizeof(real_t));
            if (hDecoder->time_out[i] == NULL)
            {
                /* could not allocate memory */
                return -1;
            }
#endif
            memset(hDecoder->time_out[i], 0, 2*FRAME_LEN);
            hDecoder->sbr_alloced[hDecoder->fr_ch_ele] = 1;
        }
        else
#endif
        {
            hDecoder->time_out[i] = s_time_buf_1024[i];
            memset(hDecoder->time_out[i], 0, 1*FRAME_LEN);
        }
    }

    return 0;
}

#ifdef DRM
int8_t NEAACDECAPI NeAACDecInitDRM(NeAACDecHandle *hDecoder, uint32_t samplerate,
                                   uint8_t channels)
{
    if (hDecoder == NULL)
        return 1; /* error */

    *hDecoder = NeAACDecOpen();

    /* Special object type defined for DRM */
    (*hDecoder)->config.defObjectType = DRM_ER_LC;

    (*hDecoder)->config.defSampleRate = samplerate;
#ifdef ERROR_RESILIENCE // This shoudl always be defined for DRM
    (*hDecoder)->aacSectionDataResilienceFlag = 1; /* VCB11 */
    (*hDecoder)->aacScalefactorDataResilienceFlag = 0; /* no RVLC */
    (*hDecoder)->aacSpectralDataResilienceFlag = 1; /* HCR */
#endif
    (*hDecoder)->frameLength = 960;
    (*hDecoder)->sf_index = get_sr_index((*hDecoder)->config.defSampleRate);
    (*hDecoder)->object_type = (*hDecoder)->config.defObjectType;

    if ((channels == DRMCH_STEREO) || (channels == DRMCH_SBR_STEREO))
        (*hDecoder)->channelConfiguration = 2;
    else
        (*hDecoder)->channelConfiguration = 1;

#ifdef SBR_DEC
    if ((channels == DRMCH_MONO) || (channels == DRMCH_STEREO))
        (*hDecoder)->sbr_present_flag = 0;
    else
        (*hDecoder)->sbr_present_flag = 1;    
#endif        


    return 0;
}
#endif

void NEAACDECAPI NeAACDecPostSeekReset(NeAACDecHandle hDecoder, int32_t frame)
{
    if (hDecoder)
    {
        hDecoder->postSeekResetFlag = 1;

        if (frame != -1)
            hDecoder->frame = frame;
    }
}

/* not used by rockbox */
#if 0
static void create_channel_config(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo)
{
    hInfo->num_front_channels = 0;
    hInfo->num_side_channels = 0;
    hInfo->num_back_channels = 0;
    hInfo->num_lfe_channels = 0;
    memset(hInfo->channel_position, 0, MAX_CHANNELS*sizeof(uint8_t));

    if (hDecoder->downMatrix)
    {
        hInfo->num_front_channels = 2;
        hInfo->channel_position[0] = FRONT_CHANNEL_LEFT;
        hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT;
        return;
    }

    /* check if there is a PCE */
    if (hDecoder->pce_set)
    {
        uint8_t i, chpos = 0;
        uint8_t chdir, back_center = 0;

        hInfo->num_front_channels = hDecoder->pce.num_front_channels;
        hInfo->num_side_channels = hDecoder->pce.num_side_channels;
        hInfo->num_back_channels = hDecoder->pce.num_back_channels;
        hInfo->num_lfe_channels = hDecoder->pce.num_lfe_channels;

        chdir = hInfo->num_front_channels;
        if (chdir & 1)
        {
            hInfo->channel_position[chpos++] = FRONT_CHANNEL_CENTER;
            chdir--;
        }
        for (i = 0; i < chdir; i += 2)
        {
            hInfo->channel_position[chpos++] = FRONT_CHANNEL_LEFT;
            hInfo->channel_position[chpos++] = FRONT_CHANNEL_RIGHT;
        }

        for (i = 0; i < hInfo->num_side_channels; i += 2)
        {
            hInfo->channel_position[chpos++] = SIDE_CHANNEL_LEFT;
            hInfo->channel_position[chpos++] = SIDE_CHANNEL_RIGHT;
        }

        chdir = hInfo->num_back_channels;
        if (chdir & 1)
        {
            back_center = 1;
            chdir--;
        }
        for (i = 0; i < chdir; i += 2)
        {
            hInfo->channel_position[chpos++] = BACK_CHANNEL_LEFT;
            hInfo->channel_position[chpos++] = BACK_CHANNEL_RIGHT;
        }
        if (back_center)
        {
            hInfo->channel_position[chpos++] = BACK_CHANNEL_CENTER;
        }

        for (i = 0; i < hInfo->num_lfe_channels; i++)
        {
            hInfo->channel_position[chpos++] = LFE_CHANNEL;
        }

    } else {
        switch (hDecoder->channelConfiguration)
        {
        case 1:
            hInfo->num_front_channels = 1;
            hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
            break;
        case 2:
            hInfo->num_front_channels = 2;
            hInfo->channel_position[0] = FRONT_CHANNEL_LEFT;
            hInfo->channel_position[1] = FRONT_CHANNEL_RIGHT;
            break;
        case 3:
            hInfo->num_front_channels = 3;
            hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
            hInfo->channel_position[1] = FRONT_CHANNEL_LEFT;
            hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT;
            break;
        case 4:
            hInfo->num_front_channels = 3;
            hInfo->num_back_channels = 1;
            hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
            hInfo->channel_position[1] = FRONT_CHANNEL_LEFT;
            hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT;
            hInfo->channel_position[3] = BACK_CHANNEL_CENTER;
            break;
        case 5:
            hInfo->num_front_channels = 3;
            hInfo->num_back_channels = 2;
            hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
            hInfo->channel_position[1] = FRONT_CHANNEL_LEFT;
            hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT;
            hInfo->channel_position[3] = BACK_CHANNEL_LEFT;
            hInfo->channel_position[4] = BACK_CHANNEL_RIGHT;
            break;
        case 6:
            hInfo->num_front_channels = 3;
            hInfo->num_back_channels = 2;
            hInfo->num_lfe_channels = 1;
            hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
            hInfo->channel_position[1] = FRONT_CHANNEL_LEFT;
            hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT;
            hInfo->channel_position[3] = BACK_CHANNEL_LEFT;
            hInfo->channel_position[4] = BACK_CHANNEL_RIGHT;
            hInfo->channel_position[5] = LFE_CHANNEL;
            break;
        case 7:
            hInfo->num_front_channels = 3;
            hInfo->num_side_channels = 2;
            hInfo->num_back_channels = 2;
            hInfo->num_lfe_channels = 1;
            hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
            hInfo->channel_position[1] = FRONT_CHANNEL_LEFT;
            hInfo->channel_position[2] = FRONT_CHANNEL_RIGHT;
            hInfo->channel_position[3] = SIDE_CHANNEL_LEFT;
            hInfo->channel_position[4] = SIDE_CHANNEL_RIGHT;
            hInfo->channel_position[5] = BACK_CHANNEL_LEFT;
            hInfo->channel_position[6] = BACK_CHANNEL_RIGHT;
            hInfo->channel_position[7] = LFE_CHANNEL;
            break;
        default: /* channelConfiguration == 0 || channelConfiguration > 7 */
            {
                uint8_t i;
                uint8_t ch = hDecoder->fr_channels - hDecoder->has_lfe;
                if (ch & 1) /* there's either a center front or a center back channel */
                {
                    uint8_t ch1 = (ch-1)/2;
                    if (hDecoder->first_syn_ele == ID_SCE)
                    {
                        hInfo->num_front_channels = ch1 + 1;
                        hInfo->num_back_channels = ch1;
                        hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
                        for (i = 1; i <= ch1; i+=2)
                        {
                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
                        }
                        for (i = ch1+1; i < ch; i+=2)
                        {
                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
                        }
                    } else {
                        hInfo->num_front_channels = ch1;
                        hInfo->num_back_channels = ch1 + 1;
                        for (i = 0; i < ch1; i+=2)
                        {
                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
                        }
                        for (i = ch1; i < ch-1; i+=2)
                        {
                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
                        }
                        hInfo->channel_position[ch-1] = BACK_CHANNEL_CENTER;
                    }
                } else {
                    uint8_t ch1 = (ch)/2;
                    hInfo->num_front_channels = ch1;
                    hInfo->num_back_channels = ch1;
                    if (ch1 & 1)
                    {
                        hInfo->channel_position[0] = FRONT_CHANNEL_CENTER;
                        for (i = 1; i <= ch1; i+=2)
                        {
                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
                        }
                        for (i = ch1+1; i < ch-1; i+=2)
                        {
                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
                        }
                        hInfo->channel_position[ch-1] = BACK_CHANNEL_CENTER;
                    } else {
                        for (i = 0; i < ch1; i+=2)
                        {
                            hInfo->channel_position[i] = FRONT_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = FRONT_CHANNEL_RIGHT;
                        }
                        for (i = ch1; i < ch; i+=2)
                        {
                            hInfo->channel_position[i] = BACK_CHANNEL_LEFT;
                            hInfo->channel_position[i+1] = BACK_CHANNEL_RIGHT;
                        }
                    }
                }
                hInfo->num_lfe_channels = hDecoder->has_lfe;
                for (i = ch; i < hDecoder->fr_channels; i++)
                {
                    hInfo->channel_position[i] = LFE_CHANNEL;
                }
            }
            break;
        }
    }
}
#endif

void* NEAACDECAPI NeAACDecDecode(NeAACDecHandle hDecoder,
                                 NeAACDecFrameInfo *hInfo,
                                 uint8_t *buffer, uint32_t buffer_size)
{
    return aac_frame_decode(hDecoder, hInfo, buffer, buffer_size);
}

static void* aac_frame_decode(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo,
                              uint8_t *buffer, uint32_t buffer_size)
{
    uint8_t channels = 0;
    uint8_t output_channels = 0;
    bitfile ld;
    uint32_t bitsconsumed;
    uint16_t frame_len;

#ifdef PROFILE
    int64_t count = faad_get_ts();
#endif

    /* safety checks */
    if ((hDecoder == NULL) || (hInfo == NULL) || (buffer == NULL))
    {
        return NULL;
    }

#if 0
    printf("%d\n", buffer_size*8);
#endif

    frame_len = hDecoder->frameLength;


    memset(hInfo, 0, sizeof(NeAACDecFrameInfo));
    memset(hDecoder->internal_channel, 0, MAX_CHANNELS*sizeof(hDecoder->internal_channel[0]));

    /* initialize the bitstream */
    faad_initbits(&ld, buffer, buffer_size);

#if 0
    {
        int i;
        for (i = 0; i < ((buffer_size+3)>>2); i++)
        {
            uint8_t *buf;
            uint32_t temp = 0;
            buf = faad_getbitbuffer(&ld, 32);
            //temp = getdword((void*)buf);
            temp = *((uint32_t*)buf);
            printf("0x%.8X\n", temp);
            free(buf);
        }
        faad_endbits(&ld);
        faad_initbits(&ld, buffer, buffer_size);
    }
#endif

#ifdef DRM
    if (hDecoder->object_type == DRM_ER_LC)
    {
        /* We do not support stereo right now */
        if (0) //(hDecoder->channelConfiguration == 2)
        {
            hInfo->error = 8; // Throw CRC error
            goto error;
        }

        faad_getbits(&ld, 8
            DEBUGVAR(1,1,"NeAACDecDecode(): skip CRC"));
    }
#endif

    if (hDecoder->adts_header_present)
    {
        adts_header adts;

        adts.old_format = hDecoder->config.useOldADTSFormat;
        if ((hInfo->error = adts_frame(&adts, &ld)) > 0)
            goto error;

        /* MPEG2 does byte_alignment() here,
         * but ADTS header is always multiple of 8 bits in MPEG2
         * so not needed to actually do it.
         */
    }

#ifdef ANALYSIS
    dbg_count = 0;
#endif

    /* decode the complete bitstream */
#ifdef SCALABLE_DEC
    if ((hDecoder->object_type == 6) || (hDecoder->object_type == DRM_ER_LC))
    {
        aac_scalable_main_element(hDecoder, hInfo, &ld, &hDecoder->pce, hDecoder->drc);
    } else {
#endif
        raw_data_block(hDecoder, hInfo, &ld, &hDecoder->pce, hDecoder->drc);
#ifdef SCALABLE_DEC
    }
#endif

    channels = hDecoder->fr_channels;

    if (hInfo->error > 0)
        goto error;

    /* safety check */
    if (channels == 0 || channels > MAX_CHANNELS)
    {
        /* invalid number of channels */
        hInfo->error = 12;
        goto error;
    }

    /* no more bit reading after this */
    bitsconsumed = faad_get_processed_bits(&ld);
    hInfo->bytesconsumed = bit2byte(bitsconsumed);
    if (ld.error)
    {
        hInfo->error = 14;
        goto error;
    }
    faad_endbits(&ld);


    if (!hDecoder->adts_header_present && !hDecoder->adif_header_present)
    {
        if (hDecoder->channelConfiguration == 0)
            hDecoder->channelConfiguration = channels;

        if (channels == 8) /* 7.1 */
            hDecoder->channelConfiguration = 7;
        if (channels == 7) /* not a standard channelConfiguration */
            hDecoder->channelConfiguration = 0;
    }

    if ((channels == 5 || channels == 6) && hDecoder->config.downMatrix)
    {
        hDecoder->downMatrix = 1;
        output_channels = 2;
    } else {
        output_channels = channels;
    }

#if (defined(PS_DEC) || defined(DRM_PS))
    hDecoder->upMatrix = 0;
    /* check if we have a mono file */
    if (output_channels == 1)
    {
        /* upMatrix to 2 channels for implicit signalling of PS */
        hDecoder->upMatrix = 1;
        output_channels = 2;
    }
#endif

    /* Make a channel configuration based on either a PCE or a channelConfiguration */
    /* not used by rockbox
    create_channel_config(hDecoder, hInfo);
    */

    /* number of samples in this frame */
    hInfo->samples = frame_len*output_channels;
    /* number of channels in this frame */
    hInfo->channels = output_channels;
    /* samplerate */
    hInfo->samplerate = get_sample_rate(hDecoder->sf_index);
    /* object type */
    hInfo->object_type = hDecoder->object_type;
    /* sbr */
    hInfo->sbr = NO_SBR;
    /* header type */
    hInfo->header_type = RAW;
    if (hDecoder->adif_header_present)
        hInfo->header_type = ADIF;
    if (hDecoder->adts_header_present)
        hInfo->header_type = ADTS;
#if (defined(PS_DEC) || defined(DRM_PS))
    hInfo->ps = hDecoder->ps_used_global;
#endif

    /* check if frame has channel elements */
    if (channels == 0)
    {
        hDecoder->frame++;
        return NULL;
    }

    /* allocate the buffer for the final samples */
    if (hDecoder->alloced_channels != output_channels)
    {
        hDecoder->alloced_channels = output_channels;
    }

#ifdef SBR_DEC
    if ((hDecoder->sbr_present_flag == 1) || (hDecoder->forceUpSampling == 1))
    {
        uint8_t ele;

        /* this data is different when SBR is used or when the data is upsampled */
        if (!hDecoder->downSampledSBR)
        {
            frame_len *= 2;
            hInfo->samples *= 2;
            hInfo->samplerate *= 2;
        }

        /* check if every element was provided with SBR data */
        for (ele = 0; ele < hDecoder->fr_ch_ele; ele++)
        {
            if (hDecoder->sbr[ele] == NULL)
            {
                hInfo->error = 25;
                goto error;
            }
        }

        /* sbr */
        if (hDecoder->sbr_present_flag == 1)
        {
            hInfo->object_type = HE_AAC;
            hInfo->sbr = SBR_UPSAMPLED;
        } else {
            hInfo->sbr = NO_SBR_UPSAMPLED;
        }
        if (hDecoder->downSampledSBR)
        {
            hInfo->sbr = SBR_DOWNSAMPLED;
        }
    }
#endif

    hDecoder->postSeekResetFlag = 0;

    hDecoder->frame++;
#ifdef LD_DEC
    if (hDecoder->object_type != LD)
    {
#endif
        if (hDecoder->frame <= 1)
            hInfo->samples = 0;
#ifdef LD_DEC
    } else {
        /* LD encoders will give lower delay */
        if (hDecoder->frame <= 0)
            hInfo->samples = 0;
    }
#endif

    /* cleanup */
#ifdef ANALYSIS
    fflush(stdout);
#endif

#ifdef PROFILE
    count = faad_get_ts() - count;
    hDecoder->cycles += count;
#endif

    return hDecoder; /* return void* != NULL */

error:

    faad_endbits(&ld);

    /* cleanup */
#ifdef ANALYSIS
    fflush(stdout);
#endif

    return NULL;
}
