//**************************************************************************
//*                     This file is part of the                           *
//*                      Mpxplay - audio player.                           *
//*                  The source code of Mpxplay is                         *
//*        (C) copyright 1998-2006 by PDSoft (Attila Padar)                *
//*                    http://mpxplay.cjb.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: DTS decoder handling
//requires the ad_dts\dtsdec.lib and dts.h files

#include "in_file.h"

#ifdef MPXPLAY_LINK_DECODER_DTS

#include "newfunc\newfunc.h"
#include "ad_dts\dts.h"

#define DTS_OUTCHANNELS 2

#define DTS_HEADERSIZE    14
#define DTS_FRAMESIZE_MIN 96
#define DTS_FRAMESIZE_MAX 18726
#define DTS_BLOCKSAMPLES  256

#define DTS_BITSTREAM_BUFSIZE (DTS_FRAMESIZE_MAX*2)

#define DTS_SYNC_RETRY_BYTE   (DTS_FRAMESIZE_MAX*8)
#define DTS_SYNC_RETRY_FRAME  64

#define DTS_GOODFRAME_LIMIT 2

//#define ADDTS_DEBUG 1

typedef struct dts_decoder_data_s{
 mpxplay_bitstreambuf_s *bs;
 dts_state_t *dtsstate;
 int info_flags;
 int sample_rate;
 int bit_rate;
 int frame_length;

 int config_flags;
 level_t config_level;

 int lastframesize;
 int blockcount;

 unsigned int goodframe_count;
}dts_decoder_data_s;

static const unsigned int dts_channums[]={
 1,  // DTS_MONO             0
 2,  // DTS_CHANNEL          1 // ???
 2,  // DTS_STEREO           2
 2,  // DTS_STEREO_SUMDIFF   3
 2,  // DTS_STEREO_TOTAL     4
 3,  // DTS_3F               5
 3,  // DTS_2F1R             6
 4,  // DTS_3F1R             7
 4,  // DTS_2F2R             8
 5,  // DTS_3F2R             9
 6,  // DTS_4F2R            10
 6,6,7,8,8
};

static int ad_dts_sync_frame(struct dts_decoder_data_s *dtsi);

static int AD_DTS_open(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct dts_decoder_data_s *dtsi;

 dtsi=calloc(1,sizeof(struct dts_decoder_data_s));
 if(!dtsi)
  return MPXPLAY_ERROR_INFILE_MEMORY;

 adi->private_data=dtsi;

 dtsi->dtsstate=dts_init(0);
 if(!dtsi->dtsstate)
  return MPXPLAY_ERROR_INFILE_MEMORY;

 dtsi->bs=mpxplay_bitstream_alloc(DTS_BITSTREAM_BUFSIZE);
 if(!dtsi->bs)
  return MPXPLAY_ERROR_INFILE_MEMORY;

 adi->outchannels=DTS_OUTCHANNELS;
 adi->bits=1;  // output scale : +1.0 ... -1.0
 adi->infobits|=ADI_FLAG_FLOATOUT;

 if(adi->infobits&ADI_CNTRLBIT_BITSTREAMOUT)
  adi->infobits|=ADI_FLAG_BITSTREAMOUT;

 dtsi->config_flags=DTS_STEREO;//|DTS_ADJUST_LEVEL;
 //dtsi->config_level=(level_t)32768.0; // ???

 return MPXPLAY_ERROR_INFILE_OK;
}

static void AD_DTS_close(struct mpxplay_audio_decoder_info_s *adi)
{
 struct dts_decoder_data_s *dtsi=(struct dts_decoder_data_s *)adi->private_data;
 if(dtsi){
  mpxplay_bitstream_free(dtsi->bs);
  dts_free(dtsi->dtsstate);
  if(adi->channeltext)
   free(adi->channeltext);
  free(dtsi);
 }
}

static int ad_dts_parse_finalize(struct mpxplay_audio_decoder_info_s *adi)
{
 struct dts_decoder_data_s *dtsi=(struct dts_decoder_data_s *)adi->private_data;

 adi->freq=dtsi->sample_rate;
 adi->filechannels=dts_channums[dtsi->info_flags&DTS_CHANNEL_MASK];
 if(dtsi->info_flags&DTS_LFE)
  adi->filechannels++;

 adi->bitrate=(dtsi->bit_rate+500)/1000;

 adi->pcm_framelen=dtsi->blockcount*DTS_BLOCKSAMPLES; // ??? constant?

 adi->channeltext=malloc(MPXPLAY_ADITEXTSIZE_CHANNEL+8);
 if(!adi->channeltext)
  return MPXPLAY_ERROR_INFILE_MEMORY;
 sprintf(adi->channeltext,"%d.%d chan",dts_channums[dtsi->info_flags&DTS_CHANNEL_MASK],((dtsi->info_flags&DTS_LFE)? 1:0));

 return MPXPLAY_ERROR_INFILE_OK;
}

/*static int AD_DTS_parse_extra(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct dts_decoder_data_s *dtsi=(struct dts_decoder_data_s *)adi->private_data;
 int framesize;

 framesize=dts_syncinfo(dtsi->dtsstate,spi->extradata,&dtsi->info_flags,&dtsi->sample_rate,&dtsi->bit_rate,&dtsi->frame_length);
 if(framesize<=0)
  return MPXPLAY_ERROR_INFILE_CANTOPEN;

 if(!spi->bs_framesize)
  spi->bs_framesize=framesize;

 return ad_dts_parse_finalize(adi);
}*/

static int AD_DTS_parse_frame(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct dts_decoder_data_s *dtsi=(struct dts_decoder_data_s *)adi->private_data;
 int retcode;

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

 retcode=ad_dts_sync_frame(dtsi);
 if(retcode!=MPXPLAY_ERROR_INFILE_OK)
  return retcode;

 if(!spi->bs_framesize)
  spi->bs_framesize=dtsi->lastframesize;

 return ad_dts_parse_finalize(adi);
}

static int AD_DTS_decode(struct mpxplay_audio_decoder_info_s *adi,struct mpxplay_streampacket_info_s *spi)
{
 struct dts_decoder_data_s *dtsi=(struct dts_decoder_data_s *)adi->private_data;
 MPXPLAY_PCMOUT_FLOAT_T *pcmout=(MPXPLAY_PCMOUT_FLOAT_T *)adi->pcm_bufptr;
 sample_t *dtsout;
 unsigned int i,ch;
 int retcode;

 if(adi->infobits&ADI_CNTRLBIT_BITSTREAMOUT){
  spi->bs_usedbytes=mpxplay_bitstream_putbytes(dtsi->bs,spi->bitstreambuf,spi->bs_leftbytes);
  retcode=ad_dts_sync_frame(dtsi);
  if(retcode!=MPXPLAY_ERROR_INFILE_OK)
   return retcode;
  mpxplay_bitstream_readbytes(dtsi->bs,adi->pcm_bufptr,dtsi->lastframesize);
  adi->pcm_samplenum=dtsi->lastframesize;
  return MPXPLAY_ERROR_INFILE_OK;
 }

 if(dtsi->lastframesize){
  mpxplay_bitstream_skipbytes(dtsi->bs,dtsi->lastframesize);
  dtsi->lastframesize=0;
 }
 spi->bs_usedbytes=mpxplay_bitstream_putbytes(dtsi->bs,spi->bitstreambuf,spi->bs_leftbytes);
 retcode=ad_dts_sync_frame(dtsi);
 if(retcode!=MPXPLAY_ERROR_INFILE_OK)
  return retcode;

 do{
  MPXPLAY_PCMOUT_FLOAT_T *pcmptr;
  if(dts_block(dtsi->dtsstate)<0){
   dtsi->blockcount=0;
   dtsi->goodframe_count=0;
#ifdef ADDTS_DEBUG
   pds_textdisplay_printf("dts_block failed");
#endif
   return MPXPLAY_ERROR_INFILE_RESYNC;
  }
  dtsout=dts_samples(dtsi->dtsstate);
  pcmptr=pcmout;

  for(ch=0;ch<DTS_OUTCHANNELS;ch++){
   for(i=0;i<DTS_BLOCKSAMPLES;i++){
    *pcmptr=(MPXPLAY_PCMOUT_FLOAT_T)(*dtsout);
    pcmptr+=DTS_OUTCHANNELS;
    dtsout++;
   }
   pcmptr-=(DTS_BLOCKSAMPLES*DTS_OUTCHANNELS-1);
  }
  pcmout+=DTS_BLOCKSAMPLES*DTS_OUTCHANNELS;
  adi->pcm_samplenum+=DTS_BLOCKSAMPLES*DTS_OUTCHANNELS;
 }while(--dtsi->blockcount);

 return MPXPLAY_ERROR_INFILE_OK;
}

static void AD_DTS_clearbuff(struct mpxplay_audio_decoder_info_s *adi,unsigned int seektype)
{
 struct dts_decoder_data_s *dtsi=(struct dts_decoder_data_s *)adi->private_data;
 mpxplay_bitstream_reset(dtsi->bs);
 dtsi->blockcount=0;
 dtsi->lastframesize=0;
 dtsi->goodframe_count=0;
 if(seektype&(MPX_SEEKTYPE_BOF|MPX_SEEKTYPE_PAUSE))
  dts_reset(dtsi->dtsstate);
}

//------------------------------------------------------------------------
static int ad_dts_sync_frame(struct dts_decoder_data_s *dtsi)
{
 unsigned int retry_frame=DTS_SYNC_RETRY_FRAME;
 unsigned int retry_byte=DTS_SYNC_RETRY_BYTE;
#ifdef ADDTS_DEBUG
 char sout[100];
#endif

 do{
  int framesize;
  if(mpxplay_bitstream_leftbytes(dtsi->bs)<DTS_HEADERSIZE)
   return MPXPLAY_ERROR_INFILE_NODATA;

  framesize=dts_syncinfo(dtsi->dtsstate,mpxplay_bitstream_getbufpos(dtsi->bs),&dtsi->info_flags,&dtsi->sample_rate,&dtsi->bit_rate,&dtsi->frame_length);
  if(framesize<=0){
   dtsi->goodframe_count=0;
   mpxplay_bitstream_skipbytes(dtsi->bs,1);
   if(!(--retry_byte))
    break;
   continue;
  }
#ifdef ADDTS_DEBUG
  sprintf(sout,"lb: %4d fs:%4d %8.8X ",mpxplay_bitstream_leftbytes(dtsi->bs),framesize,PDS_GETB_BE32(mpxplay_bitstream_getbufpos(dtsi->bs)));
  pds_textdisplay_printf(sout);
#endif

  if(mpxplay_bitstream_leftbytes(dtsi->bs)<framesize)
   return MPXPLAY_ERROR_INFILE_NODATA;

  if(dts_frame(dtsi->dtsstate,mpxplay_bitstream_getbufpos(dtsi->bs),&dtsi->config_flags,&dtsi->config_level,0)==0){
   dtsi->goodframe_count++;
   if(dtsi->goodframe_count>=DTS_GOODFRAME_LIMIT){
    dtsi->blockcount=dts_blocks_num(dtsi->dtsstate);
    dts_dynrng(dtsi->dtsstate,NULL,NULL);
    dtsi->lastframesize=framesize;
    return MPXPLAY_ERROR_INFILE_OK;
   }else{
    mpxplay_bitstream_skipbytes(dtsi->bs,framesize);
    continue;
   }
  }
#ifdef ADDTS_DEBUG
  sprintf(sout,"gfc:%d cf:%4.4X",dtsi->goodframe_count,(dtsi->config_flags&DTS_CHANNEL_MASK));
  pds_textdisplay_printf(sout);
#endif

  dtsi->goodframe_count=0;
  mpxplay_bitstream_skipbytes(dtsi->bs,framesize); // skips frame on error

  if(!(--retry_frame))
   break;

 }while(1);

 return MPXPLAY_ERROR_INFILE_EOF;
}

struct mpxplay_audio_decoder_func_s AD_DTS_funcs={
 0,
 NULL,
 NULL,
 &AD_DTS_open,
 &AD_DTS_close,
 NULL,//&AD_DTS_parse_extra,
 &AD_DTS_parse_frame,
 &AD_DTS_decode,
 &AD_DTS_clearbuff,
 NULL,
 NULL,
 DTS_FRAMESIZE_MAX,
 DTS_BLOCKSAMPLES*16,
 {{MPXPLAY_WAVEID_DTS,"DTS"},{0,NULL}}
};

#endif // MPXPLAY_LINK_DECODER_DTS
