做网站商城赔了8万,win7如何建设免费网站,WordPress电子书主题模板,wordpress 数据库 nginx这一节#xff0c;我们学习常用的音频的格式 AAC#xff0c;重点是掌握 AAC的传输格式 ADTS 头部的信息#xff0c;目的是 #xff1a; 当音频数据有问题的时候#xff0c;如果是AAC的编码#xff0c;在分析 头部信息的时候能够根据头部信息 判断问题是否出现在 头部。 A…这一节我们学习常用的音频的格式 AAC重点是掌握 AAC的传输格式 ADTS 头部的信息目的是  当音频数据有问题的时候如果是AAC的编码在分析 头部信息的时候能够根据头部信息 判断问题是否出现在 头部。 AAC ADTS格式分析 
AAC⾳频格式Advanced Audio Coding(⾼级⾳频解码)是⼀种由MPEG-4标准定义的有损⾳频压缩格式由Fraunhofer发展Dolby, Sony和ATT是主要的贡献者。 AAC 的封装格式有两种 ADIF 和 ADTS ADIF已经基本弃用-ADIF只有⼀个统⼀的头所以必须得到所有的数据后解码。 Audio Data Interchange Format ⾳频数据交换格式。这种格式的特征是可以确定的找到这个⾳频数据的开始不需进⾏在⾳频数据流中间开始的解码即它的解码必须在明确定义的开始处进⾏。故这种格式常⽤在磁盘⽂件中。 ADTS ADTS可以在任意帧解码也就是说它每⼀帧都有头信息这个是重点 
Audio Data Transport Stream。是AAC⾳频的传输流格式。AAC⾳频格式在MPEG-2ISO-13318-7 2003中有定义。AAC后来⼜被采⽤到MPEG-4标准中。这种格式的特征是它是⼀个有同步字的⽐特流解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。 可能遇见的问题1 
有的时候当你编码AAC裸流的时候会遇到写出来的AAC⽂件并不能在PC和⼿机上播放很⼤的可能就是AAC⽂件的每⼀帧⾥缺少了ADTS头信息⽂件的包装拼接。 
只需要加⼊头⽂件ADTS即可。⼀个AAC原始数据块⻓度是可变的对原始帧加:上ADTS头进⾏ADTS的封装就形成了ADTS帧。 ADTS 格式下 AAC⾳频⽂件格式 每⼀帧由ADTS Header和AAC Audio Data在图中是 AAC ES组成。结构体如下 
也就是说一个AAC 帧包含了一个ADTS header 和 一堆具体的数据。另外AAC的一帧一般包含了1024个采样点。 头文件 ADTS Header 的组成 是由 固定头信息    可变头信息 。组成 固定头信息中的数据每⼀帧都相同⽽可变头信息则在帧与帧之间可变 每⼀帧的ADTS的头⽂件都包含了⾳频的采样率声道帧⻓度等信息这样解码器才能解析读取。 
⼀般情况下ADTS的头信息都是7个字节分为2部分 
adts_fixed_header(); 
adts_variable_header(); 
其⼀为固定头信息紧接着是可变头信息。固定头信息中的数据每⼀帧都相同⽽可变头信息则在帧与帧之间可变。 头文件固定部分adts_fixed_header() syncword 同步头 总是0xFFF, all bits must be 1代表着⼀个ADTS帧的开始 12bits 
ID MPEG标识符0标识MPEG-41标识MPEG-2 1bits 
Layer always: 00 2 bits 
protection_absent表示是否误码校验。1代表 header 有 7个字节0代表 header有9个字节一般情况下都是7个字节。Warning, set to 1 if there is no CRC and 0 if there is CRC 1bits 
profile表示使⽤哪个级别的AAC如01 Low Complexity(LC)--- AAC LC。有些芯⽚只⽀持AAC LC 。 2bits。。 通过前面的ID我们可以设置是 MPEG-4 还是 MPEG-2 
在MPEG-2 中有明确的指出 profile这个值是多少。且只有三种 参见下表 在MPEG-4中profile的计算要通过  MPEG-4 Audio Object Type - 1 
profile  MPEG-4 Audio Object Type - 1 
如下的MPEG-4中关于 aac audio Object Type的说明 对应的profile的值 sampling_frequency_index表示使⽤的采样率下标通过这个下标在 Sampling Frequencies[ ]数组中查找得知采样率的值。4bits channel_configuration: 表示声道数⽐如2表示⽴体声双声道 3bits  
MPEG-4 中规定的值如下 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 还有3个没有介绍都占1bite 
private_bits: 
original: 
home: 头文件adts_variable_header() copyright_identification_bits: 未知 占1bits 
copyright_identification_start 未知占1bits aac_frame_length : ⼀个ADTS帧的⻓度 包括ADTS头和AAC原始流. 单位是bytes 
aac_frame_length  (protection_absent  1 ? 7 : 9)  size(AACFrame) 13 bits 
protection_absent0时, header length9bytes 
protection_absent1时, header length7bytes 
adts_buffer_fullness0x7FF 说明是码率可变的码流。一般都是写的0x7FF这个值 11bits number_of_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame  1个AAC原始帧。  如果number_of_raw_data_blocks_in_frame 的值是0 表示说ADTS帧中有⼀个AAC原始帧。  如果 number_of_raw_data_blocks_in_frame 的值是1表明ADTS帧中有2个原始帧。 例子 下⾯是ADTS的AAC⽂件部分⾼字节开始算   第⼀帧的帧头7个字节为0xFF 0xF1 0x4C 0x40 0x20 0xFF 0xFC 我们将这7个字节拿出来转化成2进制 0xFF         0xF1          0x4C          0x40             0x20            0xFF          0xFC 11111111   11110001   01001100   0100 0000   0010 0000   1111 1111   1111 1100 分析各个关键数值 0xFF 0xF1 表示如下的部分 111111111111 syncword 同步头 总是0xFFF, all bits must be 1代表着?个ADTS帧的开始 12bits 0 ID MPEG标识符0标识MPEG-41标识MPEG-2 1bits 00 Layer always: 00 2 bits 1 protection_absent表示是否误码校验。1代表 header 有 7个字节0代表 header有9个字节一般情况下都是7个字节。Warning, set to 1 if there is no CRC and 0 if there is CRC 1bits   0x4C 全部 0x40中的4 表示部分如下 01 profile表示使?哪个级别的AAC如01 Low Complexity(LC)--- AAC LC。有些芯片只支持AAC LC 。 2bits 0011 sampling_frequency_index  通过这个下标在 Sampling Frequencies[ ]数组中找采样率的值 4bits 0 private_bits: 1 bits 001 channel_configuration: 表示声道数比如2表示立体声双声道 3bits 0 original: 1bits 0 home: 1bits  0x40中的4  0x20 0xFF 0xFC 全部表示如下 0 copyright_identification_bits: 未知 占1bits  0 copyright_identification_start 未知占1bits  0000100000111(帧⻓度) aac_frame_length 占 13 bits 11111111111 adts_buffer_fullness0x7FF 说明是码率可变的码流。 11bits  00 number_of_raw_data_blocks_in_frame 表示ADTS帧中有number_of_raw_data_blocks_in_frame  1个AAC原始帧。 占2bits 一般一个  计算帧⻓度将⼆进制 0000100000111 转换成⼗进制为263。观察第⼀帧的⻓度确实为263个字节。红色部分的为帧头部的固定部分 0xFF 0xF1 0x4C 0x40 0x20 0xFF 0xFC  该帧长度所属位置为蓝色部分其中 第一个0的后两个0 0000 得到帧长度的计算⽅法:帧⻓度为13位使⽤unsigned int来存储帧⻓数值  unsigned int getFrameLength(unsigned char* str)
{if ( !str ){return 0;}unsigned int len  0;int f_bit  str[3];int m_bit  str[4];int b_bit  str[5];len  (b_bit5);len  (m_bit3);len  ((f_bit3)11);return len;
}  核心编码注意的在生成 ADTS Header 的代码      // 读取媒体文件并把aac数据帧写入到本地文件注意从mp4文件中读取到的aac就只有 aac data 的部分没有头的部分头的部分我们需要自己添加使用的方法为自定义的adts_header方法
//    av_read_frame方法的一些说明
//    对于音频如果每个帧具有已知的固定大小例如PCM或ADPCM数据则它包含整数个帧。// 如果音频帧具有可变大小例如MPEG音频则它包含一个帧。//当前走到这里读取的一定是AAC数据那么av_read_frame读取到pkt中的一定是一帧的大小因此adts_header方法中传递的第二个参数就是一帧的大小。int ret1 0;while((ret1  av_read_frame(ifmt_ctx, pkt)) 0 ){if(pkt.stream_index  audio_index){char adts_header_buf[7]  {0};//这里我们自己写的时候头部占7bytes意味着 校验位的值是1表示不用校验adts_header(adts_header_buf, pkt.size,ifmt_ctx-streams[audio_index]-codecpar-profile,ifmt_ctx-streams[audio_index]-codecpar-sample_rate,ifmt_ctx-streams[audio_index]-codecpar-channels);fwrite(adts_header_buf, 1, 7, aac_fd);  // 写adts header , ts流不适用ts流分离出来的packet带了adts headerlen  fwrite( pkt.data, 1, pkt.size, aac_fd);   // 写adts dataif(len ! pkt.size){av_log(NULL, AV_LOG_DEBUG, warning, length of writed data isnt equal pkt.size(%d, %d)\n,len,pkt.size);}}av_packet_unref(pkt);}   int adts_header(char * const p_adts_header, const int data_length,const int profile, const int samplerate,const int channels)
{int sampling_frequency_index  3; // 默认使用48000hzint adtsLen  data_length  7;int frequencies_size  sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);int i  0;for(i  0; i  frequencies_size; i){if(sampling_frequencies[i]  samplerate){sampling_frequency_index  i;break;}}if(i  frequencies_size){printf(unsupport samplerate:%d\n, samplerate);return -1;}p_adts_header[0]  0xff;         //syncword:0xfff                          高8bitsp_adts_header[1]  0xf0;         //syncword:0xfff                          低4bitsp_adts_header[1] | (0  3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bitp_adts_header[1] | (0  1);    //Layer:0                                 2bitsp_adts_header[1] | 1;           //protection absent:1                     1bitp_adts_header[2]  (profile)6;            //profile:profile               2bitsp_adts_header[2] | (sampling_frequency_index  0x0f)2; //sampling frequency index:sampling_frequency_index  4bitsp_adts_header[2] | (0  1);             //private bit:0                   1bitp_adts_header[2] | (channels  0x04)2; //channel configuration:channels  高1bitp_adts_header[3]  (channels  0x03)6; //channel configuration:channels 低2bitsp_adts_header[3] | (0  5);               //original0                1bitp_adts_header[3] | (0  4);               //home0                    1bitp_adts_header[3] | (0  3);               //copyright id bit0        1bitp_adts_header[3] | (0  2);               //copyright id start0      1bitp_adts_header[3] | ((adtsLen  0x1800)  11);           //frame lengthvalue   高2bitsp_adts_header[4]  (uint8_t)((adtsLen  0x7f8)  3);     //frame length:value    中间8bitsp_adts_header[5]  (uint8_t)((adtsLen  0x7)  5);       //frame length:value    低3bitsp_adts_header[5] | 0x1f;                                 //buffer fullness:0x7ff 高5bitsp_adts_header[6]  0xfc;      //11111100       //buffer fullness:0x7ff 低6bits// number_of_raw_data_blocks_in_frame//    表示ADTS帧中有number_of_raw_data_blocks_in_frame  1个AAC原始帧。return 0;
}全部代码 #include stdio.h
#include libavutil/log.h
#include libavformat/avio.h
#include libavformat/avformat.h
#include libavcodec/avcodec.h#define ADTS_HEADER_LEN  7;const int sampling_frequencies[]  {96000,  // 0x088200,  // 0x164000,  // 0x248000,  // 0x344100,  // 0x432000,  // 0x524000,  // 0x622050,  // 0x716000,  // 0x812000,  // 0x911025,  // 0xa8000   // 0xb// 0xc d e f是保留的
};int adts_header(char * const p_adts_header, const int data_length,const int profile, const int samplerate,const int channels)
{int sampling_frequency_index  3; // 默认使用48000hzint adtsLen  data_length  7;int frequencies_size  sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);int i  0;for(i  0; i  frequencies_size; i){if(sampling_frequencies[i]  samplerate){sampling_frequency_index  i;break;}}if(i  frequencies_size){printf(unsupport samplerate:%d\n, samplerate);return -1;}p_adts_header[0]  0xff;         //syncword:0xfff                          高8bitsp_adts_header[1]  0xf0;         //syncword:0xfff                          低4bitsp_adts_header[1] | (0  3);    //MPEG Version:0 for MPEG-4,1 for MPEG-2  1bitp_adts_header[1] | (0  1);    //Layer:0                                 2bitsp_adts_header[1] | 1;           //protection absent:1                     1bitp_adts_header[2]  (profile)6;            //profile:profile               2bitsp_adts_header[2] | (sampling_frequency_index  0x0f)2; //sampling frequency index:sampling_frequency_index  4bitsp_adts_header[2] | (0  1);             //private bit:0                   1bitp_adts_header[2] | (channels  0x04)2; //channel configuration:channels  高1bitp_adts_header[3]  (channels  0x03)6; //channel configuration:channels 低2bitsp_adts_header[3] | (0  5);               //original0                1bitp_adts_header[3] | (0  4);               //home0                    1bitp_adts_header[3] | (0  3);               //copyright id bit0        1bitp_adts_header[3] | (0  2);               //copyright id start0      1bitp_adts_header[3] | ((adtsLen  0x1800)  11);           //frame lengthvalue   高2bitsp_adts_header[4]  (uint8_t)((adtsLen  0x7f8)  3);     //frame length:value    中间8bitsp_adts_header[5]  (uint8_t)((adtsLen  0x7)  5);       //frame length:value    低3bitsp_adts_header[5] | 0x1f;                                 //buffer fullness:0x7ff 高5bitsp_adts_header[6]  0xfc;      //11111100       //buffer fullness:0x7ff 低6bits// number_of_raw_data_blocks_in_frame//    表示ADTS帧中有number_of_raw_data_blocks_in_frame  1个AAC原始帧。return 0;
}int main(int argc, char *argv[])
{int ret  -1;char errors[1024];char *in_filename  NULL;char *aac_filename  NULL;FILE *aac_fd  NULL;int audio_index  -1;int len  0;AVFormatContext *ifmt_ctx  NULL;AVPacket pkt;// 设置打印级别av_log_set_level(AV_LOG_DEBUG);if(argc  3){av_log(NULL, AV_LOG_DEBUG, the count of parameters should be more than three!\n);return -1;}in_filename  argv[1];      // 输入文件aac_filename  argv[2];     // 输出文件if(in_filename  NULL || aac_filename  NULL){av_log(NULL, AV_LOG_DEBUG, src or dts file is null, plz check them!\n);return -1;}aac_fd  fopen(aac_filename, wb);if (!aac_fd){av_log(NULL, AV_LOG_DEBUG, Could not open destination file %s\n, aac_filename);return -1;}// 打开输入文件if((ret  avformat_open_input(ifmt_ctx, in_filename, NULL, NULL))  0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, Could not open source file: %s, %d(%s)\n,in_filename,ret,errors);return -1;}// 获取解码器信息if((ret  avformat_find_stream_info(ifmt_ctx, NULL))  0){av_strerror(ret, errors, 1024);av_log(NULL, AV_LOG_DEBUG, failed to find stream information: %s, %d(%s)\n,in_filename,ret,errors);return -1;}// dump媒体信息
//    av_dump_format(ifmt_ctx, 0, in_filename, 0);// 初始化packetav_init_packet(pkt);// 查找audio对应的steam indexaudio_index  av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);if(audio_index  0){av_log(NULL, AV_LOG_DEBUG, Could not find %s stream in input file %s\n,av_get_media_type_string(AVMEDIA_TYPE_AUDIO),in_filename);return AVERROR(EINVAL);}// 打印AAC级别printf(audio profile:%d, FF_PROFILE_AAC_LOW:%d\n,ifmt_ctx-streams[audio_index]-codecpar-profile,FF_PROFILE_AAC_LOW);if(ifmt_ctx-streams[audio_index]-codecpar-codec_id ! AV_CODEC_ID_AAC){printf(the media file no contain AAC stream, its codec_id is %d\n,ifmt_ctx-streams[audio_index]-codecpar-codec_id);goto failed;}// 读取媒体文件并把aac数据帧写入到本地文件while(av_read_frame(ifmt_ctx, pkt) 0 ){if(pkt.stream_index  audio_index){char adts_header_buf[7]  {0};adts_header(adts_header_buf, pkt.size,ifmt_ctx-streams[audio_index]-codecpar-profile,ifmt_ctx-streams[audio_index]-codecpar-sample_rate,ifmt_ctx-streams[audio_index]-codecpar-ch_layout.nb_channels);fwrite(adts_header_buf, 1, 7, aac_fd);  // 写adts header , ts流不适用ts流分离出来的packet带了adts headerlen  fwrite( pkt.data, 1, pkt.size, aac_fd);   // 写adts dataif(len ! pkt.size){av_log(NULL, AV_LOG_DEBUG, warning, length of writed data isnt equal pkt.size(%d, %d)\n,len,pkt.size);}}av_packet_unref(pkt);}failed:// 关闭输入文件if(ifmt_ctx){avformat_close_input(ifmt_ctx);}if(aac_fd){fclose(aac_fd);}return 0;
}