aac帧分为adts头和aac编码数据
一 adts头结构
adts头主要包含profile类型,采样率,声道数,帧长度,是可变码率还是固定码率等信息。
adts_fixed_header(){
syncword; 12 0xfff
ID; 1
layer;2 (always 00)
protection_absent;1
profile;2 LC RC
sampling_frequency_index;4 uimsbf
private_bit;1 bslbf
channel_configuration;3 uimsbf
original_copy;1 bslbf
home;1 bslbf
}
syncword:always 0xfff
ID:MPEG Version: 0 for MPEG-4, 1 for MPEG-2
Layer:always: '00'
profile:AAC编码级别
0:Main profile
1:Low Complexity profile(LC)
2:Scalable sampling Rate Profile(SSR)
3:Reserved
sampling_frequency_index:采样率,对应关系如下
0: 96000 Hz
1: 88200 Hz
2: 64000 Hz
3: 48000 Hz
4: 44100 Hz
5: 32000 Hz
6: 24000 Hz
7: 22050 Hz
8: 16000 Hz
9: 12000 Hz
10: 11025 Hz
11: 8000 Hz
12: 7350 Hz
13: Reserved
14: Reserved
15: frequency is written explictly
channel_configuration:声道
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved转
frame_length:包括adts长度和aac原始数据流长度
adts_buffer_fullness:0x7FF 说明是码率可变的码流
二 aac数据体
aac数据体就是将pcm数据经过aac压缩后的数据。
AAC,全称Advanced Audio Coding,是一种专为声音数据设计的文件压缩格式。与MP3不同,它采用了全新的算法进行编码,更加高效,具有更高的“性价比”。利用AAC格式,可使人感觉声音质量没有明显降低的前提下,更加小巧。苹果ipod、诺基亚手机支持AAC格式的音频文件。
优点:相对于mp3,AAC格式的音质更佳,文件更小。
不足:AAC属于有损压缩的格式,与时下流行的APE、FLAC等无损格式相比音质存在“本质上”的差距。加之,传输速度更快的USB3.0和16G以上大容量MP3正在加速普及,也使得AAC头上“小巧”的光环不复存在。
以上这些都能从百度百科搜索到,就不赘述。
三 aac文件解析
下面贴一下我实现的aac文件解析代码。(从aac文件中提取一帧一帧的aac语音数据)
#ifndef _AAC_JITTER_H__
#define _AAC_JITTER_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma pack(1)
struct ADTS_Head
{
unsigned char syncword1;
unsigned char protection_absent:1;
unsigned char layer:2;
unsigned char ID:1;
unsigned char syncword2:4;
unsigned char channel_conf1:1;
unsigned char private_bit:1;
unsigned char sample_freq_index:4;
unsigned char profile:2;
unsigned char aac_frame_lenght1:2;
unsigned char copyright_identify_start:1;
unsigned char copyright_identif_bit:1;
unsigned char home:1;
unsigned char origin_copy:1;
unsigned char channel_conf2:2;
unsigned char aac_frame_lenght2;
unsigned char adts_buffer_fullness1:5;
unsigned char aac_frame_lenght3:3;
unsigned char number_of_raw_data:2;
unsigned char adts_buffer_fullness2:6;
void DUMP()
{
printf("synword#### %d %d\n",syncword1,syncword2);
printf("id#### %d\n",ID);
printf("layer#### %d\n",layer);
printf("protection_absent#### %d\n",protection_absent);
printf("profile#### %d\n",profile);
printf("sampleing_freq_index#### %d\n",sample_freq_index);
printf("private_bit#### %d\n",private_bit);
printf("channel_configure#### %d %d\n",channel_conf1,channel_conf2);
printf("origin_copy#### %d\n",origin_copy);
printf("home#### %d\n",home);
printf("identify_bit#### %d\n",copyright_identify_start);
printf("identify_start#### %d\n",copyright_identif_bit);
printf("frame_len#### %d %d %d\n",aac_frame_lenght1,aac_frame_lenght2,aac_frame_lenght3);
printf("buffer_fullness#### %d %d\n",adts_buffer_fullness1,adts_buffer_fullness2);
printf("raw_data_block#### %d\n",number_of_raw_data);
}
};
#define MAX_AAC_JITTER_SIZE (10240)
#define AAC_JITTER_NOT_FULL (0)
#define MAX_FRAME_COUNT (10000)
struct FrameInfo
{
char *offset;
int len;
};
class AACJitter
{
public:
AACJitter();
~AACJitter();
bool Init();
int AddAACDataToJitter(char *buf,int len);
char *GotOneFrame(int &len);
bool GetFrameHead(char *buf,int inlen,int &offset_len);
private:
char *jitter_mem_;
int data_len_;
FrameInfo frame_info_[MAX_FRAME_COUNT];
int frame_count_;
int frame_get_index_;
};
#endif
#include "aac_jitter.h"
AACJitter::AACJitter()
{
jitter_mem_ = NULL;
data_len_ = 0;
memset(frame_info_,0x0,sizeof(FrameInfo)*MAX_FRAME_COUNT);
Init();
}
AACJitter::~AACJitter()
{
if(jitter_mem_)
{
free(jitter_mem_);
jitter_mem_ = NULL;
}
}
bool AACJitter::Init()
{
if(jitter_mem_ != NULL)
{
return false;
}
jitter_mem_ = (char*)malloc(MAX_AAC_JITTER_SIZE*MAX_FRAME_COUNT);
if(jitter_mem_ == NULL)
{
return false;
}
return true;
}
int AACJitter::AddAACDataToJitter(char *buf,int len)
{
if(data_len_ + len > MAX_AAC_JITTER_SIZE*MAX_FRAME_COUNT)
{
return -1;
}
memcpy(jitter_mem_ + data_len_,buf,len);
data_len_ += len;
int parse_offset = 0;
char *parse_buffer = NULL;
int frame_len = 0;
int parse_index = 0;
int offset_len = 0;
while(GetFrameHead(jitter_mem_ + parse_offset,data_len_ - parse_offset,offset_len))
{
parse_offset += offset_len;
parse_buffer = jitter_mem_ + parse_offset;
ADTS_Head *head = (ADTS_Head*)parse_buffer;
frame_len = head->aac_frame_lenght2 * 8 + head->aac_frame_lenght3;
if(frame_len > 1024)
{
parse_offset += 2;
}
frame_info_[parse_index].offset = parse_buffer;
frame_info_[parse_index ++].len = frame_len;
parse_offset += frame_len;
if(parse_index >= MAX_FRAME_COUNT - 1)
{
break;
}
}
frame_get_index_ = 0;
frame_count_ = parse_index;
return parse_index;
}
char *AACJitter::GotOneFrame(int &len)
{
if(frame_get_index_ >= frame_count_)
{
frame_get_index_ = 0;
//return NULL;
}
len = frame_info_[frame_get_index_].len;
return frame_info_[frame_get_index_ ++].offset;
}
bool AACJitter::GetFrameHead(char *buf,int inlen,int &offset_len)
{
for(int i = 0;i<inlen;i++)
{
if(buf[i]&0xff == 0xff)
{
if(buf[i + 1]&0xf0 == 0xf0)
{
offset_len = i;
return true;
}
}
}
return false;
}
一 adts头结构
adts头主要包含profile类型,采样率,声道数,帧长度,是可变码率还是固定码率等信息。
adts_fixed_header(){
syncword; 12 0xfff
ID; 1
layer;2 (always 00)
protection_absent;1
profile;2 LC RC
sampling_frequency_index;4 uimsbf
private_bit;1 bslbf
channel_configuration;3 uimsbf
original_copy;1 bslbf
home;1 bslbf
}
syncword:always 0xfff
ID:MPEG Version: 0 for MPEG-4, 1 for MPEG-2
Layer:always: '00'
profile:AAC编码级别
0:Main profile
1:Low Complexity profile(LC)
2:Scalable sampling Rate Profile(SSR)
3:Reserved
sampling_frequency_index:采样率,对应关系如下
0: 96000 Hz
1: 88200 Hz
2: 64000 Hz
3: 48000 Hz
4: 44100 Hz
5: 32000 Hz
6: 24000 Hz
7: 22050 Hz
8: 16000 Hz
9: 12000 Hz
10: 11025 Hz
11: 8000 Hz
12: 7350 Hz
13: Reserved
14: Reserved
15: frequency is written explictly
channel_configuration:声道
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved转
frame_length:包括adts长度和aac原始数据流长度
adts_buffer_fullness:0x7FF 说明是码率可变的码流
二 aac数据体
aac数据体就是将pcm数据经过aac压缩后的数据。
AAC,全称Advanced Audio Coding,是一种专为声音数据设计的文件压缩格式。与MP3不同,它采用了全新的算法进行编码,更加高效,具有更高的“性价比”。利用AAC格式,可使人感觉声音质量没有明显降低的前提下,更加小巧。苹果ipod、诺基亚手机支持AAC格式的音频文件。
优点:相对于mp3,AAC格式的音质更佳,文件更小。
不足:AAC属于有损压缩的格式,与时下流行的APE、FLAC等无损格式相比音质存在“本质上”的差距。加之,传输速度更快的USB3.0和16G以上大容量MP3正在加速普及,也使得AAC头上“小巧”的光环不复存在。
以上这些都能从百度百科搜索到,就不赘述。
三 aac文件解析
下面贴一下我实现的aac文件解析代码。(从aac文件中提取一帧一帧的aac语音数据)
#ifndef _AAC_JITTER_H__
#define _AAC_JITTER_H__
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma pack(1)
struct ADTS_Head
{
unsigned char syncword1;
unsigned char protection_absent:1;
unsigned char layer:2;
unsigned char ID:1;
unsigned char syncword2:4;
unsigned char channel_conf1:1;
unsigned char private_bit:1;
unsigned char sample_freq_index:4;
unsigned char profile:2;
unsigned char aac_frame_lenght1:2;
unsigned char copyright_identify_start:1;
unsigned char copyright_identif_bit:1;
unsigned char home:1;
unsigned char origin_copy:1;
unsigned char channel_conf2:2;
unsigned char aac_frame_lenght2;
unsigned char adts_buffer_fullness1:5;
unsigned char aac_frame_lenght3:3;
unsigned char number_of_raw_data:2;
unsigned char adts_buffer_fullness2:6;
void DUMP()
{
printf("synword#### %d %d\n",syncword1,syncword2);
printf("id#### %d\n",ID);
printf("layer#### %d\n",layer);
printf("protection_absent#### %d\n",protection_absent);
printf("profile#### %d\n",profile);
printf("sampleing_freq_index#### %d\n",sample_freq_index);
printf("private_bit#### %d\n",private_bit);
printf("channel_configure#### %d %d\n",channel_conf1,channel_conf2);
printf("origin_copy#### %d\n",origin_copy);
printf("home#### %d\n",home);
printf("identify_bit#### %d\n",copyright_identify_start);
printf("identify_start#### %d\n",copyright_identif_bit);
printf("frame_len#### %d %d %d\n",aac_frame_lenght1,aac_frame_lenght2,aac_frame_lenght3);
printf("buffer_fullness#### %d %d\n",adts_buffer_fullness1,adts_buffer_fullness2);
printf("raw_data_block#### %d\n",number_of_raw_data);
}
};
#define MAX_AAC_JITTER_SIZE (10240)
#define AAC_JITTER_NOT_FULL (0)
#define MAX_FRAME_COUNT (10000)
struct FrameInfo
{
char *offset;
int len;
};
class AACJitter
{
public:
AACJitter();
~AACJitter();
bool Init();
int AddAACDataToJitter(char *buf,int len);
char *GotOneFrame(int &len);
bool GetFrameHead(char *buf,int inlen,int &offset_len);
private:
char *jitter_mem_;
int data_len_;
FrameInfo frame_info_[MAX_FRAME_COUNT];
int frame_count_;
int frame_get_index_;
};
#endif
#include "aac_jitter.h"
AACJitter::AACJitter()
{
jitter_mem_ = NULL;
data_len_ = 0;
memset(frame_info_,0x0,sizeof(FrameInfo)*MAX_FRAME_COUNT);
Init();
}
AACJitter::~AACJitter()
{
if(jitter_mem_)
{
free(jitter_mem_);
jitter_mem_ = NULL;
}
}
bool AACJitter::Init()
{
if(jitter_mem_ != NULL)
{
return false;
}
jitter_mem_ = (char*)malloc(MAX_AAC_JITTER_SIZE*MAX_FRAME_COUNT);
if(jitter_mem_ == NULL)
{
return false;
}
return true;
}
int AACJitter::AddAACDataToJitter(char *buf,int len)
{
if(data_len_ + len > MAX_AAC_JITTER_SIZE*MAX_FRAME_COUNT)
{
return -1;
}
memcpy(jitter_mem_ + data_len_,buf,len);
data_len_ += len;
int parse_offset = 0;
char *parse_buffer = NULL;
int frame_len = 0;
int parse_index = 0;
int offset_len = 0;
while(GetFrameHead(jitter_mem_ + parse_offset,data_len_ - parse_offset,offset_len))
{
parse_offset += offset_len;
parse_buffer = jitter_mem_ + parse_offset;
ADTS_Head *head = (ADTS_Head*)parse_buffer;
frame_len = head->aac_frame_lenght2 * 8 + head->aac_frame_lenght3;
if(frame_len > 1024)
{
parse_offset += 2;
}
frame_info_[parse_index].offset = parse_buffer;
frame_info_[parse_index ++].len = frame_len;
parse_offset += frame_len;
if(parse_index >= MAX_FRAME_COUNT - 1)
{
break;
}
}
frame_get_index_ = 0;
frame_count_ = parse_index;
return parse_index;
}
char *AACJitter::GotOneFrame(int &len)
{
if(frame_get_index_ >= frame_count_)
{
frame_get_index_ = 0;
//return NULL;
}
len = frame_info_[frame_get_index_].len;
return frame_info_[frame_get_index_ ++].offset;
}
bool AACJitter::GetFrameHead(char *buf,int inlen,int &offset_len)
{
for(int i = 0;i<inlen;i++)
{
if(buf[i]&0xff == 0xff)
{
if(buf[i + 1]&0xf0 == 0xf0)
{
offset_len = i;
return true;
}
}
}
return false;
}