音视频基础 (九)---FFmpeg过滤器框架

news/2024/7/26 11:12:33/文章来源:https://blog.csdn.net/weixin_45673259/article/details/136995392

ffmpeg的filter⽤起来是和Gstreamer的plugin是⼀样的概念,通过avfilter_link,将各个创建好的filter按
⾃⼰想要的次序链接到⼀起,然后avfilter_graph_config之后,就可以正常使⽤。
⽐较常⽤的滤镜有:scale、trim、overlay、rotate、movie、yadif。scale 滤镜⽤于缩放,trim 滤镜⽤
于帧级剪切,overlay 滤镜⽤于视频叠加,rotate 滤镜实现旋转,movie 滤镜可以加载第三⽅的视频,
yadif 滤镜可以去隔⾏

1、主要结构体和API介绍

1.1 AVFilterGraph-对filters系统的整体管理

AVFilterGraph是FFmpeg中用于管理音视频滤镜的数据结构。它表示一个完整的滤镜图,可以包含多个输入输出,并通过连接不同的滤镜节点来实现各种音视频处理操作。

AVFilterGraph提供了创建、配置和管理滤镜的接口,允许用户构建复杂的滤镜拓扑结构,以实现音视频的处理和编辑。通AVFilterGraph,用户可以添加各种滤镜(如变换、剪切、合并、调节等)并将它们连接起来,最终实现所需的音视频处理效果。

在使用AVFilterGraph时,通常的流程包括创建滤镜图、添加输入输出流、添加滤镜节点、连接滤镜节点、设置参数等。一旦完成了滤镜图的构建,就可以将音视频帧送入滤镜图进行处理,最终得到处理后的输出。
**重点
struct AVFilterGraph
{
AVFilterContext filters;
unsigned nb_filters;
}

1.2 AVFilter-定义filter本身的能⼒

AVFilter 是 FFmpeg 中用于实现音视频滤镜的基本单位。它代表了一个特定的音视频处理功能,比如色彩转换、尺寸调整、去噪等。AVFilter 可以单独使用,也可以通过 AVFilterGraph 组合成复杂的滤镜链。
AVFilter 结构的作用主要是定义了一个滤镜的基本属性和行为,以及提供了滤镜初始化、销毁、格式查询等相关的回调函数接口。通过这些接口,用户可以对滤镜进行初始化配置,并将其应用到音视频流数据上,实现各种音视频处理效果。

在使用 AVFilter 时,通常的步骤包括:

  • 创建 AVFilterContext 对象,表示一个具体的 AVFilter 实例。
  • 设置滤镜参数和选项,可以通过 priv_class定义的私有类进行配置。
  • 连接输入输出端口,将 AVFilterContext 对象连接到其他滤镜或音视频流中。
  • 将音视频帧数据送入滤镜进行处理,得到处理后的输出数据。

重点
**const char *name; // overlay
const AVFilterPad inputs;
const AVFilterPad outputs;

typedef struct AVFilter {const char *name;			//滤镜的名称,用于唯一标识滤镜。const char *description;	//对滤镜功能的文字描述。const AVFilterPad *inputs;	//const AVFilterPad *outputs;const AVClass *priv_class; //用于指定滤镜的私有类,定义了滤镜的参数和选项。int flags;int (*preinit)(AVFilterContext *ctx);int (*init)(AVFilterContext *ctx);	//用于初始化滤镜的回调函数,可以在滤镜被创建时执行一些初始化操作。int (*init_dict)(AVFilterContext *ctx, AVDictionary **options);void (*uninit)(AVFilterContext *ctx);	//用于销毁滤镜的回调函数,在滤镜不再需要时执行清理操作。int (*query_formats)(AVFilterContext *);	//用于查询支持的输入输出格式的回调函数。int priv_size;      //滤镜私有数据的大小,用于分配存储私有数据的内存空间。int flags_internal; ///< Additional flags for avfilter internal use only.struct AVFilter *next;int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags);int (*init_opaque)(AVFilterContext *ctx, void *opaque);int (*activate)(AVFilterContext *ctx);
} AVFilter;

1.3 AVFilterContext-filter实例,管理filter与外部的联系

AVFilterContext 是 FFmpeg 中用于表示一个特定 AVFilter 实例的数据结构。它包含了一个 AVFilter 的所有信息和状态,以便在音视频处理中对该滤镜进行配置、连接和处理。
AVFilterContext 结构的作用是管理一个 AVFilter 实例的输入输出端口,通过输入端口接收数据并经过滤镜处理后输出到输出端口。它还负责与滤镜图(AVFilterGraph)进行交互,将滤镜上下文与其他滤镜连接起来以实现复杂的音视频处理链。

在使用 AVFilterContext 时,通常的步骤包括:

  • 创建 AVFilterContext 对象,可以通过 avfilter_alloc_context() 函数创建。
  • 配置 AVFilterContext 的输入输出端口,可以通过 avfilter_link() 函数连接输入输出端口。
  • 设置滤镜参数和选项,可以通过 AVFilterContext 的属性进行配置。
  • 将音视频帧数据送入 AVFilterContext 进行处理,得到处理后的输出数据。

**重点
struct AVFilterContext
{
const AVFilter *filter;
char *name;
AVFilterPad *input_pads;
AVFilterLink **inputs;
unsigned nb_inputs
AVFilterPad *output_pads;
AVFilterLink *outputs;
unsigned nb_outputs;
struct AVFilterGraph graph; // 从属于哪个AVFilterGraph
}

1.4 AVFilterLink-定义两个filters之间的联接

AVFilterLink用于连接滤镜图中两个滤镜之间的输入和输出。它包含了连接两个滤镜所需的所有信息,例如输入和输出的样本格式、缓冲区、时间戳等等。AVFilterLink还包含了有关滤镜链中帧的信息,如PTS(Presentation Time Stamp,显示时间戳)和DTS(Decoding Time Stamp,解码时间戳)。通过AVFilterLink,不同的滤镜可以在滤镜图中相互连接,从而实现视频和音频处理的各种功能。

**重点
struct AVFilterLink
{
AVFilterContext *src;
AVFilterPad *srcpad;
AVFilterContext *dst;
AVFilterPad dstpad;
struct AVFilterGraph graph;
}

1.5 AVFilterPad-定义filter的输⼊/输出接⼝

AVFilterPad是FFmpeg中的结构,用于描述滤镜的输入或输出端口。滤镜可以有多个输入和输出端口,每个端口都由一个AVFilterPad结构表示。该结构包含了端口的名称、类型(输入或输出)、滤镜所支持的样本格式、是否支持多通道等信息。
在滤镜图中,滤镜之间的连接通过连接它们的输入和输出端口来实现。因此,AVFilterPad在滤镜之间建立连接时起到了关键的作用。通过AVFilterPad,FFmpeg能够正确地识别滤镜之间的连接,从而实现音视频数据的流动和处理。
**重点
struct AVFilterPad
{
const char *name;
AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h);
AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples);
int (*filter_frame)(AVFilterLink *link, AVFrame *frame);
int (request_frame)(AVFilterLink link);
}

1.6AVFilterInOut-过滤器链输⼊/输出的链接列表

在AVFilter模块中定义了AVFilter结构,很个AVFilter都是具有独⽴功能的节点,如scale filter的作⽤就是进⾏图像尺⼨变换,overlay filter的作⽤就是进⾏图像的叠加。
这⾥需要重点提的是两个特别的filter,⼀个是buffer,⼀个是buffersink,

  • 滤波器buffer代表filter graph中的源头,原始数据就往这个filter节点输⼊的;
  • ⽽滤波器buffersink代表filter graph中的输出节点,处理完成的数据从这个filter节点输出。
typedef struct AVFilterInOut {/** unique name for this input/output in the list */char *name;/** filter context associated to this input/output */AVFilterContext *filter_ctx;/** index of the filt_ctx pad to use for linking */int pad_idx;/** next input/input in the list, NULL if this is the last */struct AVFilterInOut *next;
} AVFilterInOut;

2、函数使用

2.1 获取指定名称的滤镜–avfilter_get_by_name

// 获取FFmpeg中定义的filter,调⽤该⽅法前需要先调⽤avfilter_register_all();进⾏滤波器注册
AVFilter avfilter_get_by_name(const char name);
如果找到了指定名称的滤镜,该函数将返回一个指向对应AVFilter结构体的指针。如果未找到匹配的滤镜,函数将返回NULL。

2.2 向FFmpeg中的缓冲源滤镜(Buffer Source Filter)添加视频帧或音频帧–av_buffersrc_add_frame

/**参数ctx是指向Buffer Source Filter的AVFilterContext结构体指针,通过它可以访问和控制Buffer Source Filter的属性和状态。*参数frame是要添加到Buffer Source Filter中的AVFrame结构体指针,它包含了要添加的视频帧或音频帧的数据和相关信息。*函数返回一个整数值,表示操作是否成功。如果成功添加帧数据,则返回0;如果发生错    误,则返回负值。*/
int av_buffersrc_add_frame(AVFilterContext ctx, AVFrame frame);

通过调用av_buffersrc_add_frame函数,你可以将视频帧或音频帧添加到Buffer Source Filter中,从而使得该帧数据成为滤镜链的输入。

2.3 从缓冲汇滤镜(Buffer Sink Filter)中获取输出帧数据–

av_buffersink_get_frame

/* *参数 ctx 是指向 Buffer Sink Filter 的 AVFilterContext 结构体指针,通过它可以访问和控制 Buffer Sink Filter 的属性和状态。*函数返回一个指向 AVFrame 结构体的指针,该结构体包含了从 Buffer Sink Filter 中获取的输出帧数据。如果没有可用的输出帧数据,函数将返回 NULL。*/
int av_buffersink_get_frame(AVFilterContext ctx, AVFrame frame);

2.4 分配并初始化一个空的滤镜图–avfilter_graph_alloc

//分配并初始化一个空的滤镜图`在这里插入代码片`
AVFilterGraph *avfilter_graph_alloc(void);

在使用滤镜图进行音视频处理时,首先需要通过 avfilter_graph_alloc 分配一个滤镜图,然后在该滤镜图上添加各种滤镜节点,构建滤镜链,最后配置和链接这些滤镜节点,从而完成音视频处理任务。

2.5 在滤镜图中创建一个新的滤镜–avfilter_graph_create_filter

/* * filt_ctx: 指向指针的指针,用于返回创建的滤镜实例的 AVFilterContext 结构体指针。* filt: 要创建的滤镜的 AVFilter 结构体指针。* name: 滤镜实例的名称。* args: 滤镜实例的参数,可以是滤镜实例初始化时需要的参数字符串。* opaque: 不透明指针,可以传递给滤镜的初始化函数。* graph_ctx: 滤镜图的上下文 AVFilterGraph 结构体指针,表示滤镜实例将要被添加到的滤镜图。* 该函数返回一个整数值,表示操作是否成功。如果成功创建滤镜实例并将其添加到滤镜图中,则返回0;如果发生错误,则返回负值。*/
int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt,const char name, const char args, void *opaque,AVFilterGraph *graph_ctx);

avfilter_graph_create_filter函数用于在滤镜图中创建一个新的滤镜实例,并将其添加到滤镜链中。通过调用 avfilter_graph_create_filter 函数,可以在滤镜图中创建一个指定类型的滤镜实例,并配置其参数。

2.6 在滤镜图中连接两个滤镜–avfilter_link

/** src: 源滤镜的 AVFilterContext 结构体指针,表示连接的起始滤镜。* srcpad: 源滤镜的输出端口索引,表示连接的起始滤镜的输出端口。* dst: 目标滤镜的 AVFilterContext 结构体指针,表示连接的目标滤镜。* dstpad: 目标滤镜的输入端口索引,表示连接的目标滤镜的输入端口。* 该函数返回一个整数值,表示连接是否成功。如果成功连接两个滤镜,则返回0;如果发生错误,则返回负值。*/ 
int avfilter_link(AVFilterContext *src, unsigned srcpad,AVFilterContext *dst, unsigned dstpad);

通过调用 avfilter_link 函数,可以在滤镜图中连接两个滤镜,从而构建滤镜链。连接的源滤镜的输出端口将与目标滤镜的输入端口相连。连接后,数据将从源滤镜流向目标滤镜,进行进一步的处理。

3、 AVFilter主体框架流程

在利⽤AVFilter进⾏⾳视频数据处理前先将在进⾏的处理流程绘制出来,现在以FFmpeg filter官⽅⽂档中的⼀个例⼦为例进⾏说明。
在这里插入图片描述
这个例⼦的处理流程如上所示,⾸先使⽤split滤波器将input流分成两路流(main和tmp),然后分别对两路流进⾏处理。对于tmp流,先经过crop滤波器进⾏裁剪处理,再经过flip滤波器进⾏垂直⽅向上的翻转操作,输出的结果命名为flip流。再将main流和flip流输⼊到overlay滤波器进⾏合成操作。上图的input就是上⾯提过的buffer源滤波器,output就是上⾯的提过的buffersink滤波器。上图中每个节点都是⼀个AVFilterContext,每个连线就是AVFliterLink。所有这些信息都统⼀由AVFilterGraph来管理。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang Context是什么

一、这篇文章我们简要讨论Golang的Context有什么用 1、首先说一下Context的基本作用&#xff0c;然后在讨论他的实现 (1)数据传递&#xff0c;子Context只能看到自己的和父Context的数据&#xff0c;子Context是不能看到孙Context添加的数据。 (2)父子协程的协同&#xff0c;比…

字符串-String 概述

1.用加号拼接 2.String概述 3.注意&#xff1a; 4.创建String对象两种方式 //1使用直接赋值获取一个字符串对象String s1 "ABC";System.out.println(s1);//ABC//使用new的方式来获取一个字符//空参构造&#xff1a;可以获取一个空白字符串对象String s2 new String…

动手学机器学习机器学习的基本思想+习题

正则化 后面这项叫作正则化项&#xff0c;可以对需要求出的参数θ的大小进行抑制 加入L2正则化项后&#xff0c;线性规划问题的解析解前面不再是X.T与X的乘积&#xff0c;加上λI后&#xff0c;从半正定变成了正定矩阵&#xff0c;从而确保了矩阵有逆 我们有时希望得到的模型参…

docker 安装nginx

一、先查看有没有nginx镜像 docker images 二、发现没有nginx镜像&#xff0c;下载最新镜像 docker pull nginx 三、运行镜像 为了先复制出部分文件&#xff0c;先启动一个临时容器 docker run --name nginx -p 9001:80 -d nginx docker cp nginx:/etc/nginx/conf.d /home/…

00 - Logic Circuit 简介 -- 与或非门

---- 整理自B站UP主 踌躇月光 的视频 1. Logic Circuit Logic Circuit 下载地址 界面如下&#xff0c;实际使用可下载体验 2. 与或非门

蓝桥杯第793题——排水系统

题目描述 对于一个城市来说&#xff0c;排水系统是极其重要的一个部分。 有一天&#xff0c;小 C 拿到了某座城市排水系统的设计图。排水系统由 n 个排水结点&#xff08;它们从 1∼n 编号&#xff09;和若干个单向排水管道构成。每一个排水结点有若干个管道用于汇集其他排水…

vulnhub之devguru靶场提权过程(vulnhub打靶日记)

一、环境搭建 VM版本&#xff1a;17.5.1 build-23298084 攻击机&#xff1a;Kali2024&#xff08;下载地址&#xff1a;https://www.kali.org/&#xff09; 靶机&#xff1a;vulnhub靶场Devguru&#xff08;下载地址&#xff1a;https://www.vulnhub.com/entry/devguru-1,62…

开源推荐榜【Pear Admin Flask 用python来创建后台管理系统】

最新技术高效快速开发&#xff0c;前后端分离模式&#xff0c;开箱即用。 核心模块包括&#xff1a;用户、角色、职位、组织机构、菜单、字典、日志、多应用管理、文件管理、定时任务等功能。 代码量少、学习简单、功能强大、轻量级、易扩展&#xff0c;轻松开发从现在开始&…

使用deepspeed小记

1. 减少显存占用的历程忠告 医学图像经常很大&#xff0c;所以训练模型有时候会有难度&#xff0c;但是现在找到了很多减少显存的方法。 不知道为什么&#xff0c;使用transformers的trainer库确确实实会减少显存的占用&#xff0c;即使没有使用deepspeed&#xff0c;占用的显…

重读 Java 设计模式: 深入探讨原型模式,灵活复制对象

引言 在软件开发中&#xff0c;经常会遇到需要创建对象的情况。有时候&#xff0c;我们希望创建一个新的对象&#xff0c;但又不想通过传统的构造方法来创建&#xff0c;而是希望通过复制一个现有对象的方式来创建新的对象。这时&#xff0c;原型模式就能派上用场了。原型模式…

环信IM集成教程——Web端UIKit快速集成与消息发送

写在前面&#xff1a; 千呼万唤始出来&#xff0c;环信Web端终于出UIKit了&#xff01;&#x1f389;&#x1f389;&#x1f389; 文档地址&#xff1a;https://doc.easemob.com/uikit/chatuikit/web/chatuikit_overview.html 环信单群聊 UIKit 是基于环信即时通讯云 IM SDK 开…

【六 (2)机器学习-机器学习建模步骤/kaggle房价回归实战】

一、确定问题和目标&#xff1a; 1、业务需求分析&#xff1a; 与业务团队或相关利益方进行深入沟通&#xff0c;了解他们的需求和期望。 分析业务流程&#xff0c;找出可能的瓶颈、机会或挑战。 思考机器学习如何帮助解决这些问题或实现业务目标。 2、问题定义&#xff1a;…

Java | Leetcode Java题解之第8题字符串转换整数atoi

题目&#xff1a; 题解&#xff1a; class Solution {public int myAtoi(String str) {Automaton automaton new Automaton();int length str.length();for (int i 0; i < length; i) {automaton.get(str.charAt(i));}return (int) (automaton.sign * automaton.ans);} …

基础布局之LinearLayout线性布局

目录 一、基础属性二、重点属性2.1 weight(权重)属性&#xff1a;2.2 gravity 一、基础属性 LinearLayout默认方向是水平排放 属性作用android:id控件的ID&#xff0c;可以通过这个ID号来找到对应的控件android:layout_width控件的宽度android:layout_height控件的高度androi…

[C语言实现]数据结构二叉树之《我种下的树会为我遮阳挡雨》

&#x1f970;作者: FlashRider &#x1f30f;专栏: 初阶数据结构 &#x1f356;知识概要&#xff1a;详解二叉树的概念、二叉树的遍历、以及代码实现。 目录 树的基本概念 树的存储结构与二叉树的实现 树的存储 什么是二叉树 二叉链存储二叉树 二叉树的代码实现 树的基本…

gpt 3d三角形 重心坐标填充 沿x轴炫赵师傅

go import pygame from pygame.locals import * import sys import math# 初始化Pygame pygame.init()# 设置窗口大小 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption(3D Triangle Fill with Barycentric Coordinates)…

海豚调度任务类型Apache SeaTunnel部署指南

Apache DolphinScheduler已支持Apache SeaTunnel任务类型&#xff0c;本文介绍了SeaTunnel任务类型如何创建&#xff0c;任务参数&#xff0c;以及任务样例。 一、Apache SeaTunnel SeaTunnel 任务类型&#xff0c;用于创建并执行 SeaTunnel 类型任务。worker 执行该任务的时…

Kaggle:收入分类

先看一下数据的统计信息 import pandas as pd # 加载数据&#xff08;保留原路径&#xff0c;但在实际应用中建议使用相对路径或环境变量&#xff09; data pd.read_csv(r"C:\Users\11794\Desktop\收入分类\training.csv", encodingutf-8, encoding_errorsrepl…

基于单片机智能输液器监控系统的设计

**单片机设计介绍&#xff0c;基于单片机智能输液器监控系统的设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机智能输液器监控系统的设计旨在实现对输液过程的实时监测和控制&#xff0c;以提高输液的安全性和疗效…

C++:函数重载,引用

文章目录 1. 函数重载1.1 函数重载概念1.2 C支持函数重载的原理--名字修饰1.3 缺省参数与重载 2. 引用2.1引用概念2.2 引用特性2.3 常引用2.4 使用场景2.5 引用和指针的区别 1. 函数重载 1.1 函数重载概念 C允许在同一作用域中声明几个功能类似的同名函数&#xff0c;这些同名…