//**************************************************************************
//*                     This file is part of the                           *
//*                      Mpxplay - audio player.                           *
//*                  The source code of Mpxplay is                         *
//*        (C) copyright 1998-2011 by PDSoft (Attila Padar)                *
//*                http://mpxplay.sourceforge.net                          *
//*                  email: mpxplay@freemail.hu                            *
//**************************************************************************
//*  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.                  *
//*  Please contact with the author (with me) if you want to use           *
//*  or modify this source.                                                *
//**************************************************************************
//function: AAC decoder handling
//requires ad_aac\aacdec.lib and faad.h

//#define MPXPLAY_USE_DEBUGF 1
#define MPXPLAY_DEBUG_OUTPUT stdout

#include "mpxplay.h"

#ifdef MPXPLAY_LINK_DECODER_AAC

#include "ad_aac\faad.h"

#define AAC_MAX_CHANNELS   8          // 7.1
#define AAC_FRAMESIZE_MAX  (AAC_MAX_CHANNELS*FAAD_MIN_STREAMSIZE)
#define AAC_BITSTREAM_BUFSIZE (AAC_FRAMESIZE_MAX*2)
#define AAC_SAMPLES_PER_FRAME_MAX 2048 // ???

#define AAC_SPECTRUM_ANALISER 1

typedef struct aac_decoder_data_s{
 mpxplay_bitstreambuf_s *bs;
 faacDecHandle hDecoder;
 faacDecFrameInfo *frameInfo;
 unsigned long pcmsamples_per_aacframe;

 int latm_size_bits;
 int latm_initialized;
 int latm_audio_mux_version_A;
 int latm_frame_length_type;
 int latm_frame_length;
 int latm_use_same_mux;
 int mux_slot_length_bytes;
}aac_decoder_data_s;

static faacDecHandle faaddec_init_dsi(unsigned char *bsbuffer,unsigned int bsbytes,faacDecFrameInfo *hInfo);
static faacDecHandle faaddec_init_frame(unsigned char *bsbuffer,unsigned int bsbytes,faacDecFrameInfo *hInfo,int bitstream_alloc_only);
static unsigned int MakeAdtsHeader(struct faacDecFrameInfo *frameInfo,unsigned char *data,unsigned int framesize);
static int ad_aac_handle_latm(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi);

static int AD_AAC_open(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct aac_decoder_data_s *aaci;
 faacDecFrameInfo *hInfo;

 aaci=(struct aac_decoder_data_s *)calloc(1,sizeof(struct aac_decoder_data_s));
 if(!aaci)
  return MPXPLAY_ERROR_INFILE_MEMORY;

 adi->private_data=aaci;

 aaci->frameInfo=(faacDecFrameInfo *)calloc(1,sizeof(faacDecFrameInfo));
 if(!aaci->frameInfo)
  return MPXPLAY_ERROR_INFILE_MEMORY;

 aaci->bs=mpxplay_bitstream_alloc(AAC_BITSTREAM_BUFSIZE);
 if(!aaci->bs)
  return MPXPLAY_ERROR_INFILE_MEMORY;

 adi->outchannels=(adi->filechannels)? adi->filechannels:2; // default assumed channels

 hInfo=aaci->frameInfo;
 hInfo->samplerate=adi->freq;
 hInfo->channels=adi->outchannels;
 hInfo->sbr_present_flag=-1;

 adi->bits=16; // scalebits in AAC decoder

 adi->infobits|=ADI_FLAG_FLOATOUT;
#ifdef AAC_SPECTRUM_ANALISER
 adi->infobits|=ADI_FLAG_OWN_SPECTANAL;
#endif

 if(adi->infobits&ADI_CNTRLBIT_BITSTREAMOUT){
  adi->infobits|=ADI_FLAG_BITSTREAMOUT;
  if(adi->infobits&ADI_CNTRLBIT_BITSTREAMNOFRH)
   adi->infobits|=ADI_FLAG_BITSTREAMNOFRH;
 }
 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"aac open sr:%d c:%d",adi->freq,adi->outchannels);

 return MPXPLAY_ERROR_INFILE_OK;
}

static void AD_AAC_close(struct mpxplay_audio_decoder_info_s *adi)
{
 struct aac_decoder_data_s *aaci=(struct aac_decoder_data_s *)adi->private_data;
 if(aaci){
  mpxplay_bitstream_free(aaci->bs);
  if(aaci->frameInfo)
   free(aaci->frameInfo);
  if(aaci->hDecoder)
   faacDecClose(aaci->hDecoder);
  free(aaci);
 }
 if(adi->chanmatrix)
  free(adi->chanmatrix);
 if(adi->channeltext)
  free(adi->channeltext);
}

static mpxp_uint8_t aac_chanmatrix_to_mpxplay[MPXPLAY_PCMOUTCHAN_MAX+1]=
{MPXPLAY_PCMOUTCHAN_DISABLED,MPXPLAY_PCMOUTCHAN_FRONT_CENTER,MPXPLAY_PCMOUTCHAN_FRONT_LEFT,
 MPXPLAY_PCMOUTCHAN_FRONT_RIGHT,MPXPLAY_PCMOUTCHAN_SIDE_LEFT,MPXPLAY_PCMOUTCHAN_SIDE_RIGHT,
 MPXPLAY_PCMOUTCHAN_REAR_LEFT,MPXPLAY_PCMOUTCHAN_REAR_RIGHT,MPXPLAY_PCMOUTCHAN_REAR_CENTER,
 MPXPLAY_PCMOUTCHAN_LFE
};

static int ad_aac_assign_values(struct mpxplay_audio_decoder_info_s *adi,faacDecFrameInfo *frameInfo)
{
 if(frameInfo->channels>AAC_MAX_CHANNELS)
  return MPXPLAY_ERROR_INFILE_CANTOPEN;

 adi->filechannels=frameInfo->channels;
 adi->outchannels=adi->filechannels;
 adi->freq=frameInfo->samplerate;
 adi->pcm_framelen=frameInfo->frameLength;

 if((adi->outchannels>2) && frameInfo->channel_position[0]){
  adi->chanmatrix=calloc(adi->outchannels,sizeof(*adi->chanmatrix));
  if(adi->chanmatrix){
   unsigned int i,lfe=0;
   for(i=0;i<adi->outchannels;i++){
    adi->chanmatrix[i]=aac_chanmatrix_to_mpxplay[frameInfo->channel_position[i]];
    if(adi->chanmatrix[i]==MPXPLAY_PCMOUTCHAN_LFE)
     lfe=1;
   }
   adi->channeltext=malloc(MPXPLAY_ADITEXTSIZE_CHANNEL+8);
   if(adi->channeltext)
    sprintf(adi->channeltext,"%d.%d chan",((lfe)? (adi->filechannels-1):adi->filechannels),((lfe)? 1:0));
  }
 }
 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"aac assign c:%d f:%d l:%d",adi->outchannels,adi->freq,adi->pcm_framelen);
 return MPXPLAY_ERROR_INFILE_OK;
}

static int AD_AAC_parse_extra(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct aac_decoder_data_s *aaci=(struct aac_decoder_data_s *)adi->private_data;
 mp4AudioSpecificConfig mp4ASC;

 if(AudioSpecificConfig(spi->extradata,spi->extradata_size*8,0,&mp4ASC)<0)
  return MPXPLAY_ERROR_INFILE_CANTOPEN;

 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"aac extra ot:%d sr:%d ch:%d s:%d",
   (long)mp4ASC.object_type,(long)mp4ASC.samplingFrequency,(long)mp4ASC.channelsConfiguration,(long)mp4ASC.sbr_present_flag);

 if((mp4ASC.sbr_present_flag==-1) && (mp4ASC.samplingFrequency<=24000))
  return MPXPLAY_ERROR_INFILE_CANTOPEN; // parse_frame follows (to detect sbr)

 aaci->hDecoder=faaddec_init_dsi(spi->extradata,spi->extradata_size,aaci->frameInfo);
 if(!aaci->hDecoder)
  return MPXPLAY_ERROR_INFILE_CANTOPEN;

 return ad_aac_assign_values(adi,aaci->frameInfo);
}

static int AD_AAC_parse_frame(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct aac_decoder_data_s *aaci=(struct aac_decoder_data_s *)adi->private_data;
 int leftbytes,latm_size_bits;

 spi->bs_usedbytes=mpxplay_bitstream_putbytes(aaci->bs,spi->bitstreambuf,spi->bs_leftbytes);

 if((latm_size_bits=ad_aac_handle_latm(adi,spi))<0)
  return latm_size_bits;
 leftbytes=(latm_size_bits)? ((latm_size_bits+7)/8):mpxplay_bitstream_leftbytes(aaci->bs);

 if(leftbytes<=0)
  return MPXPLAY_ERROR_INFILE_CANTOPEN;

 if(!aaci->hDecoder){
  aaci->hDecoder=faaddec_init_frame(mpxplay_bitstream_getbufpos(aaci->bs),leftbytes,aaci->frameInfo,0);
  if(!aaci->hDecoder)
   return MPXPLAY_ERROR_INFILE_CANTOPEN;
 }

 faacDecReadframe(aaci->hDecoder,aaci->frameInfo,mpxplay_bitstream_getbufpos(aaci->bs),leftbytes);

 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"parse3 lb:%d ls:%d bc:%d",mpxplay_bitstream_leftbytes(aaci->bs),latm_size_bits,aaci->frameInfo->bytesconsumed);

 if(latm_size_bits){
  mpxplay_bitstream_skipbits(aaci->bs,latm_size_bits);
  mpxplay_bitstream_consolidate(aaci->bs,1);
 }else if(aaci->frameInfo->bytesconsumed>0)
  mpxplay_bitstream_skipbytes(aaci->bs,aaci->frameInfo->bytesconsumed);
 else
  mpxplay_bitstream_reset(aaci->bs);

 if((aaci->frameInfo->bytesconsumed>0) && (aaci->frameInfo->error==0) && aaci->frameInfo->samplerate && aaci->frameInfo->channels)
  return ad_aac_assign_values(adi,aaci->frameInfo);

 return MPXPLAY_ERROR_INFILE_CANTOPEN;
}

static int AD_AAC_decode(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct aac_decoder_data_s *aaci=(struct aac_decoder_data_s *)adi->private_data;
 void *sample_buffer;
 int retcode,leftbytes,latm_size_bits;
#ifdef MPXPLAY_USE_DEBUGF
 static unsigned long allbytes;
#endif
 faacDecFrameInfo frameInfo;
 pds_memset(&frameInfo,0,sizeof(frameInfo));

#ifdef MPXPLAY_USE_DEBUGF
 if((aaci->bs->bitpos&7) || (aaci->bs->storedbits&7))
  mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"decode1 bitpos error bi:%d sb:%d",aaci->bs->bitpos,aaci->bs->storedbits&7);
#endif

 spi->bs_usedbytes=mpxplay_bitstream_putbytes(aaci->bs,spi->bitstreambuf,spi->bs_leftbytes);

 if((latm_size_bits=ad_aac_handle_latm(adi,spi))<0){
  mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"decode2 ls:%4d als:%d bi:%d lb:%3d",latm_size_bits,aaci->latm_size_bits,(aaci->bs->bitpos&7),mpxplay_bitstream_leftbytes(aaci->bs));
  return latm_size_bits;
 }
 leftbytes=(latm_size_bits)? ((latm_size_bits+7)/8):mpxplay_bitstream_leftbytes(aaci->bs);
 if(leftbytes<=0)
  retcode=MPXPLAY_ERROR_INFILE_NODATA;
 else
  retcode=MPXPLAY_ERROR_INFILE_RESYNC;

/*#ifdef MPXPLAY_USE_DEBUGF
 if(!latm_size_bits)
  mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"decode3 ls:%4d als:%d bi:%d lb:%3d",latm_size_bits,aaci->latm_size_bits,(aaci->bs->bitpos&7),leftbytes);
#endif*/

 if(adi->infobits&ADI_CNTRLBIT_BITSTREAMOUT){
  //faacDecReadframe(aaci->hDecoder,&frameInfo,mpxplay_bitstream_getbufpos(aaci->bs),leftbytes);
  sample_buffer=faacDecDecode(aaci->hDecoder,&frameInfo,mpxplay_bitstream_getbufpos(aaci->bs),leftbytes);
  if(frameInfo.bytesconsumed>0){
   //if((frameInfo.error==0) && frameInfo.samplerate && frameInfo.channels){
   if(sample_buffer && (frameInfo.error==0) && frameInfo.samplerate && frameInfo.channels){
    unsigned int headersize=0;
    if(!(adi->infobits&ADI_CNTRLBIT_BITSTREAMNOFRH))
     headersize=MakeAdtsHeader(aaci->frameInfo,adi->pcm_bufptr,frameInfo.bytesconsumed);
    pds_memcpy(adi->pcm_bufptr+headersize,mpxplay_bitstream_getbufpos(aaci->bs),frameInfo.bytesconsumed);
    adi->pcm_samplenum=headersize+frameInfo.bytesconsumed;
    retcode=MPXPLAY_ERROR_INFILE_OK;
   }
  }
 }else{
  sample_buffer = faacDecDecode(aaci->hDecoder,&frameInfo,mpxplay_bitstream_getbufpos(aaci->bs),leftbytes);
  if(frameInfo.bytesconsumed>0){
   if(sample_buffer && (frameInfo.error==0) && (frameInfo.bytesconsumed>0) && (frameInfo.samples>=adi->outchannels) && (frameInfo.samples<=spi->bs_bufsize)){
    pds_memcpy(adi->pcm_bufptr,sample_buffer,frameInfo.samples*sizeof(MPXPLAY_PCMOUT_FLOAT_T));
    adi->pcm_samplenum=frameInfo.samples;
    retcode=MPXPLAY_ERROR_INFILE_OK;
   }
  }
 }

#ifdef MPXPLAY_USE_DEBUGF
 allbytes+=leftbytes;
 //if((frameInfo.bytesconsumed<1) && !aaci->latm_use_same_mux){
 if((frameInfo.bytesconsumed<1) || (frameInfo.error!=0)){
  mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"decode4 als:%d lb:%d ab:%d bi:%d bc:%3d rc:%d e:%d sm:%d mv:%d lb:%d ft:%d",
   aaci->latm_size_bits,leftbytes,allbytes,aaci->bs->storedbits&7,frameInfo.bytesconsumed,retcode,frameInfo.error,
   aaci->latm_use_same_mux,aaci->latm_audio_mux_version_A,aaci->mux_slot_length_bytes,aaci->latm_frame_length_type);
 }
#endif

 if(latm_size_bits){
  mpxplay_bitstream_skipbits(aaci->bs,latm_size_bits);
  mpxplay_bitstream_consolidate(aaci->bs,1);
 }else if(frameInfo.bytesconsumed>0)
  mpxplay_bitstream_skipbytes(aaci->bs,frameInfo.bytesconsumed);
 else
  mpxplay_bitstream_reset(aaci->bs);

 return retcode;
}

void AD_AAC_clearbuff(struct mpxplay_audio_decoder_info_s *adi,unsigned int seektype)
{
 struct aac_decoder_data_s *aaci=(struct aac_decoder_data_s *)adi->private_data;
 mpxplay_bitstream_reset(aaci->bs);
 if(seektype&(MPX_SEEKTYPE_BOF|MPX_SEEKTYPE_PAUSE)){
#ifdef AAC_SPECTRUM_ANALISER
  aac_analiser_clear();
#endif
 }
}

//------------------------------------------------------------------
static faacDecHandle faaddec_init_dsi(unsigned char *bsbuffer,unsigned int bsbytes,faacDecFrameInfo *hInfo)
{
 faacDecHandle hDecoder;
 faacDecConfigurationPtr config;

 hDecoder=faacDecOpen();
 if(!hDecoder)
  return hDecoder;

 config = faacDecGetCurrentConfiguration(hDecoder);
 config->defSBRpresentflag= hInfo->sbr_present_flag;
 config->defChannels      = hInfo->channels;
 if(hInfo->samplerate)
  config->defSampleRate   = hInfo->samplerate;
 config->outputFormat  = FAAD_FMT_FLOAT;
 //config->downMatrix    = 1;

 if(faacDecInit_dsi(hDecoder,bsbuffer,bsbytes*8,0,hInfo)<0)
  goto err_out_dsi;

 if(!faacDecInitFields(hDecoder,hInfo))
  goto err_out_dsi;

 return hDecoder;

err_out_dsi:
 faacDecClose(hDecoder);
 return NULL;
}

//init the decoder using the first frame(s)
static faacDecHandle faaddec_init_frame(unsigned char *bsbuffer,
  unsigned int bsbytes,faacDecFrameInfo *hInfo,int bitstream_alloc_only)
{
 faacDecHandle hDecoder;
 faacDecConfigurationPtr config;
 faacDecFrameInfo frameInfo;

 hDecoder=faacDecOpen();
 if(!hDecoder)
  return hDecoder;

 config = faacDecGetCurrentConfiguration(hDecoder);
 config->defObjectType    = hInfo->object_type;
 config->defSBRpresentflag= hInfo->sbr_present_flag;
 config->defChannels      = hInfo->channels;
 if(hInfo->samplerate)
  config->defSampleRate   = hInfo->samplerate;

 config->outputFormat    = FAAD_FMT_FLOAT;
 //config->downMatrix      = 1;

 if(faacDecInit_frame(hDecoder,bsbuffer,bsbytes,&frameInfo)!=0)
  goto err_out_initfr;

 memcpy(hInfo,(void *)&frameInfo,sizeof(faacDecFrameInfo));

 if(bitstream_alloc_only){
  if(!faacDecInitField_bs(hDecoder))
   goto err_out_initfr;
 }else{
  if(!faacDecInitFields(hDecoder,hInfo))
   goto err_out_initfr;
 }

 return hDecoder;

err_out_initfr:
 faacDecClose(hDecoder);
 return NULL;
}

static unsigned int MakeAdtsHeader(struct faacDecFrameInfo *frameInfo,unsigned char *data,unsigned int framesize)
{
 int profile;

 profile = frameInfo->object_type;
 profile&=3;

 pds_memset(data,0,7);

 framesize+=7;

 data[0]  = 0xFF; // 8b: syncword
 data[1]  = 0xF0; // 4b: syncword
                  // 1b: mpeg id = 0
                  // 2b: layer = 0
 data[1] |= 0x01; // 1b: protection absent

 data[2]  = ((profile << 6) & 0xC0);             // 2b: profile
 data[2] |= ((frameInfo->sf_index << 2) & 0x3C); // 4b: sampling_frequency_index
                                                 // 1b: private = 0
 data[2] |= ((frameInfo->channels >> 2) & 0x1);  // 1b: channel_configuration

 data[3]  = ((frameInfo->channels << 6) & 0xC0); // 2b: channel_configuration
                                       // 1b: original
                                       // 1b: home
                                       // 1b: copyright_id
                                       // 1b: copyright_id_start
 data[3] |= ((framesize >> 11) & 0x3); // 2b: aac_frame_length

 data[4]  = ((framesize >> 3) & 0xFF); // 8b: aac_frame_length

 data[5]  = ((framesize << 5) & 0xE0); // 3b: aac_frame_length
 data[5] |= ((0x7FF >> 6) & 0x1F);     // 5b: adts_buffer_fullness

 data[6]  = ((0x7FF << 2) & 0x3F);     // 6b: adts_buffer_fullness
                                       // 2b: num_raw_data_blocks
 return 7;
}

//----------------------------------------------------------------------
#define AAC_LATM_HEADER     0x56e000  // 0x2b7 (11 bits)
#define AAC_LATM_HEADMASK   0xFFE000  // top 11 bits
#define AAC_LATM_SIZE_MASK  0x001FFF  // bottom 13 bits
#define AAC_LATM_HEADSIZE   3         // bytes

/*static unsigned int ad_aac_get_latmsize(mpxplay_bitstreambuf_s *bs)
{
 do{
  mpxp_uint8_t *bsbuf=mpxplay_bitstream_getbufpos(bs);
  mpxp_uint32_t head=PDS_GETB_BE24(bsbuf);
  if((head&AAC_LATM_HEADMASK)==AAC_LATM_HEADER)
   return (head&AAC_LATM_SIZE_MASK);
  mpxplay_bitstream_skipbytes(bs,1);
 }while(mpxplay_bitstream_leftbytes(bs)>AAC_LATM_HEADSIZE);
 return 0;
}*/

static unsigned int ad_aac_get_latmsize(mpxplay_bitstreambuf_s *bs)
{
 mpxp_uint8_t *bsbuf=mpxplay_bitstream_getbufpos(bs);
 mpxp_uint32_t head=PDS_GETB_BE24(bsbuf);
 if((head&AAC_LATM_HEADMASK)==AAC_LATM_HEADER)
  return (head&AAC_LATM_SIZE_MASK);
 return 0;
}

static int latm_get_value(mpxplay_bitstreambuf_s *bs)
{
 int length = mpxplay_bitstream_getbits_be24(bs, 2);
 return mpxplay_bitstream_getbits_ube32(bs, (length+1)*8);
}

static int latm_decode_audio_specific_config(struct aac_decoder_data_s *aaci)
{
 long usedbits;
 unsigned long bitindex=aaci->bs->bitpos&7,maxbits_to_process=bitindex+16; // ??? !!!
 mp4AudioSpecificConfig mp4ASC;

 //mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"latm audio specific config %d",(aaci->bs->bitpos&7));

 if((usedbits=AudioSpecificConfig(mpxplay_bitstream_getbufpos(aaci->bs),maxbits_to_process,bitindex,&mp4ASC))<0)
  return usedbits;

 mpxplay_bitstream_skipbits(aaci->bs,usedbits);

 if(!aaci->hDecoder){
  faacDecFrameInfo *hInfo=aaci->frameInfo;
  hInfo->object_type=mp4ASC.object_type;
  hInfo->samplerate=mp4ASC.samplingFrequency;
  hInfo->channels=mp4ASC.channelsConfiguration;
  hInfo->sbr_present_flag=mp4ASC.sbr_present_flag;
  mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"latm audio specific ub:%d ot:%d sr:%d ch:%d s:%d",usedbits,
   (long)mp4ASC.object_type,(long)mp4ASC.samplingFrequency,(long)mp4ASC.channelsConfiguration,(long)mp4ASC.sbr_present_flag);
 }

 return usedbits;
}

static int latm_read_stream_mux_config(struct aac_decoder_data_s *aaci)
{
 int ret, audio_mux_version = mpxplay_bitstream_getbit1_be(aaci->bs);

 aaci->latm_audio_mux_version_A = 0;
 if(audio_mux_version)
  aaci->latm_audio_mux_version_A = mpxplay_bitstream_getbit1_be(aaci->bs);

 if(!aaci->latm_audio_mux_version_A){

  if(audio_mux_version)
   latm_get_value(aaci->bs); // taraFullness

  mpxplay_bitstream_skipbits(aaci->bs, 1); // allStreamSameTimeFraming
  mpxplay_bitstream_skipbits(aaci->bs, 6); // numSubFrames
  if(mpxplay_bitstream_getbits_be24(aaci->bs, 4)){ // numPrograms
   mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"multiple programs are not supported");
   return MPXPLAY_ERROR_INFILE_CANTOPEN;
  }

  if(mpxplay_bitstream_getbits_be24(aaci->bs, 3)){ // numLayer
   mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"multiple layers are not supported");
   return MPXPLAY_ERROR_INFILE_CANTOPEN;
  }

  if(audio_mux_version){
   int asc_len = latm_get_value(aaci->bs);
   if((ret = latm_decode_audio_specific_config(aaci)) < 0)
    return ret;
   if(asc_len<ret)
    return MPXPLAY_ERROR_INFILE_CANTOPEN;
   asc_len -= ret;
   mpxplay_bitstream_skipbits(aaci->bs, asc_len);
  }else{
   if((ret = latm_decode_audio_specific_config(aaci)) < 0)
    return ret;
  }

  aaci->latm_frame_length_type = mpxplay_bitstream_getbits_be24(aaci->bs, 3);
  switch(aaci->latm_frame_length_type){
   case 0:mpxplay_bitstream_skipbits(aaci->bs, 8); // latmBufferFullness
          break;
   case 1:aaci->latm_frame_length = mpxplay_bitstream_getbits_be24(aaci->bs, 9);
          break;
   case 3:
   case 4:
   case 5:mpxplay_bitstream_skipbits(aaci->bs, 6); // CELP frame length table index
          break;
   case 6:
   case 7:mpxplay_bitstream_skipbits(aaci->bs, 1); // HVXC frame length table index
          break;
  }

  if(mpxplay_bitstream_getbit1_be(aaci->bs)){  // other data
   if(audio_mux_version) {
    latm_get_value(aaci->bs);
   }else{
    int esc;
    do{
     esc = mpxplay_bitstream_getbit1_be(aaci->bs);
     mpxplay_bitstream_skipbits(aaci->bs, 8);
    }while (esc);
   }
  }

  if(mpxplay_bitstream_getbit1_be(aaci->bs)) // crc present
   mpxplay_bitstream_skipbits(aaci->bs, 8); // config_crc
 }

 return 0;
}

static int latm_read_payload_length_info(struct aac_decoder_data_s *aaci)
{
 int mux_slot_length=0,tmp;

 switch(aaci->latm_frame_length_type){
  case 0:do{
          tmp = mpxplay_bitstream_getbits_be24(aaci->bs, 8);
          mux_slot_length += tmp;
         }while(tmp==255);
         break;
  case 1:mux_slot_length=aaci->latm_frame_length;break;
  case 3:
  case 5:
  case 7:mpxplay_bitstream_skipbits(aaci->bs, 2);
 }
 return mux_slot_length;
}

static int latm_read_audio_mux_element(struct aac_decoder_data_s *aaci)
{
 int err;
 aaci->mux_slot_length_bytes = 0;
 aaci->latm_use_same_mux = mpxplay_bitstream_getbit1_be(aaci->bs);
 if(!aaci->latm_use_same_mux){
  if((err = latm_read_stream_mux_config(aaci))<0)
   return err;
 }
 if(!aaci->latm_audio_mux_version_A){
  aaci->mux_slot_length_bytes = latm_read_payload_length_info(aaci);
  if(aaci->mux_slot_length_bytes > mpxplay_bitstream_leftbytes(aaci->bs)){
   mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"incomplete frame sb:%d lb:%d",aaci->mux_slot_length_bytes,mpxplay_bitstream_leftbytes(aaci->bs));
   return MPXPLAY_ERROR_INFILE_CANTOPEN;
  }else if((aaci->mux_slot_length_bytes*8+256) < aaci->latm_size_bits){
   mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"frame length mismatch %d << %d\n",
    (aaci->mux_slot_length_bytes*8+256),aaci->latm_size_bits);
   return MPXPLAY_ERROR_INFILE_CANTOPEN;
  }
 }
 return 0;
}

static int ad_aac_handle_latm(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct aac_decoder_data_s *aaci=(struct aac_decoder_data_s *)adi->private_data;
 unsigned int startbits;
 //mpxp_uint8_t *bsbuf;
 int retcode;

 if(spi->wave_id!=MPXPLAY_WAVEID_LATMAAC)
  return 0;

 aaci->latm_size_bits=ad_aac_get_latmsize(aaci->bs);

 if(!aaci->latm_size_bits || (aaci->latm_size_bits>=aaci->bs->bufsize)){
  mpxplay_bitstream_reset(aaci->bs);
  return MPXPLAY_ERROR_INFILE_NODATA;
 }
 if(aaci->latm_size_bits>mpxplay_bitstream_leftbytes(aaci->bs))
  return MPXPLAY_ERROR_INFILE_NODATA;

 mpxplay_bitstream_skipbytes(aaci->bs,AAC_LATM_HEADSIZE);

 aaci->latm_size_bits*=8;

 startbits=mpxplay_bitstream_leftbits(aaci->bs);

 if((retcode=latm_read_audio_mux_element(aaci))<0)
  return retcode;

 if(startbits>=mpxplay_bitstream_leftbits(aaci->bs)){
  startbits-=mpxplay_bitstream_leftbits(aaci->bs);
  if(aaci->latm_size_bits>startbits)
   aaci->latm_size_bits-=startbits;
 }

#ifdef MPXPLAY_USE_DEBUGF
 {
  int i;
  unsigned int leftbytes=(aaci->latm_size_bits+7)/8;
  unsigned char *bufpos=mpxplay_bitstream_getbufpos(aaci->bs);
  for(i=0;i<leftbytes;i++){
   fprintf(stdout,"%2.2X",bufpos[i]);
   if(i && !(i&31))
    fprintf(stdout,"\n");
  }
  fprintf(stdout,"\n 1. lb:%d bp:%d sb:%d ------------------------------\n",leftbytes,aaci->bs->bitpos,aaci->bs->storedbits);
 }
#endif

 mpxplay_bitstream_consolidate(aaci->bs,1);

#ifdef MPXPLAY_USE_DEBUGF
 {
  int i;
  unsigned int leftbytes=(aaci->latm_size_bits+7)/8;
  unsigned char *bufpos=mpxplay_bitstream_getbufpos(aaci->bs);
  for(i=0;i<leftbytes;i++){
   fprintf(stdout,"%2.2X",bufpos[i]);
   if(i && !(i&31))
    fprintf(stdout,"\n");
  }
  fprintf(stdout,"\n 2. lb:%d bp:%d sb:%d ------------------------------\n",leftbytes,aaci->bs->bitpos,aaci->bs->storedbits);
 }
#endif

 /*bsbuf=mpxplay_bitstream_getbufpos(aaci->bs)+aaci->latm_size_bits/8;
 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT,"LATM3 ls:%4X sb:%3d bi:%d bp:%3d stb:%5d %2.2X%2.2X%2.2X %2.2X%2.2X%2.2X%2.2X%2.2X ",
  aaci->latm_size_bits,startbits,(aaci->bs->bitpos&7),aaci->bs->bitpos,aaci->bs->storedbits,
  (mpxp_uint32_t)bsbuf[0],(mpxp_uint32_t)bsbuf[1],(mpxp_uint32_t)bsbuf[2],(mpxp_uint32_t)bsbuf[3],
  (mpxp_uint32_t)bsbuf[4],(mpxp_uint32_t)bsbuf[5],(mpxp_uint32_t)bsbuf[6]);*/

 return aaci->latm_size_bits;
}

//----------------------------------------------------------------------

struct mpxplay_audio_decoder_func_s AD_AAC_funcs={
 0,
 NULL,
 NULL,
 NULL,
 &AD_AAC_open,
 &AD_AAC_close,
 &AD_AAC_parse_extra,
 &AD_AAC_parse_frame,
 &AD_AAC_decode,
 &AD_AAC_clearbuff,
 NULL,
 NULL,
 AAC_FRAMESIZE_MAX,
 AAC_SAMPLES_PER_FRAME_MAX,
 {{MPXPLAY_WAVEID_AAC,"AAC"},{0x00ff,"AAC"},
 {0x4143,"AAC"},{MPXPLAY_WAVEID_LATMAAC,"AAC"},
 {0,NULL}}
};

#endif // MPXPLAY_LINK_DECODER_AAC
