9.FFmpeg学习笔记 - 解复用分离h264码流2

上一篇文章,是分离ts格式里的h264码流,分离出来后是可以直接播放的。但是对于mkv/flv/mp4等格式,直接分离h264码流是不能直接播放的,因为AVPacket的data里只包含视频压缩数据,并不包含pps,sps信息,也没有0x00000001和0x000001分隔符,没有这些信息,单凭h264码流是无法解码播放的。

H.264码流的SPS和PPS信息存储在AVCodecContext结构体的extradata中。需要使用ffmpeg中名称为“h264_mp4toannexb”的bitstream filter处理。

void demux(void)
{
    const char *src_filename = "/Users/zhw/Desktop/sintel.mkv";
    const char *video_dst_filename = "/Users/zhw/Desktop/sintel.h264";
    
    
    int video_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);
    }
    
    video_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (video_index < 0) {
        fprintf(stderr, "Could not find %s stream\n",
                av_get_media_type_string(AVMEDIA_TYPE_VIDEO));
        return;
    }
    
    FILE *out_file = fopen(video_dst_filename, "wb");
    if (!out_file) {
        fprintf(stderr, "open out_file error");
        return;
    }
    
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;
    
    //设置AVBitStreamFilter
    int ret;
    AVBSFContext *bsf_ctx;
    const AVBitStreamFilter *filter = av_bsf_get_by_name("h264_mp4toannexb");
    if(!filter)
    {
        fprintf(stderr, "Unkonw bitstream filter");
        return;
    }
    ret = av_bsf_alloc(filter, &bsf_ctx);
    if (ret < 0) {
        fprintf(stderr, "alloc bsf error");
        return;
    }
    
    ret = avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[video_index]->codecpar);
    if (ret < 0) {
        fprintf(stderr, "copy bsf error");
        return;
    }
    
    av_bsf_init(bsf_ctx);
    
    //从文件读取数据
    while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == video_index) {
            
            if (av_bsf_send_packet(bsf_ctx, &pkt) < 0) {
                fprintf(stderr, "send_packet error");
                av_packet_unref(&pkt);
                continue;
            }
            
            while (av_bsf_receive_packet(bsf_ctx, &pkt) == 0) {
                fwrite(pkt.data, 1, pkt.size, out_file);
                av_packet_unref(&pkt);
            }

        }
    }
    
    //flush
    if (av_bsf_send_packet(bsf_ctx, NULL) < 0) {
        fprintf(stderr, "send_packet error");
        return;
    }
    while (av_bsf_receive_packet(bsf_ctx, &pkt) == 0) {
        fwrite(pkt.data, 1, pkt.size, out_file);
        av_packet_unref(&pkt);
    }
    
    av_bsf_free(&bsf_ctx);
    
    printf("finish\n");
    
    h264_parser(video_dst_filename);

    
}

查看所有可用的bitstream filter,可以在下载源码后,执行以下命令:

./configure --list-bsfs

资源文件下载地址:

https://github.com/whoyouare888/Note/tree/master/resource

猜你喜欢

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