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;
}