一种视频算法插件流水线执行架构

news2024/12/25 9:00:27

目的

将视频接入进来以后,使用算法对图像进行处理并且输出
1 各种接入
2 解码
3 解码后图像算法 如矫正算法
4 共享输出

方式

使用动态库的方式进行扫描底层,每个动态库为一个插件,每个插件包含特定的函数,通过扫描的方式加载所有插件

数据结构

typedef struct PlugIn
{
	std::string name;
	//获取插件名称
	//加载顺序
	int no;
	func_name_get FUNC1;
	//获取插件功能模块函数
	func_worker_get FUNC2;
	func_no_get FUNC3;
	HMODULE Module;
	PlugIn* next = NULL;
	PlugIn* nextgroup = NULL;
	//该插件默认不开启
	int inuse = 0;
}PlugIn;

其中,基本的数据结构包含PlugIn 数据结构,两个hash表,一个hash表为容器,存储所有对象,也方便立刻查找到某一个插件,另外一个hash表为指针数据,每个对象由next指针和nextgroup指针, nextgroup表示都为同一个no号码的动态库,比如no为0 的动态库优先级为最高,但是有三个,表示为同一优先级,并且可以并行执行,只有一个表示必须单独执行。最大插件为256,不能超过这个数目。超过这个数目不加载。
在这里插入图片描述

动态库示例

#include <stdint.h>
#include <opencv2/opencv.hpp>
#include <string>
extern "C"
{
	_declspec(dllexport) std::string WINAPI func_name();
	_declspec(dllexport) cv::Mat WINAPI _fastcall func_worker(cv::Mat& data, int w, int h);
	_declspec(dllexport) int WINAPI func_no();
}

3 插件框架

3.1 插件基础函数定义

typedef  std::string (WINAPI *func_name_get)();
typedef cv::Mat (WINAPI *func_worker_get)(cv::Mat& data, int w, int h);
typedef int (WINAPI *func_no_get)();

三个函数分别表示为名称获取,功能,no号码获取,每个插件必须包含这三个函数

3.2 扫描文件系统

	int scandll(const std::string &path, std::vector<std::string> &dirs,
		std::vector<std::string> &files)
	{
		struct _finddata_t filedata;
		memset(&filedata, 0x0, sizeof(filedata));
		std::string _path = path;

		//windows is dll
		_path += "\\*.dll";

		intptr_t handle = _findfirst(_path.c_str(), &filedata);
		if (handle == -1)
		{
			std::cout<<"扫描目录失败.\n"<<std::endl;
			return -1;
			
		}

		do
		{
			if (filedata.name[0] != '.')
			{
				//cout<<file.name<<endl;

				if (filedata.attrib & _A_SUBDIR)
					dirs.push_back(filedata.name);
				else
					files.push_back(path+"\\"+filedata.name);

				if (filedata.attrib & _A_SUBDIR)
				{
					//文件为目录(文件夹)


					std::string tmp_path = path;
					tmp_path += "\\";
					tmp_path += filedata.name;

					//递归遍历
					scandll(tmp_path, dirs, files);
				}
			}

		} while (!_findnext(handle, &filedata));

		_findclose(handle);
		return 0;
	}

该函数为扫描文件夹下plugin 下面文件夹所有的动态库,window下扫描所有dll, 而linux下则扫描所有 so 文件

	int loadall(std::vector<std::string> dlls)
	{
		memset(&v_cache[0], 0, sizeof(v_cache));
		int ret = 0;
		auto iter = dlls.begin();
		while (iter != dlls.end())
		{
			if (load(*iter) == 0)
				ret++;
			iter++;
		}
		PlugIn* a = NULL;
		PlugIn* b = NULL;
		//将指针数据里的数据链接起来
		for (int i = v_minno; i <= v_maxno; ++i)
		{
			if (v_cache[i] != NULL)
			{
				if (a == NULL)
				{
					a = v_cache[i];
					//记录第一个编号,最小的编号
					v_firstno = i;
				}
				else
				{
					a->nextgroup = v_cache[i];
					a = v_cache[i];
				}
			}
		}

		return ret;
	}

以上为装载过程,单个load函数如下所示:

	//改进算法使用链表和
	int load(std::string& name)
	{

		std::cout << "load name " << name << std::endl;
		PlugIn plugin;
		plugin.no = -1;
		//func_name_get FUNC1 = NULL;
		//func_worker_get FUNC2 = NULL;
		plugin.Module = LoadLibraryA(name.c_str());
		if (plugin.Module == NULL)
			return -1;
		plugin.FUNC1 = (func_name_get)GetProcAddress(plugin.Module, "func_name");
		plugin.FUNC2 = (func_worker_get)GetProcAddress(plugin.Module, "func_worker");
		plugin.FUNC3 = (func_no_get)GetProcAddress(plugin.Module, "func_no");
		if (plugin.FUNC3 != NULL)
		{
			plugin.no = plugin.FUNC3();
		}
		else
		{
			FreeLibrary(plugin.Module);
			return -1;
		}
		if (plugin.no > (PLUGIN_MAX - 1))//编号过大直接卸载
		{
			FreeLibrary(plugin.Module);
			return -1;
		}
		if (plugin.no < 0)
			plugin.no = 0;

		if (plugin.FUNC1 != NULL && plugin.FUNC2!=NULL)
		{
			plugin.name = plugin.FUNC1();
			//hash表准备
			v_mapplugin[plugin.no] = plugin;

			PlugIn* pobj = &v_mapplugin[plugin.no];

			int no = plugin.no;
			if (no > v_maxno)
				v_maxno = no;//记录最大插件编号
			if (no < v_minno)
				v_minno = no;//记录最小插件编号
			//cache表只是按顺序放的指针
			PlugIn* tmp = v_cache[no];
			if (tmp == NULL)
				v_cache[no] = pobj;
			else
			{
				while (tmp != NULL && tmp->next != NULL)
				{
					tmp = tmp->next;
				}
				tmp->next = pobj;
			}
	
		}
		return 0;
	}

单个插件装载的时候要注意是否有同一插件编号,有则挂到最末端的指针,如果要在组里面继续使用优先级,可以改变上面代码,增加一个组内编号。

单元测试

将以上函数封装成类后,使用单例挂载对象,指定扫描目录为plugin,开始加载,执行函数,下面测试只简单测试是否挂载正常,打印所有链接的插件名称。

#include "../client/plug.h"
#include <iostream>
#ifdef _DEBUG
#pragma comment(lib,"opencv_world450d.lib")
#else 
#pragma comment(lib,"opencv_world450.lib")
#endif
using namespace std;
int main()
{
	//PlugIn* v_cache[256] = { 0 };

	//PlugIn in1;
	//in1.no = 2;
	//in1.name = "test";
	//v_cache[in1.no] = &in1;

	//std::cout << v_cache[2]->name << std::endl;


	string path = "plugin";
	vector<string> sub_dir,sub_file;

	c_plugins::instance()->scandll(path, sub_dir, sub_file);

	c_plugins::instance()->loadall(sub_file);

	c_plugins::instance()->printoutname();
 这里可以执行图像函数,输入opencv Mat
	c_plugins::instance()->unload_all();
	return 0;
}

测试结果

在这里插入图片描述

继续改进

将使用热插拔的方式继续改进,以上代码暂时是在windows上执行,下一版将增加linux代码。

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

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

相关文章

Juniper 命令集合,分好类了,网工收好了哦!

Juniper是一家全球领先的网络设备制造商&#xff0c;其设备广泛应用于企业、运营商和数据中心等领域。下面是Juniper常用命令集合&#xff0c;以供参考。 基本命令 show interfaces&#xff1a;查看所有接口状态。show interface [interface-name]&#xff1a;查看指定接口的状…

Java_常用API

Java_常用API ​ API即Application Programming Interface&#xff0c;即应用程序接口。一般来说API就是软件组件之间信息交互的桥梁&#xff0c;通过它无需访问源码。API除了有应用程序接口的含义外&#xff0c;还特质API的说明文档&#xff0c;也称为帮助文档。 1.字符串的…

STM32F4_LCD液晶显示详解

目录 1. LCD简介 2. TFT_LCD简介 2.1 LCD屏显示原理 2.2 TFTLCD硬件分析 2.3 3.5寸 16位80并口驱动 2.4 NT35310驱动时序 2.5 TFTLCD驱动流程 2.6 显存指令 2.6.1 0xD3&#xff1a;读取LCD控制器的ID 2.6.2 0x36&#xff1a;控制扫描方向 2.6.3 0x2A&#xff1a;列地…

传统机器学习(七)支持向量机(2)sklearn中的svm

传统机器学习(七)支持向量机(2)sklearn中的svm 2 sklearn中的svm 2.1 LinearSVC及SVC参数详解 2.1.1 SVC参数 class sklearn.svm.SVC(*,C1.0, kernelrbf, degree3, gammascale, coef00.0, shrinkingTrue, probabilityFalse, tol0.001, cache_size200, class_weightNone, ve…

【刷题记录】stack queue的题目练习

文章目录 1. 最小栈2. 逆波兰表达式3. 栈的压入弹出序列4. 栈实现队列5. 队列实现栈 1. 最小栈 题目链接&#xff1a;155. 最小栈 - 力扣&#xff08;LeetCode&#xff09; 题干&#xff1a; 设计一个支持 push &#xff0c;pop &#xff0c;top 操作&#xff0c;并能在常数时…

使用django_celery_beat在admin后台配置计划任务

一、依赖包的安装 django中使用celery做异步任务和计划任务最头疼的点就是包之间版本兼容性问题&#xff0c;项目一启动花花报错&#xff0c;大概率都是版本问题。每次都会花很大时间在版本兼容性问题上。本例使用如下版本&#xff1a; Django3.2 celery5.2.7 django-celery-b…

记一次 Windows10 内存压缩模块 崩溃分析

一&#xff1a;背景 1. 讲故事 在给各位朋友免费分析 .NET程序 各种故障的同时&#xff0c;往往也会收到各种其他类型的dump&#xff0c;比如&#xff1a;Windows 崩溃&#xff0c;C 崩溃&#xff0c;Mono 崩溃&#xff0c;真的是啥都有&#xff0c;由于基础知识的相对缺乏&a…

CASAIM高精度自动化三维扫描系统检测塑料件,自动检测形位公差

随着塑料工业的迅速发展&#xff0c;以及塑料制品在航空、航天、电子、机械、船舶和汽车等工业部门的推广应用&#xff0c;对塑料件的质量要求也越来越高。 为了检测塑料件的尺寸偏差以及测量关键部位的3D尺寸和形位公差&#xff0c;对影响总成零件精度的产品、工装、工艺进行精…

Spring手写模拟源码篇(你值得拥有)

概念篇 下面是本文章关于Spring底层原理的章节 Bean的创建的生命周期 类-》推断构造方法-》根据构造方法创建普通对象-》依赖注入&#xff08;Autowired等进行属性注入&#xff09;-》初始化前&#xff08;PostConstruct)->初始化&#xff08;InitializingBean)-》初始化后…

【Feign扩展】OpenFeign日志打印Http请求参数和响应数据

SpringBoot使用log4j2 在Spring Boot中所有的starter 都是基于spring-boot-starter-logging的&#xff0c;默认使用Logback。使用Log4j2的话&#xff0c;你需要排除 spring-boot-starter-logging 的依赖&#xff0c;并添加 spring-boot-starter-log4j2的依赖。 配置依赖 <…

transformer 网络概述

1. RNN存在的问题 RNN对并行计算并不友好&#xff0c;下一输出依赖于上一输入&#xff0c;难以实现并行高效计算RNN相比较与self-attension模块&#xff0c;缺少对部分变量权重的预估&#xff0c;输出的数据默认拥有一致的权重 2. self-attension self-attension是干嘛的&am…

Shell编程规范与变量使用(再也回不到故事开始的第一章了)

一、Shell编程概述 1.Shell脚本的概念 将要执行的命令按顺序保存到一个文本文件&#xff0c;给该文件可执行权限&#xff0c;可结合各种shell控制语句以完成更复杂的操作。 2.Shell脚本的应用场景 重复性操作 交互性任务 批量事务处理 服务运行状态监控 定时任务执行 … 3…

【MySQL高级】——SQL执行流程

一、MySQL 中的 SQL执行流程 1. 查询缓存 Server 如果在查询缓存中发现了这条 SQL 语句&#xff0c;就会直接将结果返回给客户端&#xff1b;如果没 有&#xff0c;就进入到解析器阶段。需要说明的是&#xff0c;因为查询缓存往往效率不高&#xff0c;所以在 MySQL8.0 之后就抛…

设计模式 -- 组合模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

CKA证书题库-总结

CKA真题&#xff08;考题总结&#xff09; 文章目录 CKA真题&#xff08;考题总结&#xff09;证书个人考试总结申诉结果 CKA题目参考博主重点介绍 CKA模拟题库 注意事项考试概要考试注意事项&#xff1a; CKA题目答案设置自动补全方法一方法二 第⼀题&#xff1a;权限控制RBAC…

C语言编程技巧 --- C语言中左移右移与乘除法的比较

C语言中右移与除法的比较 最近在做项目的时候&#xff0c;遇到了一个有趣的现象。那就是&#xff0c;对于除2的整数次幂的操作而言&#xff0c;为了加快计算速度&#xff0c;一般情况下&#xff0c;会用右移&#xff08;>>&#xff09;来替代除法&#xff08;/&#xff0…

SparkSql(RDD、DataFrame、DataSet详解)idea实例+jdbc读取数据库并保存至数据库或本地

DataFrame 是什么 DataFrame 是一种以 RDD 为基础的分布式数据集&#xff0c;类似于传统数据库中 的二维表格。DataFrame 与 RDD 的主要区别在于&#xff0c;前者带有 schema 元信息&#xff0c;即 DataFrame 所表示的二维表数据集的每一列都带有名称和类型。这使得 Spark SQL …

QT Data Visualization 模块概述(数据三维显示的模块)

Data Visualization 是 Qt 提供的用于数据三维显示的模块。在 Ot 5.7 以前只有商业版才有此模块&#xff0c;而从Qt5.7 开始此模块在社区版本里也可以免费使用了。Data Visualization 用于数据的三维显示&#xff0c;包括三维柱状图、三维空间散点、三维曲面等。Data Visualiza…

KeepChatGPT插件-提效神器,解决ChatGPT报错!

KeepChatGPT插件-提效神器&#xff0c;解决ChatGPT报错&#xff01; 一、错误提示 最近⼏天&#xff0c;相信不少人在使用OpenAI的ChatGPT时都发现一个问题&#xff0c;就是官⽹报错越来越频繁了。 当你需⽤ChatGPT来处理⼀些⽐较琐碎的任务时&#xff0c;⼀旦你离开⻚⾯时间…

Java多线程基础-7:wait() 和 notify() 用法解析

线程之间是抢占式执行的&#xff0c;线程调度是无序的、随机的&#xff0c;因此线程之间执行的先后顺序是难以预知的。但是&#xff0c;实际开发中&#xff0c;有时我们希望合理地协调多个线程间执行的先后顺序。 虽然 join() 算是一种控制顺序的方式&#xff0c;但它毕竟“功…