AAC ADTS格式协议:
从flv文件中提取AAC音频数据保存为文件。
如果需要详细了解AAC ADTS格式,可以查询文档。
原文件:
提取aac文件:
main.c
#include <stdio.h>
#include <libavutil/log.h>>
#include <libavformat/avio.h>
#include <libavformat/avformat.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_frequencies_index = 3; //默认使用48000int adtsLen = data_length + 7;//根据输入文件的samplerate 获取 相应的在ADTS中设置的索引int frequencies_size = sizeof(sampling_frequencies) / sizeof(sampling_frequencies[0]);int i = 0;for(i = 0; i < frequencies_size; i++){if(samplerate == sampling_frequencies[i]){sampling_frequencies_index = i;break;}}if(sampling_frequencies_index >= frequencies_size){printf("unsupport samplerate:%d\n", samplerate);return -1;}//同步头 总是0xFFF(12个bit),代表着一个ADTS帧的开始p_adts_header[0] = 0xff;p_adts_header[1] = 0xf0;//MPEG标识符,0标识MPEG-4,1标识MPEG-2(1个bit)p_adts_header[1] |= (0 << 3);//layer,总是0(2个bit)p_adts_header[1] |= (0 << 1);//protection_absent ,表示是否误码校验,1表示 没有, 0 表示有。(1个bit)//(注意:ADTS Header的长度在protection_absent = 0 时占9个字节, protection_absent = 1时占7个字节)p_adts_header[1] |= 1;//profile 使用aac的级别(质量)(2个bit)//MPEG-4 profile://MAIN = 0//LC = 1//SSR = 2//LTP = 3p_adts_header[2] = (profile)<<6;//采样率的索引(4个bit)p_adts_header[2] |= (sampling_frequencies_index & 0x0f) << 2;//private bit: 0 (1个bit)p_adts_header[2] |= (0 << 1);//声道(3个bit)p_adts_header[2] |= (channels & 0x04) >> 2;p_adts_header[3] = (channels & 0x03) << 6;//original_copy = 0 (1个bit)p_adts_header[3] |= (0 << 5);//home = 0 (1个bit)p_adts_header[3] |= (0 << 4);//copyright_identification_bit = 0 (1个bit)p_adts_header[3] |= (0 << 3);//copyright_identification_start = 0 (1个bit)p_adts_header[3] |= (0 << 2);//frame_length:1个ADTS帧的长度包括ADTS头和AAC原始流(13bit)p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);p_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);p_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);//adts_buffer_fullness:0x7FF 说明是码率可变的码流p_adts_header[5] |= 0x1f;p_adts_header[6] = 0xfc;//最后还有两个bit:number_of_raw_data_blocks_in_frame//表示这个ADTS帧有几个AAC数据块//计算方法://number_of_raw_data_blocks_in_frame + 1个AAC原始帧。//所以说number_of_raw_data_blocks_in_frame == 0 表示说ADTS帧中有⼀个//AAC数据块。p_adts_header[6] &= 0xfc;//其实上面p_adts_header[6] = 0xfc的操作这2个bit已经为0了return 0;
}int main()
{int ret = -1;char errors[1024];char* in_filename = "in_file.flv";char* aac_filename = "test_out.aac";FILE* aac_fd = NULL;int audio_index = -1;int len = 0;AVFormatContext* ifmat_ctc = NULL;AVPacket pkt;//设置打印级别av_log_set_level(AV_LOG_DEBUG);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(&ifmat_ctc, 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(ifmat_ctc, 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(ifmat_ctc, 0, in_filename, 0);//初始化packetav_init_packet(&pkt);//查找audio对应的stream indexaudio_index = av_find_best_stream(ifmat_ctc, 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",ifmat_ctc->streams[audio_index]->codecpar->profile,FF_PROFILE_AAC_LOW);if(ifmat_ctc->streams[audio_index]->codecpar->codec_id != AV_CODEC_ID_AAC){printf("the media file no contain AAC stream, it's codec_id is %d\n",ifmat_ctc->streams[audio_index]->codecpar->codec_id);goto END;}//读取媒体文件,并把aac数据帧写入本地文件while (av_read_frame(ifmat_ctc, &pkt) >=0 ){if(pkt.stream_index == audio_index){char adts_header_buf[7] = {0};//获取ADTS帧头信息adts_header(adts_header_buf, pkt.size,ifmat_ctc->streams[audio_index]->codecpar->profile,ifmat_ctc->streams[audio_index]->codecpar->sample_rate,ifmat_ctc->streams[audio_index]->codecpar->channels);//写入adts header,ts流不适用,ts流分离出来的packet带了adts headerfwrite(adts_header_buf, 1, 7, aac_fd);len = fwrite(pkt.data, 1, pkt.size, aac_fd);//写入adts dataif(len != pkt.size){av_log(NULL, AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n",len,pkt.size);}}av_packet_unref(&pkt);}END:if(ifmat_ctc)avformat_close_input(&ifmat_ctc);if(aac_fd)fclose(aac_fd);return 0;
}