全面介绍AVFilter 的添加和使用

news2025/4/25 12:42:52

author: hjjdebug
date: 2025年 04月 22日 星期二 13:48:19 CST
description: 全面介绍AVFilter 的添加和使用


文章目录

  • 1.两个重要的编码思想
    • 1. 写代码不再是我们调用别人,而是别人调用我们!
    • 2. 面向对象的编程方法.
  • 2. AVFilter 开发流程
    • 2.1 编写AVFilter 文件
      • 2.1.0 定义AVFilter 对象
      • 2.1.1 初始化对象必要的成员变量.
      • 2.1.2 完善对象的指针函数
      • 2.1.3 成员变量可以是对象或对象数组
    • 2.2. 向ffmpeg 系统添加AVFilter文件
      • 2.2.1 copy文件到libavfilter目录下
      • 2.2.2 修改libavfilter/allfilter.c文件,添加外部AVFilter 对象声明
    • 2.3 重新执行configure 命令
      • 2.3.1. ff_vsrc_color_screen名称的意义
    • 2.4. 修改Makefile
      • 2.4.1 CONFIG_VSRC_COLOR_SCREEN_FILTER 配置宏名称的由来? 由对象名推导来的.
    • 2.5 小结
  • 3.代码验证:
    • 3.1 应用级验证
    • 3.2 最简单代码级验证
    • 3.3 用filtergraph 创建filter验证
  • 4. 改进意见

目的,本博客将引导你完成一个最简单的视频过滤器. 叫.vsrc_color_screen
它的功能很简单,就是产生一幅彩色屏幕画面.
通过本试验,你可以了解filter 是怎样工作的,我们怎样把自己的代码加入到ffmpeg框架中.

1.两个重要的编码思想

框架人家已经写好了,不能更改,你要想让自己的代码让框架调用,必需要符合一定的规范.
我们习惯了写代码调用别人的代码, 例如libc 库函数, printf 函数等等,
现在是别人调用自己. 这是第一个要转变的思想.

1. 写代码不再是我们调用别人,而是别人调用我们!

你可能听说过, 这不就是回调函数吗! 我注册一个函数,对方调用我.
对,是的,回调函数就是代码级别人调用自己的例子, 它要求函数的参数必需按对方要求的类型和个数来写.
这就是一个规范. 即参数的个数及类型早已经确定了,你不能更改.
ffmpeg 采用的代码接口是对象, 对象的概念一两句不易说明白,在使用中需慢慢体会.
这里需要知道,对象就是带指针函数的结构变量就可以了.

2. 面向对象的编程方法.

对象是c++中提出的概念, ffmpeg c语言所写也有对象的概念吗?
是的,ffmpeg 的对象才能更让你深刻的理解对象的本质. 它们是想通的.
c++说, 对象是由类创建的, 类由成员变量和成员函数构成.其中成员函数也可以是虚函数.
其实,c++的类就对应c的结构,对象就对应结构变量. c++有成员函数,c结构也可以有成员函数.
c++有虚函数,c结构也可以有虚函数,只是定义上有点区别而已.
后边介绍过滤器时,也会把这种面向对象的思想进行介绍,并与c++对比.

有了上面2个概念,开始介绍filter,vsrc_color_screen的开发.

2. AVFilter 开发流程

2.1 编写AVFilter 文件

2.1.0 定义AVFilter 对象

首先,因为它是filter, 我们就定义一个AVFilter 对象
AVFilter ff_vsrc_color_screen;
为什么叫这个名字,为什么前面加ff_?
嗯, 先理解为这就是规定, 因为filter对象都是这样起名字的叫ff_xxx
至于为什么这样,以后再介绍.
看到了吧,约束从起名字就开始了.
你只要把这个对象都处理好了,那这个彩色视频过滤器就算写好了.

且慢. c++里我创建一个对象一般都是写好类,然后一个new操作就把对象创建出来了.
ffmpeg 这里是在干啥呢?对象创建完了,我还没有写代码呢?它则么调用输出彩色屏幕的函数?

2.1.1 初始化对象必要的成员变量.

目前 ff_vsrc_color_screen 它就是一个默认的AVFilter对象,
是个架子,是个空壳,是个还缺少初始化的结构变量, 你需要把这个结构变量中的各成员变量都付给正确的值,
这个对象才算创建完成.
我们继续定义这个对象,添加几个变量, 没写的变量都是默认的空了.

AVFilter ff_vsrc_color_screen = {
.name = “color_screen”, //对象属性.name名称,可以叫做对外的对象名称
.activate = activate, // 获取frame 就会回调这个函数
.inputs = NULL,
.outputs = color_outputs, //指向过滤器的输出脚 AVFilterPad 数组
};

AVFilter 类(或说结构) 就不用我们写了,ffmpeg 都写好了, 我们只需要创建出一个完整的对象就可以了.
new 出来的对象不完整,成员变量全是空的,我们正在补全有用的信息.
.name 就是一个字符串, 给对象起个名, 以后把这个对象注册了, 系统就知道我们叫这个名,它以后要找我们,
也是找这个名就能找到我们
.activate 是一个函数指针, 需要我们去完成这个函数

又有问题了 !!
c++的成员函数是属于类的, 所有的对象都调用同一个成员函数,只是传递的this指针不同而以.
这里.activate 是一个函数, 为什么要我们写这个函数呢?它自己不会写吗?

.activate 函数指针, 可以理解为c++的虚函数指针. 虚函数指针在子类中是可以被改变的. 使得不同的子类有不同的表现.
从c的层面来理解, 虚函数是属于对象的,因为对象中虚函数指针可以被改变,使指向不同的函数,从而有不同的表现.
AVFilter 结构中能写的函数它都写了, 那些是属于类的,包括隐含的,你看不见的和无需关心的函数
对象中定义的.activate 就是一个回调函数, 参数的个数和类型已经确定. 具体执行什么操作需要你自己去完成.
它是上层调用AVReadFrame时 的回调函数
可见对象中可以定义很多个函数指针,它们都是回调函数,都是接口函数. 你不需要实现的,可以不实现.
这里,可以给对象另一个定义.
对象是代码级接口,包含很多成员变量和一系列回调函数.

2.1.2 完善对象的指针函数

虽然AVFilter可能很复杂, 但定义一个AVFilter对象还是比较简单,
只需要定义有限的几个变量和实现少数几个接口就可以了. 继续!

static int activate(AVFilterContext* ctx)
{
    AVFilterLink* outlink = ctx->outputs[0]; //定义的输出脚,见后.
    AVFrame* frame;

    if (!ff_outlink_frame_wanted(outlink)) //安全检查
        return FFERROR_NOT_READY;

	if (!test_picref)
	{ //第一次调用生成一幅图片
		test_picref = ff_get_video_buffer(outlink, 640, 480);
		test_fill_picture_fn(outlink->src, test_picref); //自己写的函数,要补充完整.
	}
	frame = av_frame_clone(test_picref); //每次调用,克隆这幅图片
    frame->pts = test_pts;
    frame->key_frame = 1;
    frame->interlaced_frame = 0;
    frame->pict_type = AV_PICTURE_TYPE_I;
    frame->sample_aspect_ratio = AVRational(1,1);
    test_pts++;

    return ff_filter_frame(outlink, frame);
}

2.1.3 成员变量可以是对象或对象数组

例如 color_outputs 就是一个过滤器引脚AVFilterPad 数组,
而AVFilterPad 对象又包含函数.

//具体填充图片frame的代码,也是调用的库函数完成的,draw,color需要先初始化
//人家都写好了,不需要你再去写了.
static void color_fill_picture(AVFilterContext* ctx, AVFrame* picref)
{
//下面是ffmpeg utils提供的函数,画实体矩形. x,y,w,h; color
ff_fill_rectangle(&draw, &color, picref->data, picref->linesize, 0, 0, 640, 480);
}

//关于引脚的套路函数,你需要对你使用的变量进行初始化, 而初始化又是调用的ffmpeg库函数,
// 你自己就没干什么事. 是啊,牵着牛鼻子走,让牛干活就可以了.

static int color_config_props(AVFilterLink* inlink)
{
    AVFilterContext* ctx = inlink->src;
    TestSourceContext* test = ctx->priv;
    int ret;

    ff_draw_init(&test_draw, inlink->format, 0);
    ff_draw_color(&test_draw, &test_color, test_color_rgba);

    if ((ret = config_props(inlink)) < 0)
        return ret;

    return 0;
}

static const AVFilterPad color_outputs[] = {
    {
        .name = "default",
        .type = AVMEDIA_TYPE_VIDEO,
        .config_props = color_config_props,
    },
    { NULL }
};

代码中函数及变量的来历都说清楚了, 还要加上头文件,适当的变量声明. 搞定gcc 也需要2把刷子.
下面是编译通过后的完整代码,放到顶部资源中下载吧.

2.2. 向ffmpeg 系统添加AVFilter文件

现在看看怎样加到ffmpeg系统中进行编译的. 及如何注册给ffmpeg系统.

2.2.1 copy文件到libavfilter目录下

把我们写的文件命名为vsrc_color_screen.c文件,
为啥叫这个名字,加 "vsrc__“是什么意思? 嗯一会再说, 你看看libavfilter下的filter文件都是
“vf_”,“af_”,“vsrc_”,”asrc_"开头的文件,最起码它是为了分类.
把这个文件copy到libavfilter下.

怎样向系统注册你新建的对象.

2.2.2 修改libavfilter/allfilter.c文件,添加外部AVFilter 对象声明

打开libavfilter/allfilter.c, 添加 extern AVFilter ff_vsrc_color_screen 声明
你可以看到很多exptern AVFilter ff_xxx的声明,
其中还有extern AVFilter ff_vsrc_xxx的声明
这说明这个文件使用了很多AVFilter 对象, 这里你就能体会对象和类是不一样的,AVFilter 是类,
AVFilter xxxx, 是声明的对象, extern AVFilter xxxx 是说这个对象是在别的文件定义的.
这个文件只是使用了一下.

我们就在 ff_vsrc_xxx 的尾巴上添加一条(其实在哪填都一样),说明有那么一个对象
extern AVFilter ff_vsrc_color_screen;

2.3 重新执行configure 命令

把你编译ffmpeg时执行的configure 命令重新运行一遍.
为啥呢? 干吗要重新配置呢?
因为configure 命令要扫描这个allfilter.c 文件, 把该文件中"extern AVFilter ff_“开头的声明
重新处理生成一个文件,叫"filter_list.c”, 这个文件也是被allfilter.c 包含的文件
打开这个文件你就明白了,你写的这个对象就在这个表中

static const AVFilter * const filter_list[] = {
	//一堆af过滤器,copy两个说明一下就可以了.
    &ff_af_abench,
    &ff_af_acompressor,
	....
	//一堆vsrc, 少copy几个
    &ff_vsrc_allrgb,
    &ff_vsrc_allyuv,
    &ff_vsrc_cellauto,
	&ff_vsrc_color_screen  // 我们定义的过滤器
	//其它过滤器对象就忽略了.
	...
}

2.3.1. ff_vsrc_color_screen名称的意义

ff_vsrc_color_screen, 这个名称是代码中的对象名称,对应一个地址
"ff_"这3个字符,是AVFilter 对象的标识.
所有的AVFilter 对象都是以"ff_"开始的,硬性规定,为什么呢?
因为configure 工具解析了allfilter.c文件,
碰到extern AVFilter "ff_"开始的代码行. 就知道它遇到了一个对象, 它会把所有对象地址形成一个文件
叫filter_list.c文件
工具对代码的改变,也算是你改变的,只是它节省了你的时间且不会改错.
由此我们知道,"ff_"开始的名称,是给configure 工具看的,告诉它这是一个AVFilter对象

vsrc 代表一种分类,视频源.
名称其它部分自由定义.

configure 命令一定要执行,而不要去手改这个filter_list.c, 因为configure 还生成其它文件,例如
我们要做的第二项改动,修改Makefile

2.4. 修改Makefile

我们先看看目前的Makefile
OBJS- ( C O N F I G G R A D I E N T S F I L T E R ) + = v s r c g r a d i e n t s . o O B J S − (CONFIG_GRADIENTS_FILTER) += vsrc_gradients.o OBJS- (CONFIGGRADIENTSFILTER)+=vsrcgradients.oOBJS(CONFIG_HALDCLUTSRC_FILTER) += vsrc_testsrc.o
OBJS- ( C O N F I G L I F E F I L T E R ) + = v s r c l i f e . o O B J S − (CONFIG_LIFE_FILTER) += vsrc_life.o OBJS- (CONFIGLIFEFILTER)+=vsrclife.oOBJS(CONFIG_MANDELBROT_FILTER) += vsrc_mandelbrot.o

我们知道,Makefile 是支持宏变量的, 宏变量是这样定义的
haha=“我很高兴”
当我们引用haha时,用$(var)来引用
$(warning $(haha)) 就会输出"我很高兴"

我们以第一项为例
OBJS-$(CONFIG_GRADIENTS_FILTER) += vsrc_gradients.o
“+=” 是把这个宏的定义又增加了一项的意思. 还是定义宏的问题
$(CONFIG_GRADIENTS_FILTER) ,是一个变量展开, 那就要看看CONFIG_GRADIENTS_FILTER是怎样定义的.
我们打开ffbuild/config.mak 查看CONFIG_GRADIENTS_FILTER的宏定义
CONFIG_GRADIENTS_FILTER=yes
我们就知道这一行的意思是
OBJS-yes += vsrc_gradients.o

在ffmpeg Makefile 中, OBJS-yes宏变量就是要生成的所有的目标文件的集合,
我们有了新编的vsrc_color_screen.c文件,当然也要把它编译成vsrc_color_screen.o文件,这样才能使用.

OBJS-$(CONFIG_VSRC_COLOR_SCREEN_FILTER) += vsrc_color_screen.o

2.4.1 CONFIG_VSRC_COLOR_SCREEN_FILTER 配置宏名称的由来? 由对象名推导来的.

宏名称CONFIG_VSRC_COLOR_SCREEN_FILTER, 为啥叫这个名?
看看别的filter中定义的, 找葫芦画瓢来配置
它的过程是在obj名称(去掉ff_)前面加上CONFIG,在后面加上FILTER,
也就是这个宏名是从object名称推导的.

###3.4.2 vsrc_color_screen.c 源代码名称的由来 ? 可以随便设.
用对象名命名文件名显得更有意义.

如果这个config宏是yes 的话, OBJS-yes 宏中就能添加vsrc_color_screen.o,
编译器gcc就能从源文件vsrc_color_screen.c 把它编译出来

好消息来了! 这个宏我们不用自己亲自定义了, 因为当你运行configure 命令时, configure给我们生成了这个宏定义
它就存放在 ffbuild/config.mak 文件中, 每次configure,这个文件都会被更新.

我知道你又有问题了,你想问config.mak这个文件是根据什么生成的?
这也难不住咱,我对它有研究. 其实绕了一圈还是configure 文件对那个allfilter.c文件进行了解析
抽取了所有extern AVFilter “ff_” 文本行, 然后定义了CONFIG_xxx_FILTER宏并书写到ffbuild/config.mak中
configure 不仅生成了config.mak 文件,还生成了config.h文件供代码调用,还生成了许多别的文件filter_list.c等等.
configure 是个脚本工具,它干了很多事情,你也可以修改它让它干更多的事如果需要的话.

那如果我修改了Makefile 和 allfilter.c 而忘记运行configure 怎么办?
没关系,你只管运行make, 它会给出提示信息:

WARNING: libavfilter/allfilters.c newer than config.h, rerun configure
连Makefile 也已经做的很贴心了.

2.5 小结

现在总结一下添加filter的过程吧.

  1. 书写代码
  2. 修改allfilters.c,用extern AVFilter ff_xxx
  3. 修改Makefile, 添加OBJS-$(CONFIG_xxx_FILTER)= new_filter.o
  4. 重新运行configure
    再执行make, 看看你的代码是否已经编译出来了.!
    都重编了,太多内容了,看不见.
    没关系, 再touch一下你的源代码,再make,这次只编译你的代码,就能看清楚了.
    代码有问题或有警告, 你可以修改代码再编译, 于时进入filter代码开发循环了.恭喜你上了正路!

3.代码验证:

验证就很简单了.
辛辛苦苦写的代码就是为了符合它的框架.
验证当然要用它的框架来验证了.

3.1 应用级验证

用ffplay 可以验证,我们可以指定ffplay 用我们的filter, 最简单的验证方式.
$ffplay -f lavfi vsrc_color_screen

没有按期望运行,那你就要检查一下了! 使用简单的东西,出了问题检查解决问题可就要凭真本事了.
如果你真要是理解了它的运行过程,那后面的就更容易理解了.

3.2 最简单代码级验证

ffmpeg filter的上层管理对象是 “lavfi” 对象, 它是一个AVInputFormat对象,是一个虚拟设备源,
让它的实现类匹配我们的filter,使它的数据直接从我们的filter来取. 就可以验证我们的filter.
这是标准的ffmpeg操控数据的流程,用avformat_open_input 打开文件,用avcodec_open2打开codec.
用av_read_frame 来读取数据, ffplay,ffprobe,ffmpeg也是这样处理过滤器的.
核心思想是把filter当文件使用.
直接给代码.都是通过调试的.

3.3 用filtergraph 创建filter验证

"lavfi"对象的执行过程其实也是创建filtrgraph,创建filter取数的过程, 如果不用lavfi虚拟设备
而是直接自己书写filtergraph,也可以.
这次代码更底层一些,也更直接一些,对其中的过程会辽解的更细致一些.
直接给代码,见附件

4. 改进意见

  1. 程序中用了很多全局变量,应该用一个结构把它们收集起来,看得会比较正规一些.
  2. 把这个结构改用AVClass 去定义,这样可以实现从外部(过滤器名+参数)直接控制这些参数.
    例如w,h,color等等

参考:
libavfilter/vsrc_color.c
doc/examples/filtering_video.c

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

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

相关文章

【UVM项目实战】异步fifo—uvm项目结构以及uvm环境搭建

本文章同步到我的个人博客网站&#xff1a;ElemenX-King&#xff1a;【UVM项目实战】异步fifo—uvm项目结构以及uvm环境搭建 希望大家能使用此网站来进行浏览效果更佳&#xff01;&#xff01;&#xff01; 目录 一、异步FIFO1.1 异步FIFO的定义1.2 亚稳态1.3 异步FIFO关键技术…

【通关函数的递归】--递归思想的形成与应用

目录 一.递归的概念与思想 1.定义 2.递归的思想 3.递归的限制条件 二.递归举例 1.求n的阶乘 2.顺序打印一个整数的每一位 三.递归与迭代 前言:上篇博文分享了扫雷游戏的实现&#xff0c;这篇文章将会继续分享函数的递归相关知识点&#xff0c;让大家了解并掌握递归的思…

【FAQ】针对于消费级NVIDIA GPU的说明

概述 本文概述 HP Anyware 在配备消费级 NVIDIA GPU 的物理工作站上的关​​键组件、安装说明和重要注意事项。 注意&#xff1a;本文档适用于 NVIDIA 消费级 GPU。NVIDIA Quadro 和 Tesla GPU 也支持 HP Anyware 在公有云、虚拟化或物理工作站环境中运行。请参阅PCoIP Graphi…

MyBatis操作数据库---从入门到理解

文章目录 关于MyBatis操作数据库MyBatis⼊⻔&#xff08;使用&#xff09;Mybatis操作数据库的步骤&#xff1a;配置数据库连接字符串使⽤MyBatis完成简单的增删改查操作注解xml 单元测试开启驼峰命名(推荐) 打印日志 关于MyBatis操作数据库 在之前的学习,我们了解到web应⽤程…

【HFP】蓝牙语音通话控制深度解析:来电拒接与通话终止协议

目录 一、来电拒接的核心流程与信令交互 1.1 拒接场景的分类与触发条件 1.2 HF 端拒接流程 1.3 AG 端拒接流程 二、通话终止流程&#xff1a;主动断开与异常中断 2.1 终止场景的界定 2.2 HF 端终止流程 2.3 AG 端终止流程 三、信令协议的核心要素&#xff1a;AT 命令与…

使用QML Tumbler 实现时间日期选择器

目录 引言相关阅读项目结构示例实现与代码解析示例一&#xff1a;时间选择器&#xff08;TimePicker&#xff09;示例二&#xff1a;日期时间选择器&#xff08;DateTimePicker&#xff09; 主窗口整合运行效果总结下载链接 引言 在现代应用程序开发中&#xff0c;时间与日期选…

智能吸顶灯/摄影补光灯专用!FP7195双通道LED驱动,高效节能省空间 !

一、双路调光技术背景与市场需求 随着LED照明技术的快速发展和智能照明需求的激增&#xff0c;双路调光技术正成为照明行业的重要发展方向。传统单路调光方案只能实现整体亮度的统一调节&#xff0c;而双路调光则能够实现对两个独立通道的精确控制。今天&#xff0c;由我来为大…

YOLOv11改进-双Backbone架构:利用双backbone提高yolo11目标检测的精度

一、引言&#xff1a;为什么我们需要双Backbone&#xff1f; 在目标检测任务中&#xff0c;YOLO系列模型因其高效的端到端检测能力而备受青睐。然而&#xff0c;传统YOLO模型大多采用单一Backbone结构&#xff0c;即利用一个卷积神经网络&#xff08;CNN&#xff09;作为特征提…

《逃离云端束缚,拥抱GPT本地部署》

《逃离云端束缚,拥抱GPT本地部署》 一、GPT 热潮与本地部署的兴起 自 OpenAI 推出 ChatGPT 以来,全球范围内掀起了一股人工智能的热潮,其强大的自然语言处理能力和广泛的应用场景,让人们对人工智能的未来充满了想象。GPT(Generative Pretrained Transformer)作为一种基于…

头歌之动手学人工智能-机器学习 --- PCA

目录 第1关&#xff1a;维数灾难与降维 第2关&#xff1a;PCA算法流程 任务描述 编程要求 测试说明 第3关&#xff1a;sklearn中的PCA 任务描述 编程要求 测试说明 第1关&#xff1a;维数灾难与降维 第2关&#xff1a;PCA算法流程 任务描述 本关任务&#xff1a;补充…

研0调研入门

一、Web of Science 使用教程 1. 访问与注册 访问入口&#xff1a;通过高校图书馆官网进入&#xff08;需IP权限&#xff09;&#xff0c;或直接访问 Web of Science官网。注册/登录&#xff1a;若机构已订阅&#xff0c;用学校账号登录&#xff1b;个人用户可申请试用或付费…

神经网络基础[ANN网络的搭建]

神经网络 人工神经网络&#xff08; Artificial Neural Network&#xff0c; 简写为ANN&#xff09;也简称为神经网络&#xff08;NN&#xff09;&#xff0c;是一种模仿生物神经网络结构和功能的计算模型。各个神经元传递复杂的电信号&#xff0c;树突接收到输入信号&#xf…

五、web自动化测试01

目录 一、HTML基础1、HTML介绍2、常用标签3、基础案例3.1 前端代码3.2 自动化测试 二、CSS定位1、css介绍2、案例3、代码优化 三、表单自动化1、案例2、元素属性定位 四、后台基础数据自动化1、登录1.1 id与class定位1.2 定位一组元素 2、商品新增 一、HTML基础 可参考学习 链…

数据库监控 | MongoDB监控全解析

PART 01 MongoDB&#xff1a;灵活、可扩展的文档数据库 MongoDB作为一款开源的NoSQL数据库&#xff0c;凭借其灵活的数据模型&#xff08;基于BSON的文档存储&#xff09;、水平扩展能力&#xff08;分片集群&#xff09;和高可用性&#xff08;副本集架构&#xff09;&#x…

STM32F407使用ESP8266实现阿里云OTA(中)

文章目录 前言一、程序分析二、程序讲解1. main函数2. Get_Version()函数3. esp_Init()函数4. Check_Updata()函数结语前言 从上一章STM32F407使用ESP8266实现阿里云OTA(上)中我们已经对连接阿里云和从阿里云获取升级包的流程非常的熟悉了。所以本章我们进行STM32的程序开发…

微信小程序 tabbar底部导航栏

官方文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar 一、常规菜单格式 在app.json 文件中配置&#xff0c;其他关键点详见官方文档&#xff0c;后续更新不规则图标的写法

Unity InputSystem触摸屏问题

最近把Unity打包后的windows软件放到windows触摸屏一体机上测试&#xff0c;发现部分屏幕触摸点击不了按钮&#xff0c;测试了其他应用程序都正常。 这个一体机是这样的&#xff0c;一个电脑机箱&#xff0c;外接一个可以触摸的显示屏&#xff0c;然后UGUI的按钮就间歇性点不了…

Linux Awk 深度解析:10个生产级自动化与云原生场景

看图猜诗&#xff0c;你有任何想法都可以在评论区留言哦~ 摘要 Awk 作为 Linux 文本处理三剑客中的“数据工程师”&#xff0c;凭借字段分割、模式匹配和数学运算三位一体的能力&#xff0c;成为处理结构化文本&#xff08;日志、CSV、配置文件&#xff09;的终极工具。本文聚…

免费版还是专业版?Dynadot 域名邮箱服务选择指南

关于Dynadot Dynadot是通过ICANN认证的域名注册商&#xff0c;自2002年成立以来&#xff0c;服务于全球108个国家和地区的客户&#xff0c;为数以万计的客户提供简洁&#xff0c;优惠&#xff0c;安全的域名注册以及管理服务。 Dynadot平台操作教程索引&#xff08;包括域名邮…

旋转磁体产生的场-对导航姿态的影响

pitch、yaw、roll是描述物体在空间中旋转的术语&#xff0c;通常用于计算机图形学或航空航天领域中。这些术语描述了物体绕不同轴旋转的方式&#xff1a; Pitch&#xff08;俯仰&#xff09;&#xff1a;绕横轴旋转&#xff0c;使物体向前或向后倾斜。俯仰角度通常用来描述物体…