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

进入代码目录,在命令行运行./vf_file ./ring.flv -vf crop=iw/2:ih,pad=iw*2:ih
滤镜选项-vf crop=iw/2:ih,pad=iw*2:ih表示先将视频裁剪为一半宽度,再填充为二倍宽度,预期结果为视频的右半部分为黑边。
测试文件下载:ring.flv
未经滤镜处理和经过滤镜处理的视频效果对比如下两图所示:

ring


4.3 示例3:测试图作输入源

示例3使用测试图(test pattern)作为滤镜的输入,测试图(test pattern)是由FFmpeg内部产生的测试图案,用于测试非常方便。
因测试图直接输出原始视频帧,不需解码器,因此示例3中用到AVFilter库,不需要用到AVFormat库。

4.3.1 代码

3.2节源码目录中vfilter_testsrc.c就是用于示例3的主程序,实现了构建测试源,滤镜处理,播放的主流程。除滤镜输入源的获取方式与示例2不同之外,其他过程并无不同。

示例3增加的关键内容是构造测试源,参考vfilter_testsrc.c中如下函数:

// @filter [i] 产生测试图案的filter // @vfmt [i] @filter的参数 // @fctx [o] 用户定义的数据类型,输出供调用者使用 static int open_testsrc(const char *filter, const input_vfmt_t *vfmt, filter_ctx_t *fctx) { int ret = 0; // 分配一个滤镜图filter_graph fctx->filter_graph = avfilter_graph_alloc(); if (!fctx->filter_graph) { return AVERROR(ENOMEM); } // source滤镜:合法值有"testsrc"http://www.likecs.com/"smptebars"http://www.likecs.com/"color"/... const AVFilter *bufsrc = avfilter_get_by_name(filter); // 为buffersrc滤镜创建滤镜实例buffersrc_ctx,命名为"in" // 将新创建的滤镜实例buffersrc_ctx添加到滤镜图filter_graph中 ret = avfilter_graph_create_filter(&fctx->bufsrc_ctx, bufsrc, "in", NULL, NULL, fctx->filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create filter testsrc\n"); goto end; } // "buffersink"滤镜:缓冲视频帧,作为滤镜图的输出 const AVFilter *bufsink = avfilter_get_by_name("buffersink"); /* buffer video sink: to terminate the filter chain. */ // 为buffersink滤镜创建滤镜实例buffersink_ctx,命名为"out" // 将新创建的滤镜实例buffersink_ctx添加到滤镜图filter_graph中 ret = avfilter_graph_create_filter(&fctx->bufsink_ctx, bufsink, "out", NULL, NULL, fctx->filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create filter buffersink\n"); goto end; } if ((ret = avfilter_link(fctx->bufsrc_ctx, 0, fctx->bufsink_ctx, 0)) < 0) { goto end; } // 验证有效性并配置filtergraph中所有连接和格式 ret = avfilter_graph_config(fctx->filter_graph, NULL); if (ret < 0) { goto end; } vfmt->pix_fmt = av_buffersink_get_format(fctx->bufsink_ctx); vfmt->width = av_buffersink_get_w(fctx->bufsink_ctx); vfmt->height = av_buffersink_get_h(fctx->bufsink_ctx); vfmt->sar = av_buffersink_get_sample_aspect_ratio(fctx->bufsink_ctx); vfmt->time_base = av_buffersink_get_time_base(fctx->bufsink_ctx); vfmt->frame_rate = av_buffersink_get_frame_rate(fctx->bufsink_ctx); av_log(NULL, AV_LOG_INFO, "probe video format: " "%dx%d, pix_fmt %d, SAR %d/%d, tb %d/%d, rate %d/%d\n", vfmt->width, vfmt->height, vfmt->pix_fmt, vfmt->sar.num, vfmt->sar.den, vfmt->time_base.num, vfmt->time_base.den, vfmt->frame_rate.num, vfmt->frame_rate.den); return 0; end: avfilter_graph_free(&fctx->filter_graph); return ret; }

测试源的本质是使用FFmpeg提供的用于产生测试图案的滤镜来生成视频数据。具体到代码实现层面,将testsrc/smptebars等滤镜代替常用的buffer滤镜作为源滤镜,然后直接与buffersink滤镜相连,以输出测试图案,如下图:

4.3.2 编译

进入代码目录,在命令行运行make vf_test,将生成vf_test可执行文件

4.3.3 测试

测试滤镜选项-vf transpose=cclock,pad=iw+80:ih:40,此滤镜选项表示先将视频逆时针旋转90度,然后将视频左右两边各增加40像素宽度的黑边

使用“testsrc”测试图作输入源
运行如下命令:

ffplay -f lavfi -i testsrc

无滤镜处理的效果如图所示:

testsrc

运行带滤镜选项的ffplay命令:

ffplay -f lavfi -i testsrc -vf transpose=cclock,pad=iw+80:ih:40

运行带滤镜选项的测试程序(效果等同于上述ffplay命令):

./vf_test testsrc -vf transpose=cclock,pad=iw+80:ih:40

经滤镜处理的效果如图所示:

使用“smptebars”测试图作输入源
运行如下命令:

ffplay -f lavfi -i smptebars

无滤镜处理的效果如图所示:

smptebars

运行带滤镜选项的ffplay命令:

ffplay -f lavfi -i smptebars -vf transpose=cclock,pad=iw+80:ih:40

运行带滤镜选项的测试程序(效果等同于上述ffplay命令):

./vf_test smptebars -vf transpose=cclock,pad=iw+80:ih:40

经滤镜处理的效果如图所示:

5. 遗留问题

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

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