音视频解封装--解封装分离音频AAC文件

1:简介

         如下图所示,解封装就是将Flv、MP4等文件解封装为视频H264或H265压缩数据,音频解封装为AAC压缩数据。

 2:ADTS头结构

        ADTS的全称是Audio Data Transport Stream,是AAC音频的传输流TS格式。ADTS可以再任意帧解码,每一帧都有头信息。

        AAC音频文件的每一帧由ADTS Header和AAC Audio Data组成,ADTS头信息为7个字节或者9个字节(一般情况为7个字节,取决于是否包含CRC校验,也就是固定头中protection_absent的值),分为adts_fixed_header固定头,adts_variable_header可变头;固定头信息中的数据每一帧都相同,可变头信息在帧与帧之间可变。

 

3:流程分析 

 4:代码分析

        这里代码逻辑不是很严谨,异常部分也未作处理,着力先提取出AAC数据。

#include <iostream>
#include <stdio.h>
extern "C"
{
#include <libavformat/avformat.h>
}
using namespace std;

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

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; // 默认48000hz
    int adtsLen = data_length + 7;//adts头为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
    p_adts_header[1] = 0xf0;//syncword
    p_adts_header[1] |= 0;//ID:MPEG标识符,0标识MPEG-4,1标识MPEG-2
    p_adts_header[1] |= 0;
    p_adts_header[1] |= 1;
    p_adts_header[2] |= profile << 6;
    p_adts_header[2] |= (sampling_frequency_index & 0x0f) << 2;
    p_adts_header[2] |= 0 << 1;
    p_adts_header[2] |= (channels & 0x04)>>2;

    p_adts_header[3] = (channels & 0x03)<<6; //channel configuration:channels 低2bits

    p_adts_header[3] = (channels & 0x03)<<6; //channel configuration:channels 低2bits
    p_adts_header[3] |= (0 << 5);               //original:0                1bit
    p_adts_header[3] |= (0 << 4);               //home:0                    1bit
    p_adts_header[3] |= (0 << 3);               //copyright id bit:0        1bit
    p_adts_header[3] |= (0 << 2);               //copyright id start:0      1bit
    p_adts_header[3] |= ((adtsLen & 0x1800) >> 11);           //frame length:value   高2bits

    p_adts_header[4] = (uint8_t)((adtsLen & 0x7f8) >> 3);     //frame length:value    中间8bits
    p_adts_header[5] = (uint8_t)((adtsLen & 0x7) << 5);       //frame length:value    低3bits
    p_adts_header[5] |= 0x1f;                                 //buffer fullness:0x7ff 高5bits
    p_adts_header[6] = 0xfc;      //‭11111100‬       //buffer fullness:0x7ff 低6bits
}



int main()
{
    const char *default_filename = "believe.mp4";
    FILE *aac_fd = NULL;
    aac_fd = fopen("mp4ToAac.aac", "wb");



    //1:解复用器上下文分配
    AVFormatContext *ctx = NULL;


    int audio_index = -1;

    //2:打根据url打开文件
    int ret = 0;
    char errors[1024];
    if((ret = avformat_open_input(&ctx, default_filename, NULL, NULL)) < 0)
       {
           av_strerror(ret, errors, 1024);
           av_log(NULL, AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n",
                  default_filename,
                  ret,
                  errors);
           return -1;
       }

    //3:读取媒体数据包获取码流信息
    ret = avformat_find_stream_info(ctx,NULL);
    if(ret <0)
    {
        if(ctx)
            avformat_free_context(ctx);
        getchar();
        return 0;
    }

    //av_dump_format(ctx,0,default_filename,0);
    //4:查找音频流
    audio_index = av_find_best_stream(ctx,AVMEDIA_TYPE_AUDIO,-1,-1,NULL,0);
    if(audio_index < 0)
    {
        printf("av_find_best_Stream failed");
        return 0;
    }

    AVPacket pkt;
    av_init_packet(&pkt);

    if(ctx->streams[audio_index]->codecpar->codec_id != AV_CODEC_ID_AAC)
    {
      printf("the medio file not find aav stream");
       return 0;
    }
    printf("av_read_frame");
    //5:读一帧数据到pkt中
    while(av_read_frame(ctx,&pkt) >= 0)
    {
        if (pkt.stream_index == audio_index)
        {
            //6:添加adts头
            char adts_header_buf[7] = {0};
            adts_header(adts_header_buf,pkt.size,
                        ctx->streams[audio_index]->codecpar->profile,
                        ctx->streams[audio_index]->codecpar->sample_rate,
                        ctx->streams[audio_index]->codecpar->channels);
            //7:aac文件输出
            fwrite(adts_header_buf,1,7,aac_fd);
            int len = fwrite(pkt.data,1,pkt.size,aac_fd);
            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);
    }

    printf("succes");

    if(ctx)
    {
        avformat_close_input(&ctx);
    }
    if(aac_fd)
    {
        fclose(aac_fd);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值