622 lines
22 KiB
C
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
|
|
|
|
|
|
|
|
|