FFMPEG中的filter使用二

news2024/10/6 20:38:36

上一篇我们在使用滤镜时是手动创建各种滤镜,然后根据处理链路手动链接不同的过滤器,有助于我们理解滤镜的流程。这一篇我们使用参数形式,让ffmpeg自动帮我们创建和链接过滤器,这样可以减少代码量,同时我们可以先使用参数测试后,直接将参数复制到代码中使用。

准备

ffmeg 4.4

一个MP4或flv格式视频文件

处理流程

这里我们需要说明下:

首先我们需要理解filtergraph语法,每个过滤器至少有一个输入和输出,对于多个输入和输出的过滤器如何指定那个输入和输出与其他过滤器进行链接呢,所以需要指定标签,如下面的命令

[in]scale=iw/2:ih/2[in_tmp];[in_tmp]split=2[in_1][in_2];[in_1]pad=iw*2:ih*2:color=yellow[a];[a][in_2]overlay=w[out]

上面的split的滤镜将输入的视频帧复制为2个输出并指定名称为[in_1]和[in_2],[in_2]作为overlay滤镜的第二个输入,[in_1]经过pad滤镜处理后作为overlay的第一个输入。

而[in]和[out]这两个名称是系统默认的。也可自行修改。

好了我们来看上面的流程图。

/*
    和 avfilter_graph_parse 类似。不同的是 inputs 和 outputs 参数,即做输入参数,也做输出参数。
        在函数返回时,它们将会保存 graph 中所有的处于 open 状态的 pad。返回的 inout 应该使用 avfilter_inout_free() 释放掉。
    
    注意:在字符串描述的 graph 中,第一个 filter 的输入如果没有被一个字符串标识,默认其标识为"in",最后一个 filter 的输出如果没有被标识,默认为"output"。
    
    intpus:作为输入参数是,用于保存已经存在的graph的open inputs,可以为NULL。
        作为输出参数,用于保存这个parse函数之后,仍然处于open的inputs,当然如果传入为NULL,则并不输出。
    outputs:同上。
*/
int avfilter_graph_parse_ptr(AVFilterGraph *graph, const char *filters,
                             AVFilterInOut **inputs, AVFilterInOut **outputs, void *log_ctx);

方法 avfilter_graph_parse_ptr解析filters字符串中滤镜,创建滤镜并将滤镜链接起来。里面用到了2个AVFilterInOut结构。如下:

    AVFilterInOut* outputs = avfilter_inout_alloc();
    AVFilterInOut* inputs = avfilter_inout_alloc();    

    outputs->name = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx = 0;
    outputs->next = NULL;

    inputs->name = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;

outputs,inputs分别指定一个滤镜的上下文和引脚名称。这里其实就时buffer和buffersink.

然后avfilter_graph_parse_ptr 方法会将字符串的中滤镜输入引脚为in的滤镜与outputs链接,输出引脚为out的滤镜与inputs链接。这样就把buffer和buffersink滤镜加入到了整个滤镜链路中了,形成了完整的滤镜链路。

我们在创建buffer和buffersink时,分别命令了buffer的输出名称为in,buffersink的输入名称为out

这里我们看面的参数[in]............[out],其实就是为了将他们使用对应的名称链接起来。

   
const char* filter_descr = "[in]scale=iw/2:ih/2[in_tmp];[in_tmp]split=2[in_1][in_2];[in_1]pad=iw*2:ih*2:color=yellow[a];[a][in_2]overlay=w[out]";

 char args[512];
    int ret = 0;
    const AVFilter* buffersrc = avfilter_get_by_name("buffer");//预缓存帧数据。用于输入
    const AVFilter* buffersink = avfilter_get_by_name("buffersink");//缓冲视频帧,并使它们可用于过滤器图形的末尾。用于输出
    AVFilterInOut* outputs = avfilter_inout_alloc();
    AVFilterInOut* inputs = avfilter_inout_alloc();
    AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base;
    enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE };//注意输入的格式类型pix_fmts[0]

    filter_graph = avfilter_graph_alloc();
    if (!outputs || !inputs || !filter_graph) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    /* buffer video source: the decoded frames from the decoder will be inserted here. */
    snprintf(args, sizeof(args),
        "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
        dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
        time_base.num, time_base.den,
        dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den);

    //创建和初始化过滤器实例并将其添加到现有图形中。【输入】
    ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in",
        args, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n");
        goto end;
    }

    //创建和初始化过滤器实例并将其添加到现有图形中。【输出】
    /* buffer video sink: to terminate the filter chain. */
    ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out",
        NULL, NULL, filter_graph);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n");
        goto end;
    }

    //给buffersink_ctx设置参数
    ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts,
        AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n");
        goto end;
    }

    /*
     * Set the endpoints for the filter graph. The filter_graph will
     * be linked to the graph described by filters_descr.
     */

  
    outputs->name = av_strdup("in");
    outputs->filter_ctx = buffersrc_ctx;
    outputs->pad_idx = 0;
    outputs->next = NULL;


    inputs->name = av_strdup("out");
    inputs->filter_ctx = buffersink_ctx;
    inputs->pad_idx = 0;
    inputs->next = NULL;

    //将字符串描述的图形添加到图形中。
    if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL)) < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "Error avfilter_graph_parse_ptr\n");
        goto end;
    }

    //检查AVFilterGraph有效性
    if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) {
        av_log(NULL, AV_LOG_ERROR, "Error avfilter_graph_config\n");
        goto end;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/477007.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学系统集成项目管理工程师(中项)系列15_质量管理

1. 质量&#xff08;Quality&#xff09;的定义 1.1. 反应实体满足主体明确和隐含需求的能力的特性总和 1.2. 明确需求是指在标准、规范、图样、技术要求、合同和其他文件中用户明确提出的要求与需要 1.3. 隐含需求是指用户和社会通过市场调研对实体的期望以及公认的、不必明…

thinkphp路由,请求和响应

文章目录 定义获取路由后面的参数跨域请求请求响应 定义 thinkphp定义路由一般在route路由下的app.php中 下面这是一个简单的路由 Route::rule(admin/login,/app/controller/Admin/login)->middleware(\app\middleware\MyMiddleware::class);该路由表示当访问admin/login时…

人工智能课程笔记(7)强化学习(基本概念 Q学习 深度强化学习 附有大量例题)

文章目录 1.强化学习与深度学习的区别2.强化学习中的基本概念3.强化学习、有监督学习和无监督学习的区别4.强化学习的特点5.离散马尔可夫过程6.马尔可夫奖励过程7.马尔可夫决策过程8.策略学习8.1.策略学习概念8.2.策略评估与贝尔曼方程 9.强化学习的最优策略求解10.基于价值的强…

K8s基础1——发展起源、资源对象、集群架构

文章目录 一、发展起源二、资源对象2.1 集群类2.2 应用类2.3 存储类2.4 安全类 三、集群架构 一、发展起源 K8s官方文档 K8s怎么来的&#xff1f; 十几年来&#xff0c;谷歌内部使用的大规模集群管理系统是Brog&#xff0c;基于容器技术实现了资源管理的自动化和跨多个数据中心…

基于Python的连锁超市收银系统的开发与研究_kaic

基于Python的连锁超市收银系统的开发与研究 摘要&#xff1a;近几年来&#xff0c;国内的连锁超市收银系统也在不断的发展与完善&#xff0c;超市收银系统是一个超市管理的核心&#xff0c;他决定了超市的安全性。目前&#xff0c;大大小小的超市基本上由传统的人工管理逐渐过渡…

IT 面试手册 - 序

IT 面试手册 - 序 前言 首先&#xff0c;感谢你阅读我的文章。作为在计算机互联网行业摸爬滚打近十载的半个过来人&#xff0c;在这里分享一些关于求职面试和自我提升的心得感悟&#xff0c;希望能够给你一些启发。 背景 对于 IT 从业者来说&#xff0c;当今这个时代&#x…

Docker的四种网络模式

1.Host 模式 通常来讲&#xff0c;启动新的Docker容器&#xff0c;都会分配独立的Network Namespace隔离子系统&#xff0c;如果在运行是指定为host模式&#xff0c;那么Docker容器将不会获得一个独立的Network Namespace&#xff0c;而是和宿主机共用一个Network Namespace子…

计算机网络知识复习

目录 TCP/IP协议群做了哪些事情&#xff1f; TCP协议为什么是3次握手&#xff0c;4次挥手&#xff1f; 如果网络延迟是30ms&#xff0c;那么Ping(基于UDP的)一个网站需要多少ms&#xff1f; 如果请求一个HTTP协议的网站&#xff0c;TTFB至少ms&#xff1f; CDN更换图片&am…

WeakMap 与 WeakSet

WeakSet WeakSet 结构与 Set 类似&#xff0c;也是不重复的值的集合。 成员都是数组和类似数组的对象&#xff0c;WeakSet 的成员只能是对象&#xff0c;而不能是其他类型的值。 若调用 add() 方法时传入了非数组和类似数组的对象的参数&#xff0c;就会抛出错误。 const b …

Linux进程间通信 - 信号(signal) 与 管道(pipe) 与 消息队列

什么是进程间通信&#xff0c;就是进程与进程之间进行通信&#xff0c;互相发送消息&#xff1b;可以通过 信号 或者 管道 或者 消息队列 或者 信号量 去通信&#xff01; 目录 一、信号 1. 信号简介 2. 都有那些信号&#xff1f; 3. 注册信号的函数 1). signal 2). sig…

十一、通过六个因素对织物起球等级进行预测

一、需求分析 根据之前做训练的模型&#xff0c;对不同等级的标准样卡进行测试 测试样本有48张&#xff0c;其中包括起球个数、起球总面积、起球最大面积、起球平均面积、对比度、光学体积六个指标&#xff0c;最终确定出织物的等级 数据集fiber.csv大致结构如下&#xff1a; …

微服务保护 笔记分享【黑马笔记】

微服务保护 1.初识Sentinel 1.1.雪崩问题及解决方案 1.1.1.雪崩问题 微服务中&#xff0c;服务间调用关系错综复杂&#xff0c;一个微服务往往依赖于多个其它微服务。 如图&#xff0c;如果服务提供者I发生了故障&#xff0c;当前的应用的部分业务因为依赖于服务I&#xff…

Notion——构建个人知识库

前言 使用Notion快三年了&#xff0c;它All in one的理念在使用以后确实深有体会&#xff0c;一直想找一个契机将这个软件分享给大家&#xff0c;这款笔记软件在网上已经有很多的教程了&#xff0c;所以在这里我主要想分享框架这方面给大家&#xff0c;特别对于学生党、准研究生…

【Java笔试强训 12】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;二进制插…

深圳雷龙SD NAND的存储应用方案

前言: 很感谢深圳雷龙发展有限公司为博主提供的两片SD NAND的存储芯片&#xff0c;在这里博主记录一下自己的使用过程以及部分设计。 深入了解该产品&#xff1a; 拿到这个产品之后&#xff0c;我大致了解了下两款芯片的性能。CSNP4GCR01-AMW是一种基于NAND闪存和SD控制器的4G…

paddle 52 在paddleseg中实现cutmix数据增强方式

CutMix是一种极其有效的数据增强方式,尤其是在遥感影像语义分割中。这主要是因为遥感影像标注成本较大,在实际业务中通常都是采用局部标注的方式进行标注,如下图所示仅对标注成本较小的区域进行标注,而对标注成本较大的地方进行忽略。这使得标签数据中各种类别边界较少(例…

【Python零基础学习入门篇③】——第三节:Python的字符串类型

⬇️⬇️⬇️⬇️⬇️⬇️ ⭐⭐⭐Hello&#xff0c;大家好呀我是陈童学哦&#xff0c;一个普通大一在校生&#xff0c;请大家多多关照呀嘿嘿&#x1f601;&#x1f60a;&#x1f618; &#x1f31f;&#x1f31f;&#x1f31f;技术这条路固然很艰辛&#xff0c;但既已选择&…

VS+Qt+C++银行排队叫号系统

程序示例精选 VSQtC银行排队叫号系统 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<VSQtC银行排队叫号系统>>编写代码&#xff0c;带用户登录&#xff0c;管理员登录&#xff…

Mysql当中Json相关的函数详解

目录 一、前言二、创建JSON文本的函数2.1.JSON_ARRAY&#xff08;转换json数组&#xff09;2.2.JSON_OBJECT&#xff08;转换json对象&#xff09;2.3.JSON_QUOTE&#xff08;转义字符串&#xff09; 三、搜索JSON文本的函数3.1.JSON_CONTAINS&#xff08;json当中是否包含指定…

thinkphp6结合layui增删改查综合案列

文章目录 技术栈实现代码实现数据库 本案例适合新手&#xff0c;特别是杠刚入门thinkphp和layui&#xff0c;但又不是特别熟悉这类 主要实现登录退出功能&#xff0c;用户模块的增删改查功能&#xff0c;分页功能是layui表单自带功能 效果图 左侧的菜单栏我没有写对应的页面&am…