UVCcamera扫描device并展示的过程

本文详细解析了Android应用中针对UVCCamera工程的测试用例,特别是设备选择流程。首先介绍如何通过点击按钮打开设备选择对话框,然后深入到XML解析过程,解释如何根据vid和pid过滤USB设备。解析过程涉及vendorId、productId等字段,以及exclude字段的反向过滤功能。最后,展示了如何根据过滤规则匹配并显示可用的USB摄像头设备。
摘要由CSDN通过智能技术生成

UVCCamera工程中的测试用例,一般会开头扫描usb设备,这里以Test5 中的MainActivity为例说明,其实其他也一样。

进入Activity一般是黑屏,在左上角有一个按钮,这个按钮点击后会打开一个dialog样式的activity,来供选择自己需要操作的usb设备,一般选择依据是通过设备的pid,vid来选择,前提是这个设备需要是支持UVC协议的摄像头,否则即使选了也不能预览摄像头画面。

	private final CompoundButton.OnCheckedChangeListener mOnCheckedChangeListener
		= new CompoundButton.OnCheckedChangeListener() {
		@Override
		public void onCheckedChanged(final CompoundButton compoundButton, final boolean isChecked) {
			switch (compoundButton.getId()) {
			case R.id.camera_button:
				if (isChecked && !mCameraHandler.isOpened()) {
					CameraDialog.showDialog(MainActivity.this);
				} else {
					mCameraHandler.close();
					mCaptureButton.setVisibility(View.INVISIBLE);
					setCameraButton(false);
				}
				break;
			}
		}
	};

上述代码中,CameraDialog.showDialog(MainActivity.this);这一行便是展开对话框显示当前所有过滤的设备。

在CameraDialog的onResume方法中有updateDevices();

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

第一行便是调用getDeviceFilters进行xml的解析,这里解析的是res下的xml中device_filter.xml文件,将解析的内容放进list中:

	public static List<DeviceFilter> getDeviceFilters(final Context context, final int deviceFilterXmlId) {
		final XmlPullParser parser = context.getResources().getXml(deviceFilterXmlId);
		final List<DeviceFilter> deviceFilters = new ArrayList<DeviceFilter>();
		try {
			int eventType = parser.getEventType();
			while (eventType != XmlPullParser.END_DOCUMENT) {
	            if (eventType == XmlPullParser.START_TAG) {
					final DeviceFilter deviceFilter = readEntryOne(context, parser);
					if (deviceFilter != null) {
						deviceFilters.add(deviceFilter);
					}
	            }
				eventType = parser.next();
			}
		} catch (final XmlPullParserException e) {
			Log.d(TAG, "XmlPullParserException", e);
		} catch (final IOException e) {
			Log.d(TAG, "IOException", e);
		}

		return Collections.unmodifiableList(deviceFilters);
	}

其中readEntryOne表示读取其中一项内容,代码如下:

	public static DeviceFilter readEntryOne(final Context context, final XmlPullParser parser)
			throws XmlPullParserException, IOException {
		int vendorId = -1;
		int productId = -1;
		int deviceClass = -1;
		int deviceSubclass = -1;
		int deviceProtocol = -1;
		boolean exclude = false;
		String manufacturerName = null;
		String productName = null;
		String serialNumber = null;
		boolean hasValue = false;

		String tag;
        int eventType = parser.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
        	tag = parser.getName();
        	if (!TextUtils.isEmpty(tag) && (tag.equalsIgnoreCase("usb-device"))) {
        		if (eventType == XmlPullParser.START_TAG) {
        			hasValue = true;
					vendorId = getAttributeInteger(context, parser, null, "vendor-id", -1);
        			if (vendorId == -1) {
        				vendorId = getAttributeInteger(context, parser, null, "vendorId", -1);
        				if (vendorId == -1)
                			vendorId = getAttributeInteger(context, parser, null, "venderId", -1);
        			}
    				productId = getAttributeInteger(context, parser, null, "product-id", -1);
        			if (productId == -1)
            			productId = getAttributeInteger(context, parser, null, "productId", -1);
        			deviceClass = getAttributeInteger(context, parser, null, "class", -1);
        			deviceSubclass = getAttributeInteger(context, parser, null, "subclass", -1);
        			deviceProtocol = getAttributeInteger(context, parser, null, "protocol", -1);
        			manufacturerName = getAttributeString(context, parser, null, "manufacturer-name", null);
        			if (TextUtils.isEmpty(manufacturerName))
        				manufacturerName = getAttributeString(context, parser, null, "manufacture", null);
        			productName = getAttributeString(context, parser, null, "product-name", null);
        			if (TextUtils.isEmpty(productName))
        				productName = getAttributeString(context, parser, null, "product", null);
        			serialNumber = getAttributeString(context, parser, null, "serial-number", null);
        			if (TextUtils.isEmpty(serialNumber))
            			serialNumber = getAttributeString(context, parser, null, "serial", null);
					exclude = getAttributeBoolean(context, parser, null, "exclude", false);
        		} else if (eventType == XmlPullParser.END_TAG) {
        			if (hasValue) {
	        			return new DeviceFilter(vendorId, productId, deviceClass,
	        					deviceSubclass, deviceProtocol, manufacturerName, productName,
	        					serialNumber, exclude);
        			}
        		}
        	}
        	eventType = parser.next();
        }
        return null;
	}

这个解析是主要解析过程,后面会用到,这里要明白这个解析出来的规则后面会用来进行设备过滤,符合规则的设备就进行显示,不符合规则的设备就不显示。

这里解析主要解析了

vendorId,productId,class,subclass,protocol,manufacture,serial,exclude等字段,也就是说这些字段其实都可以配在xml中,如果xml中定义了这些内容,则会被解析到,如果没有定义,则结果为-1.

exclude字段是排除的意识,也就是如果定义了这个字段,则这一项xml为排除项,遇到了如果匹配上,则要把这个device排除掉,而不是像其他的如果匹配上则需要进行展示。是一个反向过滤标志。

在读到xml的末尾标签,则会创建DeviceFilter对象:

 else if (eventType == XmlPullParser.END_TAG) {
        			if (hasValue) {
	        			return new DeviceFilter(vendorId, productId, deviceClass,
	        					deviceSubclass, deviceProtocol, manufacturerName, productName,
	        					serialNumber, exclude);
        			}
        		}

在之前的上一层会循环解析这个xml文件,将所有解析到的DeviceFilter放在list里面,用于之后的设备匹配。

在updateDevices的第二行可以看到:

mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0)));

这里有个点需要注意,代码写的是:

mDeviceListAdapter = new DeviceListAdapter(getActivity(), mUSBMonitor.getDeviceList(filter.get(0)));
mUSBMonitor.getDeviceList(filter.get(0)),如果想用filter解析出来的xml项都进行匹配,则直接传入filter即可,不用filter.get(0)选择第一个,如果写了filter.get(0),则xml中的内容次序就会有关系,也就是说只会使用第一个进行匹配,其他的会忽略。

如果写filter.get(0),又想多匹配设备,则xml可以写成如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 以下内容的 vendor-id、product-id就是USB的vid和pid了-->

    <usb-device class="239" subclass="2" />	<!-- all device of UVC -->


<!--    <usb-device vendor-id="xxx" product-id="xxx"/>-->
    
    
</resources>

这里便进行了过滤匹配:

/**
	 * return device list, return empty list if no device matched
	 * @param filter
	 * @return
	 * @throws IllegalStateException
	 */
	public List<UsbDevice> getDeviceList(final DeviceFilter filter) throws IllegalStateException {
		if (destroyed) throw new IllegalStateException("already destroyed");
		final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
		final List<UsbDevice> result = new ArrayList<UsbDevice>();
		if (deviceList != null) {
			for (final UsbDevice device: deviceList.values() ) {
				if ((filter == null) || (filter.matches(device) && !filter.isExclude)) {
					result.add(device);
				}

			}
		}
		return result;
	}

对于mUsbManager获取到的每个Device,如果设备的pid,vid和filter中的匹配上,也就是相等,并且exclude为false(上面已经对该字段进行了说明),则把这个Device加入list,并赋值给Adapter进行展示。当然前提是需要有filter,没有的话可以创建任意一个即可。

那么现在逻辑就清楚了,如果要想展示自己想要展示的设备,可以编辑xml文件,加入自己的设备的pid,vid即可,也可以以class,subclass等来进行过滤,这样很多设备可能都会满足条件。

这里只对设备过滤,展示进行分析,其他再说。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值