Utilice el filtro de ffmpeg para procesar datos de yuv, incluido el filtro dividido (derivación), el filtro de recorte (recorte), el filtro vflip (volteo vertical hacia arriba), el filtro de superposición (síntesis)

Utilice el filtro de ffmpeg para procesar datos de yuv, incluido el filtro dividido (derivación), el filtro de recorte (recorte), el filtro vflip (volteo vertical hacia arriba), el filtro de superposición (síntesis)

#include <stdio.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>


int main()
{
    
    
    printf("Hello video mark!\n");
    int ret = 0;
    FILE* infile = NULL;
    const char* infileName = "768x320.yuv";
    fopen_s(&infile, infileName, "rb+");
    if(!infile)
    {
    
    
        printf("fopen_s() infile failed!\n");
        return -1;
    }

    int in_width = 768;
    int in_height = 320;

    FILE* outfile = NULL;
    const char* outfileName = "out_mark.yuv";
    fopen_s(&outfile, outfileName, "wb");
    if(!outfile)
    {
    
    
        printf("fopen_s() outfile failed!\n");
        return -1;
    }

    //注册初始化所有过滤器
    avfilter_register_all();

    //用于整个过滤流程的一个封装
    AVFilterGraph* filter_grah = avfilter_graph_alloc();
    if(!filter_grah)
    {
    
    
        printf("avfilter_graph_alloc() failed!\n");
        return -1;
    }

    char args[512];
    sprintf(args,
            "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
            in_width, in_height, AV_PIX_FMT_YUV420P,
            1, 25, 1, 1);

    //获取一个用于AVFilterGraph输入的过滤器
    AVFilter* buffersSrc = avfilter_get_by_name("buffer");
    AVFilterContext* bufferSrc_ctx;
    //将bufferSrc添加到AVFilterGraph中
    //args是用在bufferSrc的参数
    ret = avfilter_graph_create_filter(&bufferSrc_ctx, buffersSrc,
                                       "in", args, NULL, filter_grah);
    if(ret < 0)
    {
    
    
        printf("avfilter_graph_create_filter() buffersSrc failed!\n");
        return -1;
    }

    AVBufferSinkParams* bufferSinkParams;
    AVFilterContext* bufferSink_ctx;
    //获取一个用于AVFilterGraph输出的过滤器
    AVFilter* bufferSink = avfilter_get_by_name("buffersink");
    enum AVPixelFormat pix_fmts[] = {
    
    AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE};
    bufferSinkParams = av_buffersink_params_alloc();
    bufferSinkParams->pixel_fmts = pix_fmts;
    ret = avfilter_graph_create_filter(&bufferSink_ctx, bufferSink,
                                       "out", NULL, bufferSinkParams, filter_grah);
    if(ret < 0)
    {
    
    
        printf("avfilter_graph_create_filter() bufferSink failed!\n");
        return -1;
    }


    //split filter(分流)
    AVFilter* splitFilter = avfilter_get_by_name("split");
    AVFilterContext* splitFilter_ctx;
    //outputs=2 分流2通道
    ret = avfilter_graph_create_filter(&splitFilter_ctx, splitFilter, "split",
                                       "outputs=2", NULL, filter_grah);
    if(ret < 0)
    {
    
    
        printf("avfilter_graph_create_filter() splitFilter failed!\n");
        return -1;
    }

    //crop filter(裁剪)
    AVFilter* cropFilter = avfilter_get_by_name("crop");
    AVFilterContext* cropFilter_ctx;
    ret = avfilter_graph_create_filter(&cropFilter_ctx, cropFilter, "crop",
                                       "out_w=iw:out_h=ih/2:x=0:y=0", NULL, filter_grah);

    if(ret < 0)
    {
    
    
        printf("avfilter_graph_create_filter() cropFilter failed!\n");
        return -1;
    }


    //vflip filter(垂直向上的翻转)
    AVFilter* vflipFilter = avfilter_get_by_name("vflip");
    AVFilterContext* vflipFilter_ctx;
    ret = avfilter_graph_create_filter(&vflipFilter_ctx, vflipFilter, "vflip",
                                       NULL, NULL, filter_grah);
    if(ret < 0)
    {
    
    
        printf("avfilter_graph_create_filter() vflipFilter failed!\n");
        return -1;
    }


    //overlay filter(合成)
    AVFilter* overlayFilter = avfilter_get_by_name("overlay");
    AVFilterContext* overlayFilter_ctx;
    ret = avfilter_graph_create_filter(&overlayFilter_ctx, overlayFilter, "overlay",
                                       "y=0:H/2", NULL, filter_grah);

    if(ret < 0)
    {
    
    
        printf("avfilter_graph_create_filter() overlayFilter failed!\n");
        return -1;
    }


    //srcFilter -> splitFilter
    //srcpad、dstpad是一个索引,通道的索引
    ret = avfilter_link(bufferSrc_ctx, 0, splitFilter_ctx, 0);
    if(ret != 0)
    {
    
    
        printf("avfilter_link() srcFilter -> splitFilter failed!\n");
        return -1;
    }

    //splitFilter[0] -> overlayfilter[0]
    ret = avfilter_link(splitFilter_ctx, 0, overlayFilter_ctx, 0);
    if(ret != 0)
    {
    
    
        printf("avfilter_link() splitFilter[0] -> overlayfilter[0] failed!\n");
        return -1;
    }

    //splitFilter[1] -> cropFilter
    ret = avfilter_link(splitFilter_ctx, 1, cropFilter_ctx, 0);
    if(ret != 0)
    {
    
    
        printf("avfilter_link() splitFilter[1] -> cropFilter failed!\n");
        return -1;
    }
\
    //cropFilter -> vflipFilter
    ret = avfilter_link(cropFilter_ctx, 0, vflipFilter_ctx, 0);
    if(ret != 0)
    {
    
    
        printf("avfilter_link() cropFilter -> vflipFilter failed!\n");
        return -1;
    }

    //vflipFilter -> overlayfilter[1]
    ret = avfilter_link(vflipFilter_ctx, 0, overlayFilter_ctx, 1);
    if(ret != 0)
    {
    
    
        printf("avfilter_link() vflipFilter -> overlayfilter[1] failed!\n");
        return -1;
    }

    //overlayfilter -> bufferSink
    ret = avfilter_link(overlayFilter_ctx, 0, bufferSink_ctx, 0);
    if(ret != 0)
    {
    
    
        printf("avfilter_link() overlayfilter -> bufferSink failed!\n");
        return -1;
    }

    //确认所有过滤器的连接
    ret = avfilter_graph_config(filter_grah, NULL);
    if(ret < 0)
    {
    
    
        printf("avfilter_graph_config() failed!\n");
        return -1;
    }

    //打印filtergraph的信息
    char* graph_str = avfilter_graph_dump(filter_grah, NULL);
    printf("\n%s\n", graph_str);
    av_free(graph_str);

    //输入帧
    AVFrame* frame_in = av_frame_alloc();
    unsigned char* frame_buffer_in = (unsigned char*)av_malloc(
                                        av_image_get_buffer_size(AV_PIX_FMT_YUV420P, in_width, in_height, 1));

    //输出帧
    AVFrame* frame_out = av_frame_alloc();

    frame_in->width = in_width;
    frame_in->height = in_height;
    frame_in->format = AV_PIX_FMT_YUV420P;

    uint32_t frame_size = in_width * in_height * 3 / 2;

    while (1)
    {
    
    
        //读取yuv数据
        if(fread(frame_buffer_in, 1, frame_size, infile) != frame_size)
        {
    
    
            break;
        }

        av_image_fill_arrays(frame_in->data, frame_in->linesize, frame_buffer_in, AV_PIX_FMT_YUV420P, in_width, in_height, 1);


        //添加帧数据到过滤器
        if(av_buffersrc_add_frame(bufferSrc_ctx, frame_in) < 0)
        {
    
    
            printf("av_buffersrc_add_frame() failed!\n");
            break;
        }


        //获取输出帧数据
        ret = av_buffersink_get_frame(bufferSink_ctx, frame_out);
        if(ret < 0)
        {
    
    
            printf("av_buffersink_get_frame() failed!\n");
            break;
        }


        //输出文件
        if(frame_out->format == AV_PIX_FMT_YUV420P)
        {
    
    
            for (int i = 0; i < frame_out->height; i++) {
    
    
                fwrite(frame_out->data[0] + frame_out->linesize[0] * i, 1, frame_out->width, outfile);
            }
            for (int i = 0; i < frame_out->height / 2; i++) {
    
    
                fwrite(frame_out->data[1] + frame_out->linesize[1] * i, 1, frame_out->width / 2, outfile);
            }
            for (int i = 0; i < frame_out->height / 2; i++) {
    
    
                fwrite(frame_out->data[2] + frame_out->linesize[2] * i, 1, frame_out->width / 2, outfile);
            }
        }

        av_frame_unref(frame_out);

    }

    fclose(infile);
    fclose(outfile);

    av_frame_free(&frame_in);
    av_frame_free(&frame_out);
    avfilter_graph_free(&filter_grah);
    printf("end video mark!\n");
    return 0;
}```

Supongo que te gusta

Origin blog.csdn.net/m0_37599645/article/details/112707925
Recomendado
Clasificación