Android UCV 同时打开多路摄像头

Android UVC 同时打开多路摄像头

  • 前言
  • 硬件环境
  • 效果图
  • 注意问题
  • 代码分析(摄像头的打开步骤)
    • 1.找到摄像头设备
    • 打开摄像头
  • 项目地址

前言

做项目用到了多路摄像头,但是原生固件最多支持两路同时打开(cameraID 0和1),又不想对固件修改,所以打算采用uvc方式打开多路USB摄像头。找了几篇博客,以及github上的项目,down下来发现存在各种各样的问题(编译问题,打开多路问题)。从这个角度出发,打算把自己的过程以及代码分享出来。

硬件环境

硬件环境:
rk3399,rk3288,展讯9853
Logitech摄像头两个,WCH双目摄像头两个,一共六个镜头

效果图

六路,厉害了haha

注意问题

ndk版本一定要注意,否者会出现打不开的问题,笔者之前配置的android-ndk-r16b,怎么搞也不行,结果改成android-ndk-r14b就ok了,这点要注意一下

代码分析(摄像头的打开步骤)

1.找到摄像头设备

USBMonitor/usb设备控制类
主要的能力:usb设备节点(设备信息)的获取,对USB设备操作的广播监听(设备的连接与断开,usb权限请求的监听)
当我们点击demo中视频预览区域会弹出当前camera设备的列表,列表数据就是由它得来,需要注意得地方是dialog这里做了一个Camera设备的筛选

public void updateDevices() {
//		mUSBMonitor.dumpDevices();
		final List filter = DeviceFilter.getDeviceFilters(getActivity(), R.xml.device_filter);
		mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0)));
		mSpinner.setAdapter(mDeviceListAdapter);
	}

mUSBMonitor对象就是在MainActivity中初始化的那个,根据device_filter(class = 239)生成一个筛选器,至于为什么根据这个筛选我也不是很清楚,不过debug看来,确实camera数据的class = 239
Android UCV 同时打开多路摄像头_第1张图片

这样就筛选出了想要的Camera数据

打开摄像头

关键类 AbstractUVCCameraHandler,UVCCamera
UVCCamera负责jni驱动的调用,可以看作是android APi 的“Camera”类,具有打开,释放,调焦等功能
AbstractUVCCameraHandler负责控制UVCCamera,一些状态回调,数据回调,录制视频文件的编码等
它有一个内部线程类“CameraThread”很重要,主要方法都在这里面,但是蛋疼的是并没有看懂异步处理的核心用意,还是菜啊,望指正
打开逻辑很简单的,具体流程如下:
1.点击想要打开的设备节点,进行权限检查

if (item instanceof UsbDevice) {
					mUSBMonitor.requestPermission((UsbDevice)item);//获取设备信息,并检查打开此设备的权限
					((CameraDialogParent)getActivity()).onDialogResult(false);
				}

2.这个设备是否有打开权限,有的话直接打开,没有的话去请求,请求成功了直接打开

if (mUsbManager.hasPermission(device)) {
					// 如果应用已经拥有权限,请调用onConnect
					processConnect(device);
				} else {
					try {
						//未经许可请求
						mUsbManager.requestPermission(device, mPermissionIntent);
					} catch (final Exception e) {
						// 它似乎在Android 5.1.x的GALAXY系统中生成一个名为android.permission.sec.MDM_APP_MGMT的未知异常
						Log.w(TAG, e);
						processCancel(device);
						result = true;
					}
				}

3.假设已经有权限了,直接进到打开摄像头方法里面

private final void processConnect(final UsbDevice device) {
		if (destroyed) return;
		updatePermission(device, true);
		mAsyncHandler.post(new Runnable() {
			@Override
			public void run() {
				if (DEBUG) Log.v(TAG, "processConnect:device=" + device);
				UsbControlBlock ctrlBlock;
				final boolean createNew;
				ctrlBlock = mCtrlBlocks.get(device);
				if (ctrlBlock == null) {
					ctrlBlock = new UsbControlBlock(USBMonitor.this, device);//封装了一个模块数据
					mCtrlBlocks.put(device, ctrlBlock);
					createNew = true;
				} else {
					createNew = false;
				}
				if (mOnDeviceConnectListener != null) {
					mOnDeviceConnectListener.onConnect(device, ctrlBlock, createNew);
				}
			}
		});
	}

主要就是封装了一个UsbControlBlock(设备数据),还有一些是第一次打开还是反复打开的逻辑,缓存逻辑

4.回调给了MainActivity,记得前面说的“AbstractUVCCameraHandler负责控制UVCCamera”,没错,就是要用mHandlerFirst来控制打开camera

 mHandlerFirst.open(ctrlBlock);//打开摄像机
                final SurfaceTexture st = mUVCCameraViewFirst.getSurfaceTexture();
                mHandlerFirst.startPreview(new Surface(st));

                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mCaptureButtonFirst.setVisibility(View.VISIBLE);
                    }
                });

最终调用到了UVCCamera内的nativeConnect 方法,调用jni连接摄像头

到这里相机就打开了,要注意的是数据回调这部分我对源码修改了一下。

嗯,就是这些,还是挺简单的,代码会后续优化

项目地址

原项目地址(是真的牛,不过我下载编译后有些问题):
https://github.com/saki4510t/UVCCamera
我做了一些修改的项目地址:
https://github.com/yyfd2013zy/UvcCameraDemo

你可能感兴趣的:(android)