ffmpegのフィルターを使用して、分割フィルター(シャント)、トリミングフィルター(トリミング)、vflipフィルター(垂直上向きフリップ)、オーバーレイフィルター(合成)などのyuvデータを処理します。

ffmpegのフィルターを使用して、分割フィルター(シャント)、トリミングフィルター(トリミング)、vflipフィルター(垂直上向きフリップ)、オーバーレイフィルター(合成)などのyuvデータを処理します。

#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;
}```

おすすめ

転載: blog.csdn.net/m0_37599645/article/details/112707925