/***************************************************************************
                          ADM_codecwma.cpp  -  description
                             -------------------
        We do also AMR here                      
                             
    begin                : Tue Nov 12 2002
    copyright            : (C) 2002 by mean
    email                : fixounet@free.fr
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ADM_assert.h>
#include <math.h>

#include "config.h"
#include "ADM_lavcodec.h"

#include "fourcc.h"

#include "ADM_audio/aviaudio.hxx"
#include "ADM_audiocodec/ADM_audiocodec.h"
#include "ADM_audiocodec/ADM_audiocodec.h"

#define _context ((AVCodecContext *)_contextVoid)


   uint8_t ADM_AudiocodecWMA::beginDecompress( void ) 
   {
            _tail=_head=0;
            return 1;
   };
   uint8_t ADM_AudiocodecWMA::endDecompress( void ) 
   {
          _tail=_head=0;
          return 1;
   };
   
 ADM_AudiocodecWMA::ADM_AudiocodecWMA(uint32_t fourcc,WAVHeader *info,uint32_t l,uint8_t *d)
       :  ADM_Audiocodec(fourcc)
 {
    _tail=_head=0;
    ADM_assert(fourcc==WAV_WMA);	
    _contextVoid=(void *)avcodec_alloc_context();
    ADM_assert(_contextVoid);
    // Fills in some values...
    _context->sample_rate = info->frequency;
    
    _context->channels = info->channels;
    /*
    _context->bit_rate = info->byterate<<3; // byte -> bits
    */
//    _context->fourcc = fourcc;
    _context->block_align = info->blockalign;       // ...
    _context->codec_id = CODEC_ID_WMAV2;
    _blockalign=info->blockalign;
  
    _context->extradata=(void *)d;
    _context->extradata_size=(int)l;

    printf(" Using %ld bytes of extra header data\n",l);
    mixDump((uint8_t *)_context->extradata,_context->extradata_size);
    if (avcodec_open(_context, &wmav2_decoder) < 0) 
    {
        printf("\n WMA decoder init failed !\n");
        ADM_assert(0);
    }
    printf("FFwma init successful (blockalign %d)\n",info->blockalign);
}
 ADM_AudiocodecWMA::~ADM_AudiocodecWMA()
 {
        avcodec_close(_context);
        ADM_dealloc(_context);
        _contextVoid=NULL;
}    
/*-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------*/

uint8_t ADM_AudiocodecWMA::run( uint8_t * ptr, uint32_t nbIn, uint8_t * outptr,   uint32_t * nbOut)
{
int out=0;
int max=0,pout=0;

        *nbOut=0;
        // Shrink
        if(_head && (_tail+nbIn)*3>ADMWA_BUF*2)
        {
            memmove(_buffer,_buffer+_head,_tail-_head);
            _tail-=_head;
            _head=0;
        }
        //
        ADM_assert(nbIn+_tail<ADMWA_BUF);
        memcpy(_buffer+_tail,ptr,nbIn);
        _tail+=nbIn;
        while(_tail-_head>_blockalign)
        {
                out=avcodec_decode_audio(_context,(int16_t *)outptr,&pout,_buffer+_head,_tail-_head);
                //printf("Align:%d In: %d out:%d\n",_blockalign,out,pout);
                if(out<0)
                {
                        printf( " *** WMA decoding error ***\n");
                        _head+=1; // Try skipping some bytes
                        continue;
                }
            
                _head+=out; // consumed bytes
                *nbOut+=pout;
                outptr+=pout;

        }
        return 1;
}
///************************************************
  uint8_t ADM_AudiocodecAMR::beginDecompress( void ) 
   {
            _tail=_head=0;
            return 1;
   };
   uint8_t ADM_AudiocodecAMR::endDecompress( void ) 
   {
            _tail=_head=0;
            return 1;
   };
   
 ADM_AudiocodecAMR::ADM_AudiocodecAMR(uint32_t fourcc,WAVHeader *info)
       :  ADM_Audiocodec(fourcc)
 {
        _tail=_head=0;
        ADM_assert(fourcc==WAV_AMRNB);	
        _contextVoid=(void *)avcodec_alloc_context();
        ADM_assert(_contextVoid);
        // Fills in some values...	
        info->channels=_context->channels 		= 1;
        info->frequency=_context->sample_rate = 8000;
        _context->bit_rate = 12000; // byte -> bits
        _context->block_align = 32;       // ...
        _context->codec_id = CODEC_ID_AMR_NB;
        _context->extradata=NULL;
        _context->extradata_size=0;	
        printf(" Opening AMR codec\n");
        if (avcodec_open(_context, &amr_nb_decoder) < 0) 
        {
            printf("\n AMR decoder init failed !\n");
            ADM_assert(0);
        }
        printf("FFamr init successful \n");
}
 ADM_AudiocodecAMR::~ADM_AudiocodecAMR()
 {
        avcodec_close(_context);
        ADM_dealloc(_context);
        _contextVoid=NULL;
}    
/*-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------*/
#define AMR_PACKET 32
uint8_t ADM_AudiocodecAMR::run( uint8_t * ptr, uint32_t nbIn, uint8_t * outptr,   uint32_t * nbOut)
{
int out;
int max=0,pout=0,toread;
	
	*nbOut=0;
	// Shrink
        if(_head && (_tail+nbIn)*3>ADM_AMR_BUFFER*2)
        {
            memmove(_buffer,_buffer+_head,_tail-_head);
            _tail-=_head;
            _head=0;
        }
        //
        ADM_assert(nbIn+_tail<ADM_AMR_BUFFER);
        memcpy(_buffer+_tail,ptr,nbIn);
        _tail+=nbIn;
        while(_tail-_head>AMR_PACKET)
        {
                out=avcodec_decode_audio(_context,(int16_t *)outptr,&pout,_buffer+_head,_tail-_head);
                
                if(out<0)
                {
                        printf( " *** WMA decoding error ***\n");
                        _head+=1; // Try skipping some bytes
                        continue;
                }
            
                _head+=out; // consumed bytes
                *nbOut+=pout;
                outptr+=pout;

        }
        return 1;
}

//---
