11.FFmpeg学习笔记 - 解复用分离aac码流

上一篇文章,是分离视频文件里的mp3音频码流,分离出来后是可以直接播放的。但是对于aac编码的音频,直接分离aac码流是不一定能播放的。如果视频复用格式是TS,则直接存储AVPacket的data是可以播放的。如果是mp4/flv/mkv等格式则不行,因为调用av_read_frame()后得到的AVPacket里面的内容是AAC纯数据,就是那种不包含ADTS文件头的AAC数据。

本以为仿照分离h264的方法,用 “aac_adtstoasc” bitstream filter会起作用,没想到还是不能播放,官方文档对aac_adtstoasc的解释:

aac_adtstoasc只是把带ADTS头的AAC流封装进MOV/MP4等格式时,创建MPEG-4 AudioSpecificConfig(asc),并去掉ADTS header。并没有相反的过程。所以只能手动添加7字节的ADTS头。

下面代码输入是一个ts格式的视频,分离aac数据,直接可播放。

void demux_ts(void)
{
    const char *src_filename = "/Users/zhw/Desktop/resource/sintel_h264_aac.ts";
    const char *audio_dst_filename = "/Users/zhw/Desktop/sintel.aac";
    
    
    int audio_index;
    AVFormatContext *ifmt_ctx = NULL;
    
    AVPacket pkt;
    
    /* open input file, and allocate format context */
    if (avformat_open_input(&ifmt_ctx, src_filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open source file %s\n", src_filename);
        exit(1);
    }
    
    /* retrieve stream information */
    if (avformat_find_stream_info(ifmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        exit(1);
    }
    
    audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if (audio_index < 0) {
        fprintf(stderr, "Could not find %s stream\n",
                av_get_media_type_string(AVMEDIA_TYPE_AUDIO));
        return;
    }
    
    FILE *out_file = fopen(audio_dst_filename, "wb");
    if (!out_file) {
        fprintf(stderr, "open out_file error");
        return;
    }
    
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;
    
    while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == audio_index) {
            fwrite(pkt.data, 1, pkt.size, out_file);
        }
        av_packet_unref(&pkt);
    }
    printf("finish\n");
    
}

下面代码的输入是mkv/mp4/flv格式的视频文件, 分离aac码流,并添加ADTS header后,可以播放。

void demux_other(void)
{
    const char *src_filename = "/Users/zhw/Desktop/resource/sintel_h264_aac.flv";
    const char *audio_dst_filename = "/Users/zhw/Desktop/sintel.aac";
    
    int audio_index;
    AVFormatContext *ifmt_ctx = NULL;
    AVPacket pkt;
    
    /* open input file, and allocate format context */
    if (avformat_open_input(&ifmt_ctx, src_filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open source file %s\n", src_filename);
        exit(1);
    }
    
    /* retrieve stream information */
    if (avformat_find_stream_info(ifmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        exit(1);
    }
    
    audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    if (audio_index < 0) {
        fprintf(stderr, "Could not find %s stream\n",
                av_get_media_type_string(AVMEDIA_TYPE_AUDIO));
        return;
    }
    
    FILE *out_file = fopen(audio_dst_filename, "wb");
    if (!out_file) {
        fprintf(stderr, "open out_file error");
        return;
    }
    
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;
    
    AVStream *stream = ifmt_ctx->streams[audio_index];
    AVCodecParameters *params = stream->codecpar;
    
    //从文件读取数据
    while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == audio_index) {
            
            char bits[7] = {0};
            int aac_frame_length = 7 + pkt.size;
            int sample_index = find_sample_index(params->sample_rate);
            int channels = params->channels;
            if (channels == 8) {
                channels = 7;
            }
            
            bits[0] = 0xff;
            bits[1] = 0xf9;
            bits[2] = (params->profile << 6);
            bits[2] |= (sample_index << 2);
            bits[2] |= (channels >> 2);
            bits[3] |= ((channels << 6) & 0xC0);
            bits[3] |= (aac_frame_length >> 11);
            bits[4] = ((aac_frame_length >> 3) & 0xFF);
            bits[5] = ((aac_frame_length << 5) & 0xE0);
            bits[5] |= (0x7FF >> 6);
            bits[6] = 0xfc;
            
            fwrite(bits, 1, 7, out_file);
            
            fwrite(pkt.data, 1, pkt.size, out_file);
        }
        av_packet_unref(&pkt);
    }

    printf("finish\n");
    
}


int find_sample_index(int samplerate)
{
    int adts_sample_rates[] = {96000,882000,64000,48000,441000,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0};
    int i;
    for(i=0; i < 16;i++)
    {
        if(samplerate == adts_sample_rates[i])
            return i;
    }
    return 16 - 1;
}

猜你喜欢

转载自blog.csdn.net/whoyouare888/article/details/94383440