扫盲
AAC实际上是高级音频编码的缩写,它是MPEG-2规范的一部分。但2000年,MPEG-4标准出台,AAC从新整合了其特性,故现又称 MPEG-4 AAC,即m4a。以上也就是说以.aac和.m4a结尾的都可以称为aac。
目前成熟的解码器
- opencore的opencore-aacdec
- ffmpeg 的aac解码器,当然还包括很多其他格式的音频视频解码器。
- faad 解码器
目的:把faad的aac解码器移植到android平台上来。
方法:参考demo移植解码器。
实现方式:
附上部分代码
首先定义结构体:
#define MAX_BUFFER 20480 //20K
#define MIN_BUFFER 2048
/* FAAD file buffering routines */
typedef struct {
long bytes_into_buffer;
long bytes_consumed;
long file_offset;
long size;
unsigned char *buffer;
int at_eof;
FILE *infile;
} aac_buffer;
struct AACFileHandle
{
FILE* file;//文件
int size;//文件长度
int bitrate;//比特率
int samplerate;//抽样率
float duration;//播放时长
int channelNum;//声道数
int fileType;//文件类型(1:ADTS,2: ADIF)
int mp4file;
int track;
long sampleId;
mp4ff_t *infile;
mp4AudioSpecificConfig *mp4ASC;
mp4ff_callback_t *mp4cb;
aac_buffer buffer;//aac缓存信息
NeAACDecHandle hDecoder;
};
打开文件操作:
int mp4file = 0;
int index = findFreeHandle( );
if( index == -1 )
return -1;
//取得文件全路径
const char* fileString = env->GetStringUTFChars(file, NULL);
FILE* fileHandle = fopen( fileString, "rb" );//以只读的方式打开文件
env->ReleaseStringUTFChars(file, fileString);//释放文件路径
if( fileHandle == 0 )//如果打开文件失败返回-1
return -1;
//*********************以上打开文件完毕********************************
AACFileHandle* aacHandle = new AACFileHandle();
if(aacHandle == NULL){
return -1;
}
memset(aacHandle, 0, sizeof(AACFileHandle));
//读取文件头,判断是否是MP4
unsigned char header[8];
fread(header, 1, 8, fileHandle);
rewind(fileHandle);
if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p')
mp4file = 1;
aacHandle->mp4file = mp4file;
if (!mp4file){
if(open_aac_file(fileHandle, aacHandle) < 0)
{
fclose(fileHandle);
delete aacHandle;
return -1;
}
}else{//mp4 aac
if(open_mp4_file(fileHandle, aacHandle) < 0)
{
fclose(fileHandle);
delete aacHandle;
return -1;
}
}
handles[index] = aacHandle;
// AACD_TRACE("index :" + index);
return index;
解码操作:
AACD_TRACE("start");
//加传入参数的判断
if(aacHandle == NULL || size <=0){
//这部分返回0是因为外部判断的是0
return 0;
}
// size = size >>1;
// if(fp == NULL)
// {
// fp = fopen("sdcard/temp222.wav", "a+b");
// }
int pos =0;
AACD_TRACE("read_aac_samples, isSeeking %d",isSeeking);
jshort * target = env->GetShortArrayElements(buffer, NULL);
if(aacHandle->buffer.bytes_into_buffer == 0)
{
fill_buffer(&aacHandle->buffer, 1);
}
int times = 0;
void *sample_buffer = NULL;
while(pos < size && aacHandle->buffer.bytes_into_buffer != 0){
if(isSeeking)return -1;
NeAACDecFrameInfo frameInfo;
sample_buffer = NeAACDecDecode(aacHandle->hDecoder, &frameInfo, aacHandle->buffer.buffer, aacHandle->buffer.bytes_into_buffer);
if((frameInfo.error == 0) && (frameInfo.samples >= 0) && sample_buffer != NULL)
{
times++;
if((pos + frameInfo.samples) > size){
AACD_TRACE("samples: %d, pos: %d, size %d", frameInfo.samples, pos, size);
break;
}
aacHandle->sampleId += 1;
// if(pos + frameInfo.samples < size){
// AACD_TRACE("samples %d", frameInfo.samples);
// aacHandle->buffer.bytes_consumed = 0;
memmove((void *)(target + pos), (void *)sample_buffer, sizeof(short) * frameInfo.samples);
// memset(sample_buffer, 0, sizeof(short) * frameInfo.samples);
pos += frameInfo.samples;
advance_buffer(&aacHandle->buffer, frameInfo.bytesconsumed);
fill_buffer(&aacHandle->buffer, 1);
// }else{
// int othersize = 0;
// unsigned long bytesconsumed = 0;
// if(frameInfo.samples < (size -pos)){
// othersize = frameInfo.samples;
// }else{
// othersize = (size -pos);
// }
// AACD_TRACE( "othersize %d", othersize);
// memcpy((void *)(target + pos), (void *)sample_buffer, sizeof(short) * othersize);
// advance_buffer(&aacHandle->buffer, frameInfo.bytesconsumed*othersize/size);
// pos += othersize;
// fill_buffer(&aacHandle->buffer);
// AACD_TRACE( "decodingothers %d", frameInfo.samples);
// break;
// }
}
else if(frameInfo.error != 0){
AACD_TRACE("read error %d, consumed bytes: %d", frameInfo.error, frameInfo.bytesconsumed);
advance_buffer(&aacHandle->buffer, frameInfo.bytesconsumed);
if (frameInfo.bytesconsumed == 0) {
fseek(aacHandle->buffer.infile,aacHandle->buffer.file_offset,SEEK_SET);
aacHandle->buffer.bytes_into_buffer = 0;
break;
}
// if(aacHandle->mp4file){
// mp4ff_set_sample_position(aacHandle->infile, aacHandle->track, aacHandle->sampleId);
// }
}
}
AACD_TRACE("times : %d, pos %d, size %d", times, pos, size);
env->ReleaseShortArrayElements(buffer, target, 0);
return times > 0 ? pos: -1;