UVC系列2-探索Android UVC协议

2024-06-01 06:18
文章标签 android 协议 系列 探索 uvc

本文主要是介绍UVC系列2-探索Android UVC协议,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章选取android下linux-3.10作为分析对象,具体的UVC初始化过程可以参考csdn大神写的博客,地址是:http://blog.csdn.net/orz415678659。

uvc加载摄像头的过程无非是初始化设备,加载设备,获取设备相关参数并加载相关参数到buffer,此时就已经将视频和控制参数加载到buffer了,这篇文章主要关注的是控制相关的参数。
需要关注的两个核心文件是:

  • drivers\media\usb\uvc\uvc_ctrl.c
  • drivers\media\usb\uvc\uvc_v4l2.c

首先看看uvc_ctrl.c文件中的struct uvc_control_info uvc_ctrls[]结构体,这个结构体中定义了摄像头的控制参数详情,主要包含了各种类型的控制,比如白平衡,曝光度等。其中需要重点关注的参数是上下左右和焦距的控制参数,如下:

{.entity		= UVC_GUID_UVC_CAMERA,.selector	= UVC_CT_ZOOM_ABSOLUTE_CONTROL,.index		= 9,.size		= 2,.flags		= UVC_CTRL_FLAG_SET_CUR| UVC_CTRL_FLAG_GET_RANGE| UVC_CTRL_FLAG_RESTORE| UVC_CTRL_FLAG_AUTO_UPDATE,
},
{.entity		= UVC_GUID_UVC_CAMERA,.selector	= UVC_CT_ZOOM_RELATIVE_CONTROL,.index		= 10,.size		= 3,.flags		= UVC_CTRL_FLAG_SET_CUR| UVC_CTRL_FLAG_GET_MIN| UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES| UVC_CTRL_FLAG_GET_DEF| UVC_CTRL_FLAG_AUTO_UPDATE,
},
{.entity		= UVC_GUID_UVC_CAMERA,.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,.index		= 11,.size		= 8,.flags		= UVC_CTRL_FLAG_SET_CUR| UVC_CTRL_FLAG_GET_RANGE| UVC_CTRL_FLAG_RESTORE| UVC_CTRL_FLAG_AUTO_UPDATE,
},
{.entity		= UVC_GUID_UVC_CAMERA,.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,.index		= 12,.size		= 4,.flags		= UVC_CTRL_FLAG_SET_CUR| UVC_CTRL_FLAG_GET_MIN| UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES| UVC_CTRL_FLAG_GET_DEF| UVC_CTRL_FLAG_AUTO_UPDATE,
}

在这里可以看到这里定义了相对控制和绝对控制的参数,有焦距和上下左右,其中zoom是焦距调节,pan是左右,tilt是上下,缩写是ptz,所以云台摄像头也叫ptz摄像头。
另外需要重点关注的变量是struct uvc_control_mapping uvc_ctrl_mappings[],这个结构体枚举出来了所有的控制类型,比如id = V4L2_CID_PAN_ABSOLUTEid = V4L2_CID_TILT_ABSOLUTE的selector等于uvc_ctrls[]中的selector 是UVC_CT_PANTILT_RELATIVE_CONTROL参数,这两个id分别表示左右和上下的绝对控制,绝对控制的意思是给一个角度,摄像头转到指定的角度之后就停了。焦距的参数与pan和tilt的参数类似。稍微有点不一样的地方是zoom在3.10版本中已经添加了相对和绝对控制,参数id分别为V4L2_CID_ZOOM_ABSOLUTE,V4L2_CID_ZOOM_CONTINUOUS,其中V4L2_CID_ZOOM_CONTINUOUS是相对控制,从名称也可以看出continuous是持续的意思,相对控制就是发给摄像头一个参数,摄像头会一直不停的转动,直到最大角度才停止,中途如果给发送了停止位,才会停止。
在这么多控制参数中,重点看一下焦距的相对控制,如下:

{.id		= V4L2_CID_ZOOM_CONTINUOUS,.name		= "Zoom, Continuous",.entity		= UVC_GUID_UVC_CAMERA,.selector	= UVC_CT_ZOOM_RELATIVE_CONTROL,.size		= 0,.offset		= 0,.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,.get		= uvc_ctrl_get_zoom,.set		= uvc_ctrl_set_zoom,
}

看看这个参数中定义了get和set,其实这个是映射到的具体get和set方法,具体方法是:

static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,__u8 query, const __u8 *data)
{__s8 zoom = (__s8)data[0];switch (query) {case UVC_GET_CUR:return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);case UVC_GET_MIN:case UVC_GET_MAX:case UVC_GET_RES:case UVC_GET_DEF:default:return data[2];}
}
static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,__s32 value, __u8 *data)
{data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;data[2] = min((int)abs(value), 0xff);
}

第一个函数是获取当前焦距所处的位置,在UVC_GET_CUR处,当前位置为0是,返回0,否则的话大于0,返回当前值,否则返回相反数。

第二个函数是设置zoom的值,data[0]填写的值有三种情况,0,1,0xff,其中0表示停止,1表示拉远,0xff表示拉近。

在这两个函数中可以看到UVC_GET_MINUVC_GET_MAX,意思是获取最大值和最小值,其实在设备初始化的时候,会将设备的这些各个参数的最大值和最小值读取并保存。

具体取值的地方在__uvc_query_v4l2_ctrl这个函数中,函数定义如下:

static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,struct uvc_control *ctrl,struct uvc_control_mapping *mapping,struct v4l2_queryctrl *v4l2_ctrl)
{struct uvc_control_mapping *master_map = NULL;struct uvc_control *master_ctrl = NULL;struct uvc_menu_info *menu;unsigned int i;memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);v4l2_ctrl->id = mapping->id;v4l2_ctrl->type = mapping->v4l2_type;strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);v4l2_ctrl->flags = 0;if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;if (mapping->master_id)__uvc_find_control(ctrl->entity, mapping->master_id,&master_map, &master_ctrl, 0);if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {s32 val;int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);if (ret < 0)return ret;if (val != mapping->master_manual)v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;}if (!ctrl->cached) {int ret = uvc_ctrl_populate_cache(chain, ctrl);if (ret < 0)return ret;}if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,uvc_ctrl_data(ctrl,UVC_CTRL_DATA_DEF));}switch (mapping->v4l2_type) {case V4L2_CTRL_TYPE_MENU:v4l2_ctrl->minimum = 0;v4l2_ctrl->maximum = mapping->menu_count - 1;v4l2_ctrl->step = 1;menu = mapping->menu_info;for (i = 0; i < mapping->menu_count; ++i, ++menu) {if (menu->value == v4l2_ctrl->default_value) {v4l2_ctrl->default_value = i;break;}}return 0;case V4L2_CTRL_TYPE_BOOLEAN:v4l2_ctrl->minimum = 0;v4l2_ctrl->maximum = 1;v4l2_ctrl->step = 1;return 0;case V4L2_CTRL_TYPE_BUTTON:v4l2_ctrl->minimum = 0;v4l2_ctrl->maximum = 0;v4l2_ctrl->step = 0;return 0;default:break;}if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));return 0;
}

其中结构体v4l2_queryctrl的定义在\include\uapi\linux\videodev2.h文件中,

struct v4l2_queryctrl {__u32		     id;__u32		     type;	/* enum v4l2_ctrl_type */__u8		     name[32];	/* Whatever */__s32		     minimum;	/* Note signedness */__s32		     maximum;__s32		     step;__s32		     default_value;__u32                flags;__u32		     reserved[2];
};

包含了最大值,最小值,步长,默认值,控制名称等信息。
通过传递过来的控制id和类型遍历,并将遍历的结果保存在 v4l2_queryctrl中返回。
顺带说一下,在这个文件下面这个函数也很重要:
int uvc_ctrl_set(struct uvc_video_chain *chain,struct v4l2_ext_control *xctrl),这个函数掌控着控制的大权。其中v4l2_ext_control参数就是上层传递过来的控制参数,非常重要。
从相关控制参数一路分析过来,大致明白了控制的过程和控制代码的逻辑,下一步就是熟悉USB协议之后对这个参数做出定制,以适合不同厂商的摄像头。

这篇关于UVC系列2-探索Android UVC协议的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1020208

相关文章

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

Android协程高级用法大全

《Android协程高级用法大全》这篇文章给大家介绍Android协程高级用法大全,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友跟随小编一起学习吧... 目录1️⃣ 协程作用域(CoroutineScope)与生命周期绑定Activity/Fragment 中手

Java对接MQTT协议的完整实现示例代码

《Java对接MQTT协议的完整实现示例代码》MQTT是一个基于客户端-服务器的消息发布/订阅传输协议,MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛,:本文主要介绍Ja... 目录前言前置依赖1. MQTT配置类代码解析1.1 MQTT客户端工厂1.2 MQTT消息订阅适配器1.

Android 缓存日志Logcat导出与分析最佳实践

《Android缓存日志Logcat导出与分析最佳实践》本文全面介绍AndroidLogcat缓存日志的导出与分析方法,涵盖按进程、缓冲区类型及日志级别过滤,自动化工具使用,常见问题解决方案和最佳实... 目录android 缓存日志(Logcat)导出与分析全攻略为什么要导出缓存日志?按需过滤导出1. 按

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

Linux中的HTTPS协议原理分析

《Linux中的HTTPS协议原理分析》文章解释了HTTPS的必要性:HTTP明文传输易被篡改和劫持,HTTPS通过非对称加密协商对称密钥、CA证书认证和混合加密机制,有效防范中间人攻击,保障通信安全... 目录一、什么是加密和解密?二、为什么需要加密?三、常见的加密方式3.1 对称加密3.2非对称加密四、

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

如何在Spring Boot项目中集成MQTT协议

《如何在SpringBoot项目中集成MQTT协议》本文介绍在SpringBoot中集成MQTT的步骤,包括安装Broker、添加EclipsePaho依赖、配置连接参数、实现消息发布订阅、测试接口... 目录1. 准备工作2. 引入依赖3. 配置MQTT连接4. 创建MQTT配置类5. 实现消息发布与订阅