【基于openharmony的多路摄像头功能:USB设备插拔检测】
前言
最近项目接触的模块比较繁多而杂,因此开始写文章记录下用以总结。
目前在做的是基于openharmony3.2的多camera功能主要涉及HDF(HAL)层与framework层。
本文章涉及多路摄像头功能的第一步:支持USB摄像头插拔检测。
内容
目前openharmony在HDF层支持的camera模式有V4L2和MPP,除了海思芯片大多用的linux通用的V4L2模式,因此在devicemanager中启动的是V4L2DeviceManager。
初始化
在V4L2DeviceManager::Init会创建一个EnumeratorManager并调用其Init。
RetCode EnumeratorManager::Init()
{uvcVideo_ = std::make_shared<HosV4L2UVC>();if (uvcVideo_ == nullptr) {CAMERA_LOGE("%s Create HosV4L2UVC fail", __FUNCTION__);return RC_ERROR;}uvcVideo_->V4L2UvcDetectInit([&](const std::string& hardwareName,std::vector<DeviceControl>& deviceControl,std::vector<DeviceFormat>& deviceFormat, bool uvcState) {UvcCallBack(hardwareName, deviceControl, deviceFormat, uvcState);});return RC_OK;
}
可以看到上面代码初始化了一个HosV4L2UVC对象并调用其V4L2UvcDetectInit
RetCode HosV4L2UVC::V4L2UvcDetectInit(UvcCallback cb)
{// set callbackuvcCallbackFun_ = cb;uDevFd_ = socket(PF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);if (uDevFd_ < 0) {CAMERA_LOGE("UVC:V4L2Detect socket() error\n");return RC_ERROR;}memset_s(&nls, sizeof(nls), 0, sizeof(nls));nls.nl_family = AF_NETLINK;nls.nl_pid = getpid();nls.nl_groups = 1;rc = bind(uDevFd_, (struct sockaddr *)&nls, sizeof(nls));eventFd_ = eventfd(0, 0);uvcDetectThread_ = new (std::nothrow) std::thread(&HosV4L2UVC::loopUvcDevice, this);
}
聪明的朋友应该已经看出来了,这里起了个线程执行loopUvcDevice通过监听NETLINK消息来循环检测USBcamera设备的插入。
USB设备检测
void HosV4L2UVC::loopUvcDevice()
{V4L2UvcEnmeDevices();...while (g_uvcDetectEnable) {int rc = select(((uDevFd > eventFd) ? uDevFd : eventFd) + 1, &fds, &fds, NULL, NULL);if (rc > 0 && FD_ISSET(uDevFd, &fds)) {usleep(delayTime);constexpr uint32_t buffSize = 4096;char buf[buffSize] = {};unsigned int len = recv(uDevFd, buf, sizeof(buf), 0);if (CheckBuf(len, buf)) {return;}...}
}
loopUvcDevice起了个无限循环,通过select监听之前创建的fd。从fd的创建参数NETLINK_KOBJECT_UEVENT可以知道是监听的udev设备文件创建的事件。
收到后会调用CheckBuf来处理。因为会收到所有的udev事件,所以需要过滤下
int HosV4L2UVC::CheckBuf(unsigned int len, char *buf)
{constexpr uint32_t UVC_DETECT_ENABLE = 0;constexpr uint32_t UVC_DETECT_DISABLE = -1;if (len > 0 && (strstr(buf, "video4linux") != nullptr)) {std::lock_guard<std::mutex> lock(g_uvcDetectLock);if (!g_uvcDetectEnable) {return UVC_DETECT_DISABLE;}std::string action = "";std::string subsystem = "";std::string devnode = "";V4L2GetUsbString(action, subsystem, devnode, buf, len);UpdateV4L2UvcMatchDev(action, subsystem, devnode);}return UVC_DETECT_ENABLE;
每次udev信息传递都会调用CheckBuf处理,感觉这里有优化空间。
从日志看我们会收到SUBSYSTEM为video4linux,创建的设备节点为video9的消息。

由于是USB设备,也可以看下当前设备插入USB camera后的USB枚举情况

可以看到此设备匹配的uvcvideo驱动。关于底层驱动我没有去适配,应该linux系统自动支持了,后续找机会了解下。
MatchDev
因为之前获取到了devnode设备节点,因此就可以直接通过设备节点访问设备了。
V4L2UvcGetCap
检测到了设备后通过VIDIOC_QUERYCAP向设备节点查询设备能力,
struct v4l2_capability {__u8 driver[16];__u8 card[32];__u8 bus_info[32];__u32 version;__u32 capabilities;__u32 device_caps;__u32 reserved[3];};
struct v4l2_capability cap;
rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
其中capabilities就是设备能力,查看是否支持V4L2_CAP_VIDEO_CAPTURE和V4L2_CAP_STREAMING。
camera驱动的本质就是将硬件采集到的流数据传递给用户侧。正常情况下用户侧可以使用read接口从内核读取出数据,但是这就涉及到了内核态数据和用户态数据的拷贝了。对于camera这种频繁且数据大的流效率会很低,所以目前主流都是使用内层映射的机制。
V4L2_CAP_STREAMING能力就是表示支持内存映射的方式建立buffer传递流数据。由于内核态直接将一块buffer空间映射到用户态,因此HAL层可以直接从该内存空间去除数据提高了效率。
V4L2_CAP_VIDEO_CAPTURE 则是表示这个设备是个视频捕捉设备,以此判断是否camera设备
V4L2UvcMatchDev
void HosV4L2UVC::V4L2UvcMatchDev(const std::string name, const std::string v4l2Device, bool inOut)
{....if ((sprintf_s(devName, sizeof(devName), "%s", name.c_str())) < 0) {CAMERA_LOGE("%s: sprintf devName failed", __func__);return;}if (inOut) {std::lock_guard<std::mutex> l(HosV4L2Dev::deviceFdLock_);iter = HosV4L2Dev::deviceMatch.insert(std::make_pair(std::string(devName), v4l2Device));.....} else {HosV4L2Dev::deviceMatch.erase(std::string(devName));}V4L2UvcSearchCapability(std::string(devName), v4l2Device, inOut);uvcCallbackFun_(std::string(devName), control_, format_, inOut);
}
这个接口就是将驱动name与设备节点作为一个pair插入到HosV4L2Dev::deviceMatch表中。
之后当HAL层需要访问设备时就通过驱动name找到设备节点最终访问设备。
这里有一个问题,如果插入了多个设备并且这些设备节点都是用的同一个驱动name,那就无法区分出硬件了。因此后续还需要进行优化,使用cameraID来更细化区分,这块等实现后更新到另外的博客。
之后还需要进一步获取设备的FMT能力,也就是设备支持的分辨率、帧率等信息。
void HosV4L2UVC::V4L2UvcSearchCapability(const std::string devName, const std::string v4l2Device, bool inOut)
{....std::shared_ptr<HosFileFormat> fileFormat = nullptr;fileFormat = std::make_shared<HosFileFormat>();fileFormat->V4L2GetFmtDescs(fd, format_);....std::shared_ptr<HosV4L2Control> control = nullptr;control = std::make_shared<HosV4L2Control>();control->V4L2GetControls(fd, control_);
}
V4L2GetFmtDescs在v4l2_fileformat.cpp中实现。下一章meta数据添加会再介绍,这里就不细讲了。主要是通过V4L2GetFmtDescs查询视频格式。
V4L2GetControls在v4l2_control.cpp中实现。通过VIDIOC_QUERYCTRL命令可以查到当前设备支持的控制命令信息。这些控制命令比如有对比度、饱和度、白平衡、曝光度等等。

最后再看看uvcCallbackFun_。
V4L2UvcDetectInit是在最开始初始化时传入的参数,倒回去看下初始化贴的代码可以知道这个回调是EnumeratorManager::UvcCallBack。然后这里又是被其他模块注册了回调。也就是最开始介绍的V4L2DeviceManager。
void EnumeratorManager::UvcCallBack(const std::string hardwareName,std::vector<DeviceControl>& deviceControl,std::vector<DeviceFormat>& deviceFormat, bool uvcState)
{uvcCb_(hardwareName, deviceControl, deviceFormat, uvcState);
}void V4L2DeviceManager::SetHotplugDevCallBack(HotplugDevCb cb)
{uvcCb_ = cb;enumeratorManager_->SetCallBack([&](const std::string hardwareName, std::vector<DeviceControl>& deviceControl,std::vector<DeviceFormat>& deviceFormat, bool uvcState) {UvcCallBack(hardwareName, deviceControl, deviceFormat, uvcState);});
}
因此USB设备插入检测后最终会通知给V4L2DeviceManager。参数是驱动name、上面查到的控制信息、视频格式、状态(插入还是移除)。
相关文章:
【基于openharmony的多路摄像头功能:USB设备插拔检测】
前言 最近项目接触的模块比较繁多而杂,因此开始写文章记录下用以总结。 目前在做的是基于openharmony3.2的多camera功能主要涉及HDF(HAL)层与framework层。 本文章涉及多路摄像头功能的第一步:支持USB摄像头插拔检测。 内容 目前openharmony在HDF层…...
uni-app:实现数字文本框,以及左右加减按钮
效果 代码 <template><view><view classline3><view classline3_position><view classleft>数量<text>*</text></view> <view class"right"><view class"quantity_btn"><view class"…...
跨平台开发框架Qt:面向对象、丰富API
Qt是一个跨平台C图形用户界面应用程序开发框架,它具有以下三大优势: 优良的跨平台特性:Qt支持多种操作系统,包括Windows、Linux、Solaris、HP-UX、Irix、FreeBSD等,使开发人员能够在不同平台上开发和部署应用程序&…...
An unexpected error has occurred. Conda has prepared the above report
今日在服务器上创建anaconda虚拟环境的时候,出现了如下报错 An unexpected error has occurred. Conda has prepared the above report 直接上解决方案 在终端中输入如下指令 conda config --show-sources 如果出现以下提示,说明多了一个文件 输入以下…...
考研C语言进阶题库——更新6-10题
目录 6输入一个字符串,输出其中字母的个数 7用递归求函数值x1,f(x)10,x>1.f(x)f(x-1)2 8所给字符串正序反序连接,形成新串并输出 9输入若干个整数以-1标记为结束输出其中的最大值 10求矩阵的两条对角线之和 6输入一个字符串,输出其中…...
汽车BOOTLOADER开发经历
鄙人参与电动汽车BOOTLOADER开发近三年,从完全没有这方面的基础到参与国内外大小知名或不知名车企的电动车三大件的BOOTLOADER开发,总结了以下一点学习心得。 1.熟悉基本术语含义 诊断、寻址方式、FBL、擦除、驱动 2.熟悉国际标准、UDS服务格式 汽车的…...
适配器模式(C++)
定义 将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 应用场景 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象 ”放在新的环境中应用,但是新环境要求…...
HTTP连接之出现400 Bad Request分析
1、400简介 400是一种HTTP状态码,告诉客户端它发送了一条异常请求。400页面是当用户在打开网页时,返回给用户界面带有400提示符的页面。其含义是你访问的页面域名不存在或者请求错误。主要分为两种。 1、语义有误,当前请求无法被服务器理解…...
后端开发, 接口幂等性是什么意思
在后端开发中,接口的幂等性是指同一个请求的多次执行所产生的效果与执行一次的效果相同。简而言之,对于同一个接口请求,无论发送多少次,其对资源的状态修改结果都是一致的。 幂等性在接口设计和实现中非常重要,特别是在涉及数据修改或资源状态变更的情况下。如果一个接口…...
k8s手动发布镜像的方法
kubectl edit deploy编辑对应的文件,并:wq!保存即可...
十二、ESP32控制步进电机
1. 运行效果 2. 步进电机 最大特点:能够控制旋转一定的角度 3. 步进电机原理...
利用openTCS实现车辆调度系统(六)openTCS订单的使用
运输订单 由类的实例表示,描述了由车辆执行的进程。 通常,此过程是货物从一个地点到另一个地点的实际运输。 然而,A也可以只描述车辆到目的地位置的运动以及要执行的可选车辆操作。TransportOrderTransportOrder 以下所有内容都是 openTCS …...
第一天 什么是CSRF ?
✅作者简介:大家好,我是Cisyam,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Cisyam-Shark的博客 💞当前专栏: 每天一个知识点 ✨特色专…...
知识图谱推荐系统研究综述
基于协同过滤的推荐是当前应用最为广泛的推荐方法,但也存在着新用户或新项目的冷启动以及数据稀疏等问题。针对上述两种方法出现的问题,研究者进一步提出了混合推荐系统。混合推荐系统结合上述两种方法的优点,可以有效缓解其中的不足,增加推荐的准确性。但是,混合推荐系统…...
基于Centos7的Nginx源码安装
目录 1、准备安装环境 2、获取tar包: 3、解压创建软链接 4、创建用户和组 5、执行安装 6、创建服务脚本 7、开启nginx:编辑编辑 1、准备安装环境 yum insatall -y make gcc gcc-c pcre-devel #pcre-devel -- pcre库 #安装openssl-devel yum …...
Ubuntu 20.04 安装 Stable Diffusionn
步骤 1:安装 wget、git、Python3 和 Python3虚拟环境(如果已安装可忽略这步骤) sudo apt install wget git python3 python3-venv步骤 2:克隆 SD 项目到本地 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webu…...
vue name命名错误 Do not use built-in or reserved HTML elements as component
描述: Do not use built-in or reserved HTML elements as component id: header 这里指的是components的名称命名不正确。 在项目中我使用的是header 作为组件名称,但是在前端html中这个是内置组件来的,名称已被占用不能再使用这些名称了。…...
知识付费系统开发:构建高效智能的付费内容平台
随着数字化时代的来临,知识付费正迅速崭露头角,为知识创作者和求知者带来了全新的商机。在这个背景下,开发一款高效智能的知识付费系统成为了一项重要的任务。本文将深入探讨如何基于Python编程语言和相关技术构建一个智能的知识付费内容平台…...
数据结构----结构--线性结构--递归
数据结构----结构–线性结构–递归 1.递归的概念 递归:将一个问题拆解成解决方案完全相同的子问题,并且有一个明确的终点 看如下递归代码理解一下递归 void fun(int n){if(n4){printf("%d",n);return;}fun(n1);printf("%d",n); …...
在Windows批处理程序中实现延时功能
方法1:使用PowerShell echo off:: 使用 PowerShell 的 Start-Sleep 命令来实现精确延时 powershell -command "Start-Sleep -Milliseconds 3000"echo Delay complete. 不过,通常Win7专业版和旗舰版中都会默认安装了PowerShell,但是标准版和家…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
