当前位置: 首页 > 工具软件 > BSF > 使用案例 >

从flv文件中提取h264码流(使用av_bsf_send_packet和av_bsf_receive_packet)

邓崇凛
2023-12-01

最近在学习音视频开发,需要开发一个从flv文件中提取h264码流的demo。

具体的原理,在雷神的文章中写的很清楚了:
https://blog.csdn.net/leixiaohua1020/article/details/39767055
https://blog.csdn.net/leixiaohua1020/article/details/39802819

在这里致敬一下雷神,给我们这些小白入门音视频铺平了道路!

但是雷神在Demo中使用的API是旧版本的API,比如bitstream_filter相关的:
av_bitstream_filter_init()
av_bitstream_filter_filter()
等,这些API即将被弃用,我们需要使用新版本的API

但是网上并没有找到相关的实现,根据上面链接的方法也并不能正确解析出h264码流。

在分析bitstream_filter.c源码后我们发现,在调用av_bsf_init()前需要调用avcodec_parameters_from_context(),增加解码必要的一些参数。

修改后的demo如下,大家可以用来参考。因为我也是刚入门,所以欢迎大家批评指正~:

#include <stdio.h>
#include <libavformat/avformat.h>
#define FFMPEG_NEW

int main() {
    AVFormatContext *ifmt_ctx = NULL;
    AVPacket pkt;
    int ret, i;
    int videoindex = -1, audioindex = -1;
    const char *in_filename = "demo.flv";
    const char *out_filename_v = "ffmpeg_demo.h264";
    const char *out_filename_a = "ffmpeg_demo.mp3";

    //av_register_all(); 已废弃

    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
        printf("Could not open input file.");
        goto ERROR;
    }

    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
        printf("Failed to retrieve input stream information");
        goto ERROR;
    }

    videoindex = -1;
    for (i=0; i<ifmt_ctx->nb_streams; i++) { //nb_streams:视音频流的个数
        if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
            videoindex = i;
        else if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
            audioindex = i;
    }

    printf("\nInput Video===========================\n");
	av_dump_format(ifmt_ctx, 0, in_filename, 0);  // 打印信息
	printf("\n======================================\n");

    FILE *fp_audio=fopen(out_filename_a,"wb+");  
	FILE *fp_video=fopen(out_filename_v,"wb+");

#ifdef FFMPEG_NEW
    AVBSFContext *bsf_ctx = NULL; 
    const AVBitStreamFilter *pfilter = av_bsf_get_by_name("h264_mp4toannexb");
    if (pfilter == NULL) {
        printf("Get bsf failed!\n");
        goto ERROR;
    }
#else 
    AVBitStreamFilterContext* h264bsfc =  av_bitstream_filter_init("h264_mp4toannexb");
#endif

    while (av_read_frame(ifmt_ctx, &pkt) >= 0) {
        if (pkt.stream_index == videoindex) {
#ifdef FFMPEG_NEW
            if ((ret = av_bsf_alloc(pfilter, &bsf_ctx)) != 0) {
                printf("Alloc bsf failed!\n");
                goto ERROR;
            }
            ret = avcodec_parameters_from_context(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codec);
            if (ret < 0) {
                printf("Set Codec failed!\n");
                goto ERROR;
            }
            ret = av_bsf_init(bsf_ctx);
            if (ret < 0) {
                printf("Init bsf failed!\n");
                goto ERROR;
            }
            av_bsf_send_packet(bsf_ctx, &pkt);
            ret = av_bsf_receive_packet(bsf_ctx, &pkt);
            if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                break;
            else if (ret < 0) {
                printf("Receive Pkt failed!\n");
                goto ERROR;
            }
#else
            av_bitstream_filter_filter(h264bsfc, ifmt_ctx->streams[videoindex]->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
#endif
            printf("Write Video Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts);
            fwrite(pkt.data, 1, pkt.size, fp_video);
        }
        else if (pkt.stream_index == audioindex) {
            printf("Write Audio Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts);
            fwrite(pkt.data, 1, pkt.size, fp_audio);
        }
        av_packet_unref(&pkt);
    }
#ifdef FFMPEG_NEW
    av_bsf_free(&bsf_ctx);
#else
    av_bitstream_filter_close(h264bsfc); 
#endif

    fclose(fp_video);
	fclose(fp_audio);
 
	avformat_close_input(&ifmt_ctx);
    return 0;

ERROR:
    if (ifmt_ctx)
        avformat_close_input(&ifmt_ctx);
    if (fp_audio)
        fclose(fp_audio);
    if (fp_video)
        fclose(fp_video);
    if (bsf_ctx)
        av_bsf_free(&bsf_ctx);
    return -1;
}
 类似资料: