FFmpeg滤镜API用法与实例解析 (5)

buffer滤镜用作滤镜链的输入节点。buffer滤镜缓冲视频帧,滤镜链可以从buffer滤镜中取得视频帧数据。
在上述帮助信息中,Inputs和Outputs指滤镜的输入引脚和输出引脚。buffer滤镜是滤镜链中的第一个滤镜,因此只有输出引脚而无输入引脚。

滤镜(AVFilter)需要通过滤镜实例(AVFilterContext)引用,为buffer滤镜创建的滤镜实例是fctx->bufsrc_ctx,用户通过往fctx->bufsrc_ctx填入视频帧来为滤镜链提供输入。
为buffer滤镜创建滤镜实例时需要提供参数,buffer滤镜需要的参数在帮助信息中的“buffer AVOptions”部分列出,由vfmt输入参数提供,代码如下:

char args[512]; char *p_args = NULL; if (vfmt != NULL) { // args是buffersrc滤镜的参数 snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", vfmt->width, vfmt->height, vfmt->pix_fmt, vfmt->time_base.num, vfmt->time_base.den, vfmt->sar.num, vfmt->sar.den); p_args = args; } // buffer滤镜:缓冲视频帧,作为滤镜图的输入 const AVFilter *bufsrc = avfilter_get_by_name("buffer"); // 为buffersrc滤镜创建滤镜实例buffersrc_ctx,命名为"in" // 将新创建的滤镜实例buffersrc_ctx添加到滤镜图filter_graph中 ret = avfilter_graph_create_filter(&fctx->bufsrc_ctx, bufsrc, "in", p_args, NULL, fctx->filter_graph);

buffersink滤镜
在命令行中输入ffmpeg -h filter=buffersink查看buffersink滤镜的帮助信息,如下:

$ ffmpeg -h filter=buffersink ffmpeg version 4.1 Copyright (c) 2000-2018 the FFmpeg developers Filter buffersink Buffer video frames, and make them available to the end of the filter graph. Inputs: #0: default (video) Outputs: none (sink filter) buffersink AVOptions: pix_fmts <binary> ..FV..... set the supported pixel formats

buffersink滤镜用作滤镜链的输出节点。滤镜链处理后的视频帧可以缓存到buffersink滤镜中。
buffersink滤镜是滤镜链中的最后一个滤镜,因此只有输入引脚而无输出引脚。

为buffersink滤镜创建的滤镜实例是fctx->bufsink_ctx,用户可以从fctx->bufsink_ctx中读视频帧来获得滤镜链的输出。
通过帮助信息可以看到,buffersink滤镜参数只有一个“pix_fmt”,用于设置滤镜链输出帧的像素格式列表,这个像素格式有多种,以限制输出帧格式不超过指定的范围。

// buffersink滤镜:缓冲视频帧,作为滤镜图的输出 const AVFilter *bufsink = avfilter_get_by_name("buffersink"); // 为buffersink滤镜创建滤镜实例buffersink_ctx,命名为"out" // 将新创建的滤镜实例buffersink_ctx添加到滤镜图filter_graph中 ret = avfilter_graph_create_filter(&fctx->bufsink_ctx, bufsink, "out", NULL, NULL, fctx->filter_graph); #if 0 // 因为后面显示视频帧时有sws_scale()进行图像格式转换,故此处不设置滤镜输出格式也可 enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE }; // 设置输出像素格式为pix_fmts[]中指定的格式(如果要用SDL显示,则这些格式应是SDL支持格式) ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); #endif

将buffer滤镜和buffsink滤镜添加进滤镜图中后,如下图所示:

3.1.2 将filters_descr描述的滤镜插入滤镜图中

解析滤镜选项(filters_descr),将解析得到的滤镜插入第1步构造的滤镜图中,并与滤镜图输入端和输出端连接起来

// 设置滤镜图的端点,将filters_descr描述的滤镜图连接到此滤镜图 // 两个滤镜图的连接是通过端点(AVFilterInOut)连接完成的 // 端点数据结构AVFilterInOut主要用于avfilter_graph_parse()系列函数 // outputs变量意指buffersrc_ctx滤镜的输出引脚(output pad) // src缓冲区(buffersrc_ctx滤镜)的输出必须连到filters_descr中第一个 // 滤镜的输入;filters_descr中第一个滤镜的输入标号未指定,故默认为 // "in",此处将buffersrc_ctx的输出标号也设为"in",就实现了同标号相连 AVFilterInOut *outputs = avfilter_inout_alloc(); outputs->name = av_strdup("in"); outputs->filter_ctx = fctx->bufsrc_ctx; outputs->pad_idx = 0; outputs->next = NULL; // inputs变量意指buffersink_ctx滤镜的输入引脚(input pad) // sink缓冲区(buffersink_ctx滤镜)的输入必须连到filters_descr中最后 // 一个滤镜的输出;filters_descr中最后一个滤镜的输出标号未指定,故 // 默认为"out",此处将buffersink_ctx的输出标号也设为"out",就实现了 // 同标号相连 AVFilterInOut *inputs = avfilter_inout_alloc(); inputs->name = av_strdup("out"); inputs->filter_ctx = fctx->bufsink_ctx; inputs->pad_idx = 0; inputs->next = NULL; // 将filters_descr描述的滤镜图添加到filter_graph滤镜图中 // 调用前:filter_graph包含两个滤镜buffersrc_ctx和buffersink_ctx // 调用后:filters_descr描述的滤镜图插入到filter_graph中,buffersrc_ctx连接到filters_descr // 的输入,filters_descr的输出连接到buffersink_ctx,filters_descr只进行了解析而不 // 建立内部滤镜间的连接。filters_desc与filter_graph间的连接是利用AVFilterInOut inputs // 和AVFilterInOut outputs连接起来的,AVFilterInOut是一个链表,最终可用的连在一起的 // 滤镜链/滤镜图就是通过这个链表串在一起的。 ret = avfilter_graph_parse_ptr(fctx->filter_graph, filters_descr, &inputs, &outputs, NULL);

filters_descr描述的滤镜如下图所示:

pic1

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzpdg.html