FFmpeg之Filter FilterChain FilterGraph

基础

  1. filter: 数据处理器
  2. filter_chain: 链表链接链接所有的filter
  3. filter_graph:数据处理管理器
  4. 查看filter的相关事项:ffmpeg -h filter=filter_name
$ ffmpeg -h filter=crop
Filter crop
  Crop the input video.
    Inputs:
       #0: default (video)
    Outputs:
       #0: default (video)
crop AVOptions:
  out_w             <string>     ..FV..... set the width crop area expression (default "iw")
  w                 <string>     ..FV..... set the width crop area expression (default "iw")
  out_h             <string>     ..FV..... set the height crop area expression (default "ih")
  h                 <string>     ..FV..... set the height crop area expression (default "ih")
  x                 <string>     ..FV..... set the x crop area expression (default "(in_w-out_w)/2")
  y                 <string>     ..FV..... set the y crop area expression (default "(in_h-out_h)/2")
  keep_aspect       <boolean>    ..FV..... keep aspect ratio (default false)
  exact             <boolean>    ..FV..... do exact cropping (default false)

初始化过滤器

创建graph

    //avfilter_register_all();  // 4.0后被删除,同avdevice_regeister_all
    AVFilterGraph *filter_graph = avfilter_graph_alloc();
    if (!filter_graph) {
        printf("failed to create filter graph\n");
        return -1;
    }

创建chain

编码创建

创建输入buffer

    char args[512];
    memset(args, 0, 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);
    AVFilter *buffser_src =
        avfilter_get_by_name("buffer");  // AVFilterGraph的输入源
    AVFilterContext *buffer_src_ctx;
    ret = avfilter_graph_create_filter(
        &buffer_src_ctx, buffser_src, "in", args, NULL, filter_graph);
    if (ret < 0) {
        printf("failed to create filter buffersrc\n");
        return -1;
    }

输出buffersink

    // sink filter
    AVBufferSinkParams *buffer_sink_paras;
    AVFilterContext    *buffer_sink_ctx;
    AVFilter           *buffer_sink = avfilter_get_by_name("buffersink");
    enum AVPixelFormat  pix_fmts[]  = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };
    buffer_sink_paras               = av_buffersink_params_alloc();
    buffer_sink_paras->pixel_fmts   = pix_fmts;
    ret = avfilter_graph_create_filter(&buffer_sink_ctx,
                                       buffer_sink,
                                       "out",
                                       NULL,
                                       buffer_sink_paras,
                                       filter_graph);
    if (ret < 0) {
        printf("failed to create split filter\n");
        return -1;
    }

个人需要使用的filter

    // split fitler
    AVFilter        *split_filter = avfilter_get_by_name("split");
    AVFilterContext *split_filter_ctx;
    ret = avfilter_graph_create_filter(&split_filter_ctx,
                                       split_filter,
                                       "split",
                                       "outputs=2",
                                       NULL,
                                       filter_graph);
    if (ret < 0) {
        printf("failed to create split filter\n");
        return -1;
    }

    // crop filter
    AVFilter        *crop_filter = avfilter_get_by_name("crop");
    AVFilterContext *crop_filter_ctx;
    ret = avfilter_graph_create_filter(&crop_filter_ctx,
                                       crop_filter,
                                       "crop",
                                       "out_w=iw:out_h=ih/2:x=0:y=0",
                                       NULL,
                                       filter_graph);
    if (ret < 0) {
        printf("failed to create crop filter\n");
        return -1;
    }

    // vflip filter
    AVFilter        *vflip_filter = avfilter_get_by_name("vflip");
    AVFilterContext *vflip_filter_ctx;
    ret = avfilter_graph_create_filter(
        &vflip_filter_ctx, vflip_filter, "vflip", NULL, NULL, filter_graph);
    if (ret < 0) {
        printf("failed to create vflip filter\n");
        return -1;
    }

    // overlap filter
    AVFilter        *overlay_filter = avfilter_get_by_name("overlay");
    AVFilterContext *overlay_filter_ctx;
    ret = avfilter_graph_create_filter(&overlay_filter_ctx,
                                       overlay_filter,
                                       "overlay",
                                       "y=0:H/2",
                                       NULL,
                                       filter_graph);
    if (ret < 0) {
        printf("failed to create overlay filter\n");
        return -1;
    }

link需要的filters

    // src filter to split filter
    ret = avfilter_link(buffer_src_ctx, 0, split_filter_ctx, 0);
    if (ret != 0) {
        printf("failed to link src filter and split filter\n");
        return -1;
    }
    // split filter's first pad to overlay fiilter's main pad
    ret = avfilter_link(split_filter_ctx, 0, overlay_filter_ctx, 0);
    if (ret != 0) {
        printf("failed to link split filter's first pad and overlay filter\n");
        return -1;
    }
    // split fitler's second pad to crop filter
    ret = avfilter_link(split_filter_ctx, 1, crop_filter_ctx, 0);
    if (ret != 0) {
        printf("failed to link split filter's second pad and crop filter\n");
        return -1;
    }
    // crop filter to vflip filter
    ret = avfilter_link(crop_filter_ctx, 0, vflip_filter_ctx, 0);
    if (ret != 0) {
        printf("failed to link crop filter and vflip filter\n");
        return -1;
    }
    // vflip filter to overlay filtes'second pad
    ret = avfilter_link(vflip_filter_ctx, 0, overlay_filter_ctx, 1);
    if (ret != 0) {
        printf("failed to link vflip filter and overlay's second filter\n");
        return -1;
    }
    // overlay filter to sink filter
    ret = avfilter_link(overlay_filter_ctx, 0, buffer_sink_ctx, 0);
    if (ret != 0) {
        printf("failed to link overlay filter and sink filter\n");
        return -1;
    }

初始化graph

    // check filter graph
    ret = avfilter_graph_config(filter_graph, NULL);
    if (ret < 0) {
        printf("failed in filter graph\n");
        return -1;
    }

命令创建

初始化命令行

    char           filter_args[1024] = { 0 };
    snprintf(
        filter_args,
        sizeof(filter_args),
        "buffer=video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d[v0];"  // Parsed_buffer_0
        "[v0]split[main][tmp];"               // Parsed_split_1
        "[tmp]crop=iw:ih/2:0:0,vflip[flip];"  // Parsed_crop_2 Parsed_vflip_3
        "[main][flip]overlay=0:H/2[result];"  // Parsed_overlay_4
        "[result]buffersink",                 // Parsed_buffersink_5
        width,
        height,
        format,
        1,
        25,
        1,
        1);

利用命令行初始化graph

    AVFilterInOut *inputs            = NULL;
    AVFilterInOut *outputs           = NULL;
    int ret = avfilter_graph_parse2(filter_graph, filter_args, &inputs, &outputs);
    if (ret < 0) {
        printf("cannot parse graph\n");
        return ret;
    }
    ret = avfilter_graph_config(filter_graph, NULL);
    if (ret < 0) {
        printf("cannot config graph\n");
        return ret;
    }

获取输入buffer和输出buffersink

    mainsrc_ctx = avfilter_graph_get_filter(filter_graph, "Parsed_buffer_0");
    if (!mainsrc_ctx) {
        printf("avfilter_graph_get_filter Parsed_buffer_0 failed\n");
        return -1;
    }
    resultsink_ctx =
        avfilter_graph_get_filter(filter_graph, "Parsed_buffersink_5");
    if (!resultsink_ctx) {
        printf("avfilter_graph_get_filter Parsed_buffer_5 failed\n");
        return -1;
    }

处理数据

向buffer中添加数据

        if (av_buffersrc_add_frame(mainsrc_ctx, frame_in) < 0) {
            printf("error while add frame\n");
            break;
        }

从buffersink中获取数据

        ret = av_buffersink_get_frame(resultsink_ctx, frame_out);
        if (ret < 0)
            break;

其他业务

        // output Y U V
        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);
        }
posted @ 2023-03-17 11:35  flxx  阅读(166)  评论(0编辑  收藏  举报