UVC for USBCamera in Android - 篇一

基于UVC 协议,完成USBCamera 开发

一、目的:

1)依托于以前公司项目中自己折腾出来的USBCamera 基于 UVC协议,特别有必要总结一次,总结核心内容和知识点。
2)对于需要USBCamera 项目需求的新手一些指导性 建议、思路,特别适用,并不是所有的人都能上手直接折腾出来的

二、USBCamera 技术实现方案

  • 基于UVC协议 来实现
  • 基于Android 体系下的SDK API来实现,底层就是Camera 或者 Camera2 框架下来实现

难点

UVC 协议相机开发,资料很少很少 还比较老旧,基于UVC协议开发USBCamera 解决了UVC协议 库文件 等基本库方法问题,还需要知晓USB通讯相关知识。

三、误区:

基本常识是 USBCamera 是无驱的,那么跟底层系统不相关,USB相机插着就能用,系统本身支持的想法其实是错误的。
大家可以自行查阅相关资料,这里重点说明的是:
1)使用UVC协议来实现USBCamera ,作为一个系统应用 具备系统签名,不用考虑各种权限,是没有问题的。
2)使用Android SDK 框架下的API来实现USBCamera 是不可取的,官方文档明确说明Camera2 是不支持的。但是我们在不同半导体平台下不一样,比如RK上面是支持Camera2 开发USBCamera,
但是在MTK上面 Camera2 是不支持USBCamera,就是打不开相机的。 所以,要想实现Camera2 API来写一个USBCamera 务必驱动层、framework层在芯片平台支持的情况下适配好才行。

四、基础补充、资源参考

对于相机开发,还是建议无论是UVC协议开发USBCamera,还是 Android SDK API框架下Camera api 来开发相机,都需要了解最基本的相关资料。UVC和Camera 架构体系是两套完全不同的体系,可分别参考。

相机整个模块确实太专业、复杂了。 无论从硬件外设、驱动【USBCamera免驱】、相机 都比较专业、覆盖面及广,针对思考中的问题 给出自己认为比较好相关博客,方便了解,助于梳理流程、提升认知。

对于上层应用或者Framework 系统应用开发者,只需要了解基本的架构、API、使用方法,当然这些也不简单的
下面提供部分资源,方便快速了解,充电

架构图了解

MTKCamera2相机架构
Camera2架构
Android Camera架构简析

Camera相关专栏

Camera Framework 专栏
小驰私房菜系列
小驰私房菜MTK系列
小驰Camera 开发系列
Camera 相机开发
展讯平台 Camera
官方文档:谷歌官方 API 描述

零散知识了解

MTK 相机UI介绍
Camera2 相机认知
Camera2学习笔记
camera2关于拍照预览方向旋转90度和拍照图片镜像功能实现
Camera2 预览集成、简单拍照:熟悉预览步骤流程比较有用
Camera镜像上下左右颠倒问题的解决办法
MTK相机成像质量差
Camera应用分析

部分相机源码参考,学习API使用,梳理流程,偏应用层

极客相机 Camera2 API
Camera2 API详解
极客相机源码
Camera2 相机Demo
Camera2 专业相机Demo
拍照、预览、录像Demo
使用Camera2 拍照

Camera2 系统相关

Camera2 Service 启动

五)具体项目参考

参考gitHub项目:
UVCCamera 原始项目 需要自己配置NDK,编译
USBCamera 自己就是通过这个开源代码进行修改,定制,实现自身USBCamera 业务
AndroidUSBCamera 比较好的,支持多个USBCamera 并行展示,功能齐全,但是分辨率无法全部加载、存在.so 崩溃导致无解。

项目参考优劣:

  • UVCCamera:基本功能,需要自己封装方法,编译,搭建环境。 项目太老,很难跑通,需要自己封装。
  • USBCamera:封装比较好,单个摄像头显示 基本功能都有的 预览、拍照、录像OK,USB检测,查找、注册流程 都有,方便熟悉 USBCamera 使用流程,USBCamera的思想。上层相关USBManager 相关api 参考,到底层 native层不用管他们。
  • AndroidUSBCamera:封装最好,功能特别齐全,也可以实现多个摄像头同时显示。 但是预览尺寸会显示不全、部分预览尺寸点击会崩溃。
    这个目前无解,需要源码重新编译.so,无解,仅供学习使用。

建议直接从 USBCamera、AndroidUSBCamera 两个开源项目选择其中一个,根据自己实际需求来选择适合自己的项目。 如果指定了分辨率,对分辨率无选择要求,可以选择AndroidUSBCamera 。
如果通用版本,强烈建议选择USBCamera项目,稳定性更强。

当然:两个项目都有崩溃,特别在定制自己应用,在各种复杂场景下,各种崩溃需要自己去解决 适配。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

六) 核心源码逻辑说明

权限、过滤器

 AndroidMenifest.xml 中
	 
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
      <uses-permission android:name="android.permission.CAMERA"
          tools:ignore="PermissionImpliesUnsupportedChromeOsHardware" />
    <uses-feature android:name="android.hardware.usb.host"/>





  res/xml/device_filter.xml 过滤usb 设备
  
<usb>
	<usb-device class="239" subclass="2" />	<!-- all device of UVC -->
	<!-- a few android 9.0 -->
	<usb-device class="14" subclass="9" />
	<usb-device class="2" subclass="0" />
	<usb-device class="6" subclass="-1" />
	<usb-device class="39" subclass="0" />
	<usb-device class="0" subclass="0" />
	<usb-device class="239" subclass="2" />
	<usb-device class="239" subclass="2" />
	<usb-device product-id="4836" vendor-id="9573" />
	<usb-device product-id="2229" vendor-id="1133" />
	<usb-device product-id="640" vendor-id="1409" />
	<usb-device product-id="258" vendor-id="9228" />
	<usb-device product-id="61" vendor-id="65366" />
	<usb-device product-id="4867" vendor-id="10071" />
	<usb-device product-id="7995" vendor-id="4130" />
	<!--
	classData:0   subClassData:0  productId:61   vendorId1Id:65366
	 classData:239   subClassData:2  productId:4867   vendorId1Id:10071
classData:0   subClassData:0  productId:61   vendorId1Id:65366
 classData:0   subClassData:0  productId:61   vendorId1Id:65366
	-->
</usb>

通过USBManager 获取服务 得到USB外设

获取UsbManager 对象

mUsbManager = (UsbManager)context.getSystemService(Context.USB_SERVICE)

得到 detected devices

final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList()

得到过滤条件,加载xml 过滤器

    List<DeviceFilter> deviceFilters = DeviceFilter
                .getDeviceFilters(mActivity.getApplicationContext(), R.xml.device_filter);

过滤得到所有的 有效的外设 USBDevice

final List<UsbDevice> result = new ArrayList<UsbDevice>();
		if (deviceList != null) {
			if ((filters == null) || filters.isEmpty()) {
				result.addAll(deviceList.values());
			} else {
				for (final UsbDevice device: deviceList.values() ) {
					// match devices
					for (final DeviceFilter filter: filters) {
						if ((filter != null) && filter.matches(device) || (filter != null && filter.mSubclass == device.getDeviceSubclass())) {
							// when filter matches
							if (!filter.isExclude) {
								result.add(device);
							}
							break;
						} else {
						.....
						}
					}
				}
			}
		}

判断USBDevice 是否有权限

mUsbManager.hasPermission(device)

UVC 进行打开和预览操作

打开设备: 在有了权限之后开始打开设备,进行设备连接. 后面就是通过UVC协议进行Camera 的打开和预览操作了


onConnect -> openCamera、startPreview


 openCamera(ctrlBlock);
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        // wait for camera created
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // start previewing
                        Log.d(TAG,"onConnect   mCamView:"+mCamView);
                        startPreview(mCamView);
                    }
                }).start();

实际对camera 的处理,预览、拍照、录像 都是通过UVC协议编译的.so 文件来处理的,上面只是简单介绍了上层的USBManager 查找、检测、过滤 找到USB Camera 设备,之后的Camera 都通过封装好的 方法,最终通过native 方法实现。

实际项目效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如果你想在安卓设备上读取UVC摄像头的按键处理,你需要使用Android的USB主机模式来连接UVC摄像头。然后,你可以使用Android的USB API来访问UVC摄像头并读取按键事件。 以下是实现步骤: 1. 在AndroidManifest.xml文件中添加USB设备权限: ``` <uses-permission android:name="android.permission.USB_PERMISSION" /> ``` 2. 在你的活动中注册个BroadcastReceiver以接收USB设备权限请求: ``` private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbDevice usbDevice = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (usbDevice != null) { // 权限已授予,开始读取UVC摄像头 // ... } } else { // 权限未授予 Log.d(TAG, "permission denied for device " + usbDevice); } } } } }; ``` 3. 在你的活动中初始化USB模块并请求USB设备权限: ``` private UsbManager usbManager; private UsbDevice uvcCamera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); // 在此处获取UVC摄像头设备 uvcCamera = // ... // 请求USB设备权限 PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); usbManager.requestPermission(uvcCamera, permissionIntent); } ``` 4. 旦你获得了UVC摄像头的权限,你可以使用UsbDeviceConnection和UsbInterface来打开UVC摄像头并读取按键事件: ``` private void readUvcCameraButtons(UsbDeviceConnection connection, UsbInterface usbInterface) { // 在此处使用UsbDeviceConnection和UsbInterface打开UVC摄像头 // ... // 读取按键事件 byte[] buffer = new byte[8]; int requestType = UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_CLASS | UsbConstants.USB_RECIP_INTERFACE; int endpoint = usbInterface.getEndpoint(0).getAddress(); int length = connection.bulkTransfer(usbInterface.getEndpoint(0), buffer, buffer.length, 0); if (length > 0) { // 处理按键事件 // ... } } ``` 请注意,这只是个简单的示例。实际上,要成功地读取UVC摄像头的按键事件,你需要了解UVC协议,并编写正确的UVC命令来与UVC摄像头通信。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值