ffmpeg-从flv文件中提取AAC音频数据保存为文件

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, //0x0
    88200, //0x1
    64000, //0x2
    48000, //0x3
    44100, //0x4
    32000, //0x5
    24000, //0x6
    22050, //0x7
    16000, //0x8
    12000,  // 0x9
    11025,  // 0xa
    8000   // 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; //默认使用48000
    int 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   = 3
    p_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);

    //初始化packet
    av_init_packet(&pkt);

    //查找audio对应的stream index
    audio_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 header
           fwrite(adts_header_buf, 1, 7, aac_fd);

           len = fwrite(pkt.data, 1, pkt.size, aac_fd);//写入adts data

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







猜你喜欢

转载自blog.csdn.net/m0_37599645/article/details/112007245