ffmpeg-从mp4、flv、ts文件中提取264视频流数据

ffmpeg-从mp4、flv、ts文件中提取264视频流数据

main.c

#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>





void proc(int need_to_annexb, char* in_file, char* out_file)
{
    
    
    AVFormatContext* ifmat_ctx = NULL;
    int     videoindex = -1;
    AVPacket* pkt = NULL;
    int     ret = -1;
    int file_end = 0;

    //char* in_file = "believe.mp4";
    //char* out_file = "out_mp4_no_annexb.h264";

    FILE* out_fd = fopen(out_file, "wb");
    printf("in_file = %s , out_file = %s\n", in_file, out_file);

    //创建解复用器,最后使用avformat_close_input()释放相关内存
    ifmat_ctx = avformat_alloc_context();
    if(!ifmat_ctx)
    {
    
    
        printf("avformat_alloc_context faild!\n");
        return -1;
    }

    //根据url打开码流,会选择匹配的解复用器的
    ret = avformat_open_input(&ifmat_ctx, in_file, NULL, NULL);
    if(ret != 0)
    {
    
    
        printf("avformat_open_input failed!\n");
        return -1;
    }

    //读取媒体文件的部分数据包可以获取码流信息
    ret = avformat_find_stream_info(ifmat_ctx, NULL);
    if(ret < 0)
    {
    
    
        printf("avformat_find_stream_info faile!\n");
        avformat_close_input(&ifmat_ctx);
        return -1;
    }

    //查找出哪个码流是音频还是视频还是字幕
    videoindex = av_find_best_stream(ifmat_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if(videoindex == -1)
    {
    
    
        printf("av_find_best_stream failed!\n");
        avformat_close_input(&ifmat_ctx);
        return -1;
    }

    //分配packet
    pkt = av_packet_alloc();
    av_init_packet(pkt);


    file_end = 0;
    while (0 == file_end)
    {
    
    
        if((ret = av_read_frame(ifmat_ctx, pkt)) < 0)
        {
    
    
            file_end = 1;
            printf("av_read_frame end!\n");
        }

        //读出的帧判断是否是视频帧
        if(ret == 0 && pkt->stream_index == videoindex)
        {
    
    
            //是否需要使用h264_mp4toannexb转换
            if(need_to_annexb)
            {
    
    

                //获取比特流过滤器(h264_mp4toannexb)
                const AVBitStreamFilter* bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
                AVBSFContext *bsf_ctx = NULL;
                //申请过滤器上下文
                av_bsf_alloc(bsfilter, &bsf_ctx);
                //从视频流中拷贝编解决码器参数
                avcodec_parameters_copy(bsf_ctx->par_in, ifmat_ctx->streams[videoindex]->codecpar);
                //初始化过滤器上下文
                av_bsf_init(bsf_ctx);

                int input_size = pkt->size;

                //记录下是否send 一个packet,receive 一个packet。基本都是这个情况的
                //有比较少情况出现会send 一个packet,receive 几个packet
                //(SPS、PPS、I帧在一个packet send,receive 多个packet)。
                int out_pkt_count = 0;

                if(av_bsf_send_packet(bsf_ctx, pkt) != 0)
                {
    
    
                    //不管是否成功,都要释放packet,因为bitstreamfilter内部还有引用这个内存空间的
                    av_packet_unref(pkt);
                    continue;
                }
                //不管是否成功,都要释放packet,因为bitstreamfilter内部还有引用这个内存空间的
                av_packet_unref(pkt);

                while (av_bsf_receive_packet(bsf_ctx , pkt) == 0)
                {
    
    
                    out_pkt_count++;
                    size_t size = fwrite(pkt->data, 1, pkt->size, out_fd);
                    if(size != pkt->size)
                    {
    
    
                        printf("fwrite failed!\n");
                    }
                    av_packet_unref(pkt);
                }

                //send 一个packet ,receive pakcet 超过2个就输出提示信息
                if(out_pkt_count >= 2)
                {
    
    
                    printf("one send packet size = %d, receive %d packet.\n", input_size,
                           out_pkt_count);
                }
                if(bsf_ctx)
                    av_bsf_free(&bsf_ctx);
            }
            else
            {
    
    
                size_t size = fwrite(pkt->data, 1, pkt->size, out_fd);
                if(size != pkt->size)
                {
    
    
                    printf("fwrite failed!\n");
                }
                av_packet_unref(pkt);

            }

        }
        else
        {
    
    
            if(ret == 0)
            {
    
    
                av_packet_unref(pkt);
            }
        }
    }

    if(out_fd)
        fclose(out_fd);

    if(pkt)
        av_packet_free(&pkt);
    if(ifmat_ctx)
        avformat_close_input(&ifmat_ctx);

}

int main()
{
    
    
    proc(1, "believe.flv", "out_flv_need_toannexb.h264");//使用ffplay可以播放
    proc(0, "believe.flv", "out_flv_no_toannexb.h264");//使用ffplay不可以
    proc(1, "believe.mp4", "out_mp4_need_toannexb.h264");//使用ffplay可以播放
    proc(0, "believe.mp4", "out_mp4_no_toannexb.h264");//使用ffplay不可以
    proc(1, "believe.ts", "out_ts_need_toannexb.h264");//使用ffplay可以播放
    proc(0, "believe.ts", "out_ts_no_toannexb.h264");//使用ffplay可以播放

    //注意:
    //flv/mp4/mkv一些结构中,h264需要h264_mp4toannexb处理,添加startcode/SPS/PPS等信息
    //ts不用h264_mp4toannexb处理。

    return 0;
}




flv两个文件的对比:
在这里插入图片描述
mp4两个文件的对比:
在这里插入图片描述
ts两个文件的对比:
在这里插入图片描述

猜你喜欢

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