Files
2026-08-24 10:03:24 +08:00

622 lines
22 KiB
C

/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2005 M. Bakker, Nero 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.
**
** The "appropriate copyright message" mentioned in section 2c of the GPLv2
** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com"
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Nero AG through [email protected].
**
** $Id: main.c,v 1.85 2008/09/22 17:55:09 menno Exp $
**/
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define off_t __int64
#else
#include <time.h>
#endif
#include "libaacdec.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/time.h>
#include <stdbool.h>
#ifndef WIN32
#include <android/log.h>
#endif
//#define min(a,b) ( (a) < (b) ? (a) : (b) )
#ifndef __unused
#define __unused __attribute__((unused))
#endif
/* MicroSoft channel definitions */
#define SPEAKER_FRONT_LEFT 0x1
#define SPEAKER_FRONT_RIGHT 0x2
#define SPEAKER_FRONT_CENTER 0x4
#define SPEAKER_LOW_FREQUENCY 0x8
#define SPEAKER_BACK_LEFT 0x10
#define SPEAKER_BACK_RIGHT 0x20
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
#define SPEAKER_BACK_CENTER 0x100
#define SPEAKER_SIDE_LEFT 0x200
#define SPEAKER_SIDE_RIGHT 0x400
#define SPEAKER_TOP_CENTER 0x800
#define SPEAKER_TOP_FRONT_LEFT 0x1000
#define SPEAKER_TOP_FRONT_CENTER 0x2000
#define SPEAKER_TOP_FRONT_RIGHT 0x4000
#define SPEAKER_TOP_BACK_LEFT 0x8000
#define SPEAKER_TOP_BACK_CENTER 0x10000
#define SPEAKER_TOP_BACK_RIGHT 0x20000
#define SPEAKER_RESERVED 0x80000000
#define DefaultReadSize 1024*10 //read count from kernel audio buf one time
#define DefaultOutBufSize 1024*1024
//#define MAX_CHANNELS 6 /* make this higher to support files with more channels */
//audio decoder buffer 6144 bytes
#define AAC_INPUTBUF_SIZE 768 /* pick something big enough to hold a bunch of frames */
#define ERROR_RESET_COUNT 40
#define RSYNC_SKIP_BYTES 1
#define FRAME_RECORD_NUM 40
#define FRAME_SIZE_MARGIN 300
#define PROPERTY_FILTER_HEAAC "vendor.media.filter.heaac"
#define PROPERTY_FAAD_DETECT_FORMAT_DISABLE "vendor.media.faad.detect.format.disable"
enum {
AAC_ERROR_NO_ENOUGH_DATA = -1,
AAC_ERROR_NEED_RESET_DECODER = -2,
};
typedef struct FaadContext {
NeAACDecHandle hDecoder;
int init_flag;
int header_type;
int gSampleRate;
int gChannels;
int decoded_nb_frames;
int bit_rate;
unsigned int error_count;
unsigned int error_num; //add for get error num
int frame_length_his[FRAME_RECORD_NUM];
unsigned int muted_samples;
unsigned int muted_count;
unsigned init_cost; // summary init funciton cost bytes
unsigned init_start_flag; //start flag to summary data cost
int64_t starttime;
int64_t endtime;
bool filter_heaac;
bool isDetectFormatDisable;//Fixme: default value as false
int success_count;
} FaadContext;
//typedef int (*findsyncfunc)(unsigned char *buf, int nBytes);
static const int adts_sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, 0, 0, 0};
static int64_t gettime(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
}
#if 0
static long aacChannelConfig2wavexChannelMask(NeAACDecFrameInfo *hInfo)
{
if (hInfo->channels == 6 && hInfo->num_lfe_channels) {
return SPEAKER_FRONT_LEFT + SPEAKER_FRONT_RIGHT +
SPEAKER_FRONT_CENTER + SPEAKER_LOW_FREQUENCY +
SPEAKER_BACK_LEFT + SPEAKER_BACK_RIGHT;
} else {
return 0;
}
}
static char *position2string(int position)
{
switch (position) {
case FRONT_CHANNEL_CENTER:
return "Center front";
case FRONT_CHANNEL_LEFT:
return "Left front";
case FRONT_CHANNEL_RIGHT:
return "Right front";
case SIDE_CHANNEL_LEFT:
return "Left side";
case SIDE_CHANNEL_RIGHT:
return "Right side";
case BACK_CHANNEL_LEFT:
return "Left back";
case BACK_CHANNEL_RIGHT:
return "Right back";
case BACK_CHANNEL_CENTER:
return "Center back";
case LFE_CHANNEL:
return "LFE";
case UNKNOWN_CHANNEL:
return "Unknown";
default:
return "";
}
return "";
}
#endif
#if 0
static int FindAdtsSRIndex(int sr)
{
int i;
for (i = 0; i < 16; i++) {
if (sr == adts_sample_rates[i]) {
return i;
}
}
return 16 - 1;
}
static unsigned char *MakeAdtsHeader(int *dataSize, NeAACDecFrameInfo *hInfo, int old_format)
{
unsigned char *data;
int profile = (hInfo->object_type - 1) & 0x3;
int sr_index = ((hInfo->sbr == SBR_UPSAMPLED) || (hInfo->sbr == NO_SBR_UPSAMPLED)) ?
FindAdtsSRIndex(hInfo->samplerate / 2) : FindAdtsSRIndex(hInfo->samplerate);
int skip = (old_format) ? 8 : 7;
int framesize = skip + hInfo->bytesconsumed;
if (hInfo->header_type == ADTS) {
framesize -= skip;
}
*dataSize = 7;
data = malloc(*dataSize * sizeof(unsigned char));
memset(data, 0, *dataSize * sizeof(unsigned char));
data[0] += 0xFF; /* 8b: syncword */
data[1] += 0xF0; /* 4b: syncword */
/* 1b: mpeg id = 0 */
/* 2b: layer = 0 */
data[1] += 1; /* 1b: protection absent */
data[2] += ((profile << 6) & 0xC0); /* 2b: profile */
data[2] += ((sr_index << 2) & 0x3C); /* 4b: sampling_frequency_index */
/* 1b: private = 0 */
data[2] += ((hInfo->channels >> 2) & 0x1); /* 1b: channel_configuration */
data[3] += ((hInfo->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 data;
}
#endif
static unsigned get_frame_size(FaadContext *gFaadCxt)
{
int i;
unsigned sum = 0;
unsigned valid_his_num = 0;
for (i = 0; i < FRAME_RECORD_NUM; i++) {
if (gFaadCxt->frame_length_his[i] > 0) {
valid_his_num ++;
sum += gFaadCxt->frame_length_his[i];
}
}
if (valid_his_num == 0) {
return 2048;
}
return sum / valid_his_num;
}
static void store_frame_size(FaadContext *gFaadCxt, int lastFrameLen)
{
/* record the frame length into the history buffer */
int i = 0;
for (i = 0; i < FRAME_RECORD_NUM - 1; i++) {
gFaadCxt->frame_length_his[i] = gFaadCxt->frame_length_his[i + 1];
}
gFaadCxt->frame_length_his[FRAME_RECORD_NUM - 1] = lastFrameLen;
}
static int AACFindADTSSyncWord(unsigned char *buf, int nBytes)
{
int i;
for (i = 0; i < nBytes - 1; i++) {
if (((buf[i + 0] & 0xff) == 0xff) && ((buf[i + 1] & 0xf6) == 0xf0)) {
break;
}
}
return i;
}
//check two latm frames sync header
static int AACFindLATMSyncWord(unsigned char *buffer, int nBytes)
{
int i;
int i_frame_size = 0;
for (i = 0; i < nBytes - 2; i++) {
if (buffer[i] == 0x56 && (buffer[i + 1] & 0xe0) == 0xe0) {
i_frame_size = ((buffer[i + 1] & 0x1f) << 8) + buffer[i + 2];
if (i_frame_size > 4608) {
audio_codec_print("i_frame_size exceed 4608 ,%d \n", i_frame_size);
}
if (i_frame_size > 0 && i_frame_size < 4608) {
break;
}
}
}
return i;
}
int audio_dec_init(
#ifndef WIN32
audio_decoder_operations_t *adec_ops
#endif
)
{
//audio_codec_print("[%s]BuildDate--%s BuildTime--%s", __FUNCTION__, __DATE__, __TIME__);
FaadContext *gFaadCxt = NULL;
adec_ops->pdecoder = calloc(1, sizeof(FaadContext));
if (!adec_ops->pdecoder) {
audio_codec_print("malloc for decoder instance failed\n");
return -1;
}
gFaadCxt = (FaadContext*)adec_ops->pdecoder;
memset(gFaadCxt, 0, sizeof(FaadContext));
adec_ops->nInBufSize = AAC_INPUTBUF_SIZE; //4608 bytes input buffer size
adec_ops->nOutBufSize = 64 * 1024; //3 * adec_ops->channels * adec_ops->samplerate * 16/8; // 3s
gFaadCxt->gChannels = adec_ops->channels;
gFaadCxt->gSampleRate = adec_ops->samplerate;
gFaadCxt->init_flag = 0;
gFaadCxt->header_type = 1; //default adts
gFaadCxt->filter_heaac = false;
gFaadCxt->isDetectFormatDisable = false;
gFaadCxt->success_count = 0;
audio_codec_print("got property %s %s\n", PROPERTY_FAAD_DETECT_FORMAT_DISABLE, gFaadCxt->isDetectFormatDisable ? "true": "false");
return 0;
}
static int audio_decoder_init(
#ifndef WIN32
audio_decoder_operations_t *adec_ops,
#endif
char *outbuf, int *outlen __unused, char *inbuf, int inlen, long *inbuf_consumed)
{
unsigned long samplerate;
unsigned char channels;
int ret;
NeAACDecConfigurationPtr config = NULL;
char *in_buf;
int inbuf_size;
in_buf = inbuf;
inbuf_size = inlen;
int nReadLen = 0;
FaadContext *gFaadCxt = (FaadContext*)adec_ops->pdecoder;
int islatm = 0;
if (!in_buf || !inbuf_size || !outbuf) {
audio_codec_print(" input/output buffer null or input len is 0 \n");
return -1;
}
{
int latmheader_detected = 0,adtsheader_detected = 0;
int nSeekNum = AACFindLATMSyncWord((unsigned char *)in_buf, inbuf_size);
if (nSeekNum == (inbuf_size - 1)) {
audio_codec_print("%d bytes data not found latm sync header \n", nSeekNum);
} else {
latmheader_detected = 1;
audio_codec_print(" latm header detected nSeekNum %d \n", nSeekNum);
}
nSeekNum = AACFindADTSSyncWord((unsigned char *)in_buf, inbuf_size);
if (nSeekNum == (inbuf_size - 1)) {
audio_codec_print("%d bytes data not found adts sync header \n", nSeekNum);
} else {
adtsheader_detected = 1;
audio_codec_print(" adts head detected nSeekNum %d", nSeekNum);
}
if (adec_ops->nAudioDecoderType == ACODEC_FMT_AAC_LATM) {
if (latmheader_detected && !adtsheader_detected) {
gFaadCxt->isDetectFormatDisable = true;
} else {
gFaadCxt->isDetectFormatDisable = false;
}
}
if (adec_ops->nAudioDecoderType == ACODEC_FMT_AAC) {
if (latmheader_detected && !adtsheader_detected) {
gFaadCxt->isDetectFormatDisable = true;
adec_ops->nAudioDecoderType = ACODEC_FMT_AAC_LATM;
}
}
}
retry:
if (gFaadCxt->isDetectFormatDisable == true) {
/*
*fixed to LATM aac frame header sync to speed up seek speed
*set property PROPERTY_FAAD_NOT_DETECT_FORMAT as true
*/
if (adec_ops->nAudioDecoderType == ACODEC_FMT_AAC_LATM) {
islatm = 1;
int nSeekNum = AACFindLATMSyncWord((unsigned char *)in_buf, inbuf_size);
if (nSeekNum == (inbuf_size - 2)) {
audio_codec_print("[%s %d]%d bytes data not found latm sync header \n", __FUNCTION__,__LINE__, nSeekNum);
} else {
audio_codec_print("[%s %d]latm seek sync header cost %d,total %d,left %d \n", __FUNCTION__,__LINE__, nSeekNum, inbuf_size, inbuf_size - nSeekNum);
}
inbuf_size = inbuf_size - nSeekNum;
}
}
gFaadCxt->hDecoder = NeAACDecOpen();
gFaadCxt->error_num = 0;
config = NeAACDecGetCurrentConfiguration(gFaadCxt->hDecoder);
config->defObjectType = LC;
config->outputFormat = FAAD_FMT_16BIT;
config->downMatrix = 0x01;
config->useOldADTSFormat = 0;
//config->dontUpSampleImplicitSBR = 1;
NeAACDecSetConfiguration(gFaadCxt->hDecoder, config);
int skipbytes=RSYNC_SKIP_BYTES;
if ((ret = NeAACDecInit(gFaadCxt->hDecoder, (unsigned char *)in_buf, inbuf_size, &samplerate, &channels, islatm,&skipbytes)) < 0) {
in_buf += skipbytes;
inbuf_size -= skipbytes;
NeAACDecClose(gFaadCxt->hDecoder);
gFaadCxt->hDecoder = NULL;
if (inbuf_size < 0) {
inbuf_size = 0;
}
audio_codec_print("init fail,inbuf_size %d \n", inbuf_size);
//if (inbuf_size < (int)(get_frame_size(gFaadCxt) + FRAME_SIZE_MARGIN) || skipbytes == 0) {
if (skipbytes == 0) {
audio_codec_print("skipbytes/%d inbuf_size/%d get_frame_size()/%d ,need more data \n",skipbytes, inbuf_size, (get_frame_size(gFaadCxt) + FRAME_SIZE_MARGIN));
*inbuf_consumed = inlen - inbuf_size;
return AAC_ERROR_NO_ENOUGH_DATA;
}
goto retry;
}
audio_codec_print("init sucess cost %d gFaadCxt->success_count %d\n", ret, gFaadCxt->success_count);
NeAACDecStruct* hDecoder = (NeAACDecStruct*)(gFaadCxt->hDecoder);
if (hDecoder->adts_header_present &&
adec_ops->nAudioDecoderType == ACODEC_FMT_AAC_LATM) {
gFaadCxt->success_count++;
in_buf += skipbytes;
inbuf_size -= skipbytes;
if (gFaadCxt->success_count < 2)
goto retry;
}
in_buf += ret;
inbuf_size -= ret;
*inbuf_consumed = inlen - inbuf_size;
gFaadCxt->init_flag = 1;
gFaadCxt->gChannels = channels;
gFaadCxt->gSampleRate = samplerate;
audio_codec_print("[%s] Init OK adif_present :%d adts_present:%d latm_present:%d,sr %lu,ch %d\n", __FUNCTION__, hDecoder->adif_header_present, hDecoder->adts_header_present, hDecoder->latm_header_present, samplerate, channels);
return 0;
}
int audio_dec_decode(
#ifndef WIN32
audio_decoder_operations_t *adec_ops,
#endif
char *outbuf, int *outlen, char *inbuf, int inlen)
{
unsigned long samplerate;
unsigned char channels;
void *sample_buffer;
NeAACDecFrameInfo frameInfo = {0};
int outmaxlen = 0;
char *dec_buf;
int dec_bufsize;
int inbuf_consumed = 0;
int ret = 0;
FaadContext *gFaadCxt = (FaadContext*)adec_ops->pdecoder;
NeAACDecStruct* hDecoder = NULL;
dec_bufsize = inlen;
dec_buf = inbuf;
outmaxlen = *outlen ;
*outlen = 0;
if (!outbuf || !inbuf || !inlen) {
audio_codec_print("decoder parameter error,check \n");
goto exit;
}
if (gFaadCxt->init_start_flag == 0) {
audio_codec_print("MyFaadDecoder init first in \n");
gFaadCxt->starttime = gettime();
gFaadCxt->init_start_flag = 1;
}
if (!gFaadCxt->init_flag) {
gFaadCxt->error_count = 0;
gFaadCxt->decoded_nb_frames = 0;
audio_codec_print("begin audio_decoder_init,buf size %d \n", dec_bufsize);
ret = audio_decoder_init(adec_ops, outbuf, outlen, dec_buf, dec_bufsize, (long *)&inbuf_consumed);
if (ret == AAC_ERROR_NO_ENOUGH_DATA) {
audio_codec_print("decoder buf size %d,cost %d byte input data ,but initiation failed.^_^ \n", inlen, inbuf_consumed);
dec_bufsize -= inbuf_consumed;
goto exit;
}
gFaadCxt->init_flag = 1;
dec_buf += inbuf_consumed;
dec_bufsize -= inbuf_consumed;
gFaadCxt->init_cost += inbuf_consumed;
gFaadCxt->endtime = gettime();
//audio_codec_print(" MyFaadDecoder decoder init finished total cost %d bytes,consumed time %ld ms \n", gFaadCxt->init_cost, (gFaadCxt->endtime - gFaadCxt->starttime) / 1000);
gFaadCxt->init_cost = 0;
if (dec_bufsize < 0) {
dec_bufsize = 0;
}
}
hDecoder = (NeAACDecStruct*)(gFaadCxt->hDecoder);
if (!hDecoder) {
goto exit;
}
//TODO .fix to LATM aac decoder when ffmpeg parser return LATM aac type
#if 0
if (adec_ops->nAudioDecoderType == ACODEC_FMT_AAC_LATM) {
hDecoder->latm_header_present = 1;
}
#endif
if (hDecoder->adts_header_present) {
int nSeekNum = AACFindADTSSyncWord((unsigned char *)dec_buf, dec_bufsize);
if (nSeekNum == (dec_bufsize - 1)) {
audio_codec_print("%d bytes data not found adts sync header \n", nSeekNum);
}
dec_bufsize = dec_bufsize - nSeekNum;
}
if (hDecoder->latm_header_present) {
int nSeekNum = AACFindLATMSyncWord((unsigned char *)dec_buf, dec_bufsize);
if (nSeekNum == (dec_bufsize - 2)) {
audio_codec_print("%d bytes data not found latm sync header \n", nSeekNum);
}
dec_bufsize = dec_bufsize - nSeekNum;
}
sample_buffer = NeAACDecDecode(gFaadCxt->hDecoder, &frameInfo, (unsigned char *)dec_buf, dec_bufsize);
//audio_codec_print("dec_bufsize:%d, frameInfo.bytesconsumed:%lu, frameInfo.samples:%lu, frameInfo.error:%u", dec_bufsize, frameInfo.bytesconsumed, frameInfo.samples, frameInfo.error);
dec_bufsize -= frameInfo.bytesconsumed;
if (frameInfo.channels > 8) {
audio_codec_print("[%s %d]ERR__Unvalid Nch/%d bytesconsumed/%d error/%d\n",
__FUNCTION__,__LINE__,frameInfo.channels,(int)frameInfo.bytesconsumed,frameInfo.error);
sample_buffer=NULL;
}
if (frameInfo.error == 0 && sample_buffer == NULL && hDecoder->latm_header_present) {
dec_bufsize -= 3;
goto exit;
}
if ((frameInfo.error == 0) && (frameInfo.samples > 0) && sample_buffer != NULL) {
gFaadCxt->decoded_nb_frames++;
store_frame_size(gFaadCxt, frameInfo.bytesconsumed);
gFaadCxt->gSampleRate = frameInfo.samplerate;
gFaadCxt->gChannels = frameInfo.channels;
//code to mute first 1 s ???
#define MUTE_S 0.2
if (gFaadCxt->muted_samples == 0) {
gFaadCxt->muted_samples = gFaadCxt->gSampleRate * gFaadCxt->gChannels * MUTE_S;
}
if (gFaadCxt->muted_count < gFaadCxt->muted_samples) {
memset(sample_buffer, 0, 2 * frameInfo.samples);
gFaadCxt->muted_count += frameInfo.samples;
}
if ((outmaxlen - (*outlen)) >= (int)(2 * frameInfo.samples)) {
memcpy(outbuf + (*outlen), sample_buffer, 2 * frameInfo.samples);
*outlen += 2 * frameInfo.samples;
gFaadCxt->error_count = 0;
} else {
audio_codec_print("[%s %d]WARNING: no enough space used for pcm!\n", __FUNCTION__, __LINE__);
}
}
if (frameInfo.error > 0) { //failed seek to the head
if (frameInfo.error != 34 && frameInfo.error != 35) {
//dec_bufsize -= RSYNC_SKIP_BYTES; do not need rsync skip for data had been parsed already
//audio_codec_print("Error: %s,lslsinlen %d\n", NeAACDecGetErrorMessage(frameInfo.error), inlen);
}
// sr/ch changed info happened 5 times always,some times error maybe,skip bytes
else if (frameInfo.error == 34 && gFaadCxt->error_count > 5) {
dec_bufsize -= RSYNC_SKIP_BYTES;
audio_codec_print("%s,,inlen %d\n", NeAACDecGetErrorMessage(frameInfo.error), inlen);
}
gFaadCxt->error_count++;
gFaadCxt->error_num++;
//err 34,means aac profile changed , PS.SBR,LC ....,normally happens when switch audio source
if (gFaadCxt->error_count >= ERROR_RESET_COUNT || frameInfo.error == 34) {
if (gFaadCxt->hDecoder) {
NeAACDecClose(gFaadCxt->hDecoder);
gFaadCxt->hDecoder = NULL;
}
gFaadCxt->init_flag = 0;
gFaadCxt->init_start_flag = 0;
}
}
exit:
if (dec_bufsize < 0) {
dec_bufsize = 0;
}
if (gFaadCxt->init_flag == 0) {
gFaadCxt->init_cost += (inlen - dec_bufsize);
}
//disable HE-AAC decoder
hDecoder = (NeAACDecStruct*)(gFaadCxt->hDecoder);
if (hDecoder && hDecoder->sbr_present_flag == 1 && *outlen > 0 && gFaadCxt->filter_heaac) {
memset(outbuf,0,*outlen);
}
return inlen - dec_bufsize;
}
int audio_dec_release(
#ifndef WIN32
audio_decoder_operations_t *adec_ops
#endif
)
{
if (adec_ops->pdecoder) {
FaadContext *gFaadCxt = (FaadContext*)adec_ops->pdecoder;
if (gFaadCxt->hDecoder) {
NeAACDecClose(gFaadCxt->hDecoder);
}
free(adec_ops->pdecoder);
adec_ops->pdecoder = NULL;
}
return 0;
}
#ifndef WIN32
int audio_dec_getinfo(audio_decoder_operations_t *adec_ops, void *pAudioInfo)
{
FaadContext *gFaadCxt = (FaadContext*)adec_ops->pdecoder;
if (gFaadCxt) {
NeAACDecStruct* hDecoder = (NeAACDecStruct*)gFaadCxt->hDecoder;
if (hDecoder)
adec_ops->NchOriginal = hDecoder->fr_channels;
((AudioInfo *)pAudioInfo)->channels = gFaadCxt->gChannels;
((AudioInfo *)pAudioInfo)->samplerate = gFaadCxt->gSampleRate;
((AudioInfo *)pAudioInfo)->error_num = gFaadCxt->error_num;
((AudioInfo *)pAudioInfo)->drop_num = gFaadCxt->error_num;
((AudioInfo *)pAudioInfo)->decode_num = gFaadCxt->decoded_nb_frames;
//audio_codec_print("--%s,gFaadCxt->error_num=%d,gFaadCxt->gSampleRate=%d--\n",__func__,gFaadCxt->error_num,gFaadCxt->gSampleRate);
}
return 0;
}
#endif