全面介绍AVFilter 的添加和使用


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.mzph.cn/news/902589.shtml

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

相关文章

生物计算安全攻防战:从DNA存储破译到碳基芯片防御体系重构

随着碳基生物芯片突破冯诺依曼架构限制&#xff0c;DNA数据存储密度达到1EB/克量级&#xff0c;合成生物学与信息技术的融合正引发新一轮安全革命。本文深入解析碳基芯片逆向工程路径&#xff0c;揭示酶驱动DNA数据解码的技术突破&#xff0c;预警合成生物回路潜在的数据泄露风…

Spring Boot 集成 Ollama API 使用总结

Spring Boot 中集成 Ollama API 的完整指南&#xff0c;涵盖基础配置、API 调用、性能优化及常见问题解决。 一、环境准备 1. 依赖配置 在 pom.xml 中添加必要的依赖&#xff1a; <!-- Spring Web (用于 REST 请求) --> <dependency><groupId>org.springf…

SimVG论文精读

1. 数据集和任务部分 SimVG用的六个数据集&#xff1a;RefCOCO//g, ReferIt, Flickr30K, and GRefCOCO 数据集名称图像数量参照表达式数量参照对象实例数语言特性主要任务RefCOCO19,994142,20950,000​基于 MS COCO 图像&#xff0c;采用 ReferItGame 收集的指代表达数据集。…

VS中回显109:对‘pthread_create’未定义的引用

VS中解决 用VS2022写多线性程时需要使用pthread_create()用于创建线程,即使项目里加了所需要的头文件#include <pthread.h>但编译却报对pthread_create未定义的引用的错误,这是因为没有包含所需要的库 项目右击属性 在库依赖项中添加 pthread Ubuntu中解决 在Ubuntu中…

kotlin与MVVM结合使用总结(一)

一、Kotlin 与 MVVM 结合的核心优势 代码简洁性 数据类&#xff08;data class&#xff09;简化 Model 层定义&#xff0c;自动生成equals/hashCode/toString扩展函数简化 View 层逻辑&#xff08;如点击事件扩展&#xff09;lateinit/by lazy优化 ViewModel 属性初始化 异步处…

视频分析设备平台EasyCVR安防视频小知识:安防监控常见故障精准排查方法

随着安防监控技术的飞速发展&#xff0c;监控系统已经成为现代安防体系中不可或缺的核心组成部分&#xff0c;广泛应用于安防监控、交通管理、工业自动化等多个领域。然而&#xff0c;监控系统的稳定运行高度依赖于设备的正确配置、线路的可靠连接以及电源的稳定供电。在实际应…

【DeepSeek 学习推理】Llumnix: Dynamic Scheduling for Large Language Model Serving实验部分

6.1 实验设置 测试平台。我们使用阿里云上的16-GPU集群&#xff08;包含4个GPU虚拟机&#xff0c;类型为ecs.gn7i-c32g1.32xlarge&#xff09;。每台虚拟机配备4个NVIDIA A10&#xff08;24 GB&#xff09;GPU&#xff08;通过PCI-e 4.0连接&#xff09;、128个vCPU、752 GB内…

如何利用深度学习进行交通流量预测与疏导

传统的交通管理方法&#xff0c;诸如固定的信号灯配时方案、基于经验的警力部署等&#xff0c;在面对现代城市如此复杂多变的交通状况时&#xff0c;已然显得捉襟见肘&#xff0c;难以满足高效交通管理的需求。 在此背景下&#xff0c;准确的交通流量预测便成为了破解交通拥堵难…

LSTM-GAN生成数据技术

1. 项目概述 本项目利用生成对抗网络&#xff08;GAN&#xff09;技术来填补时间序列数据中的缺失值。项目实现了两种不同的GAN模型&#xff1a;基于LSTM的GAN&#xff08;LSTM-GAN&#xff09;和基于多层感知机的GAN&#xff08;MLP-GAN&#xff09;&#xff0c;并对两种模型…

CMake 入门指南:从零开始配置你的第一个项目

目录 一、CMake 是什么&#xff0c;为什么要使用 CMake 二、CMakeLists.txt 文件结构与简单示例 三、进阶的CMake 四、静态库与动态库生成及其使用 五、注释的语法 六、 set、list、message 三个常用的 CMake 函数与命令 七、CMake 的控制语句以及自定义宏/函数 八、为S…

多线程出bug不知道如何调试?java线程几种常见状态

当你的多线程代码结构很复杂的时候很难找出bug的原因所在&#xff0c;此时我们可以使用getState()方法获取该线程当前的状态&#xff0c;通过观察其状态是阻塞了还是因为没有启动等原因导致的。 状态描述NEW安排了工作&#xff0c;还未开始行动RUNNABLE可工作的&#xff0c;又…

Spark(20)spark和Hadoop的区别

Apache Spark 和 Apache Hadoop 都是广泛使用的开源大数据处理框架&#xff0c;但它们在设计理念、架构、性能和适用场景等方面存在显著区别。以下是它们的主要区别&#xff1a; ### **1. 架构设计** - **Hadoop**&#xff1a; - **HDFS&#xff08;Hadoop Distributed File…

【redis】哨兵模式

Redis主从模式虽然支持数据备份与读写分离&#xff0c;但存在三大核心缺陷&#xff1a;1. 故障切换依赖人工&#xff08;主节点宕机需手动提升从节点&#xff09;&#xff1b;2. 监控能力缺失&#xff08;无法自动检测节点异常&#xff09;&#xff1b;3. 脑裂风险&#xff08;…

Spark-Streaming

找出所有有效数据&#xff0c;要求电话号码为11位&#xff0c;但只要列中没有空值就算有效数据。 按地址分类&#xff0c;输出条数最多的前20个地址及其数据。 代码讲解&#xff1a; 导包和声明对象&#xff0c;设置Spark配置对象和SparkContext对象。 使用Spark SQL语言进行数…

Sentinel源码—9.限流算法的实现对比一

大纲 1.漏桶算法的实现对比 (1)普通思路的漏桶算法实现 (2)节省线程的漏桶算法实现 (3)Sentinel中的漏桶算法实现 (4)Sentinel中的漏桶算法与普通漏桶算法的区别 (5)Sentinel中的漏桶算法存在的问题 2.令牌桶算法的实现对比 (1)普通思路的令牌桶算法实现 (2)节省线程的…

Redis 详解:安装、数据类型、事务、配置、持久化、订阅/发布、主从复制、哨兵机制、缓存

目录 Redis 安装与数据类型 安装指南 Windows Linux 性能测试 基本知识 数据类型 String List&#xff08;双向列表&#xff09; Set&#xff08;集合&#xff09; Hash&#xff08;哈希&#xff09; Zset&#xff08;有序集合&#xff09; 高级功能 地理位置&am…

Docker配置带证书的远程访问监听

一、生成证书和密钥 1、准备证书目录和生成CA证书 # 创建证书目录 mkdir -p /etc/docker/tls cd /etc/docker/tls # 生成CA密钥和证书 openssl req -x509 -newkey rsa:4096 -keyout ca-key.pem \ -out ca-cert.pem -days 365 -nodes -subj "/CNDocker CA" 2、为…

MCP接入方式介绍

上一篇文章&#xff0c;我们介绍了MCP是什么以及MCP的使用。 MCP是什么&#xff0c;MCP的使用 接下来&#xff0c;我们来详细介绍一下MCP的接入 先看官网的架构图 上图的MCP 服务 A、MCP 服务 B、MCP 服务 C是可以运行在你的本地计算机&#xff08;本地服务器方式&#xff…

关于Agent的简单构建和分享

前言&#xff1a;Agent 具备自主性、环境感知能力和决策执行能力&#xff0c;能够根据环境的变化自动调整行为&#xff0c;以实现特定的目标。 一、Agent 的原理 Agent(智能体)被提出时&#xff0c;具有四大能力 感知、分析、决策和执行。是一种能够在特定环境中自主行动、感…

Gitlab runner 安装和注册

Gitlab Runner GitLab Runner是一个用于运行GitLab CI/CD流水线作业的软件包&#xff0c;由GitLab官方开发&#xff0c;完全开源。你可以在很多主流的系统环境或平台上安装它&#xff0c;如Linux、macOS、Windows和Kubernetes。如果你熟悉Jenkins 的话&#xff0c;你可以把它…