Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】

2024-02-24 13:20

本文主要是介绍Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        有的自定义系统,对于自己外接的USB摄像头,android原生的camera和camera2都无法打开,CameraX也用不了。这时候就要用libusbCamera,这个库可以打开摄像头,还可以多摄像头同时预览。本文主要是同时打开3个USB摄像头的项目记录,详细的接口介绍请参见原博客。

        特别感谢(原博客):UVCAndroid,安卓UVC相机通用开发库(支持多预览和多摄像头)_android com.herohan.uvcapp-CSDN博客

0,测试效果:

1,new一个project
2,增加依赖
implementation 'com.herohan:UVCAndroid:1.0.5'
implementation 'com.github.getActivity:XXPermissions:13.5'

3,增加配置
android.enableJetifier = true

4,增加仓库
maven { url 'https://jitpack.io' }

5,存储权限(这个我觉得不是必须的)
android:requestLegacyExternalStorage="true"

6,布局源码:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:orientation="vertical"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:orientation="vertical"><TextViewandroid:id="@+id/textViewLeft"android:text="左相机"android:layout_gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"/><com.serenegiant.widget.AspectRatioSurfaceViewandroid:id="@+id/svCameraViewLeft"android:layout_gravity="center"android:layout_width="440dp"android:layout_height="220dp"/></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginLeft="10dp"android:orientation="vertical"><TextViewandroid:id="@+id/textViewRight"android:text="右相机"android:layout_gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"/><com.serenegiant.widget.AspectRatioSurfaceViewandroid:id="@+id/svCameraViewRight"android:layout_gravity="center"android:layout_width="440dp"android:layout_height="220dp"/></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginTop="5dp"android:orientation="vertical"><TextViewandroid:id="@+id/textViewCenter"android:text="中间相机"android:layout_gravity="center"android:layout_width="wrap_content"android:layout_height="wrap_content"/><com.serenegiant.widget.AspectRatioSurfaceViewandroid:id="@+id/svCameraViewCenter"android:layout_gravity="center"android:layout_width="440dp"android:layout_height="220dp"/></LinearLayout></LinearLayout></androidx.coordinatorlayout.widget.CoordinatorLayout>
7,页面源码
package com.qz.camera;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;import android.Manifest;
import android.content.Intent;
import android.hardware.usb.UsbDevice;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;import com.herohan.uvcapp.CameraHelper;
import com.herohan.uvcapp.ICameraHelper;
import com.hjq.permissions.XXPermissions;
import com.serenegiant.usb.Size;
import com.serenegiant.usb.UVCCamera;
import com.serenegiant.usb.UVCParam;
import com.serenegiant.widget.AspectRatioSurfaceView;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;public class MainActivity extends AppCompatActivity {private static final boolean DEBUG = true;private static final String TAG = MainActivity.class.getSimpleName();private static final int DEFAULT_WIDTH = 640;private static final int DEFAULT_HEIGHT = 480;private TextView mCameraNameLeft,mCameraNameRight, mCameraNameCenter;private UsbDevice mUsbDeviceLeft,mUsbDeviceRight, mUsbDeviceCenter;private ICameraHelper mCameraHelperLeft, mCameraHelperRight, mCameraHelperCenter;private AspectRatioSurfaceView svCameraViewLeft, svCameraViewRight, svCameraViewCenter;private ConcurrentLinkedQueue<UsbDevice> mReadyUsbDeviceList = new ConcurrentLinkedQueue<>();private ConditionVariable mReadyDeviceConditionVariable = new ConditionVariable();private final Object mSync = new Object();private HandlerThread mHandlerThread;private Handler mAsyncHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//setTitle(R.string.entry_multi_camera_new);if (DEBUG) Log.d(TAG, "huahua--onCreate:");mCameraNameLeft = findViewById(R.id.textViewLeft);mCameraNameRight = findViewById(R.id.textViewRight);mCameraNameCenter = findViewById(R.id.textViewCenter);List<String> needPermissions = new ArrayList<>();needPermissions.add(Manifest.permission.CAMERA);XXPermissions.with(this).permission(needPermissions).request((permissions, all) -> {if (!all) {return;}initViews();mHandlerThread = new HandlerThread(TAG);mHandlerThread.start();mAsyncHandler = new Handler(mHandlerThread.getLooper());initCameraHelper();});}@Overrideprotected void onDestroy() {super.onDestroy();mHandlerThread.quitSafely();mAsyncHandler.removeCallbacksAndMessages(null);}private void initViews() {setCameraViewLeft();setCameraViewRight();setCameraViewCenter();}private void setCameraViewLeft() {svCameraViewLeft = findViewById(R.id.svCameraViewLeft);svCameraViewLeft.setAspectRatio(DEFAULT_WIDTH, DEFAULT_HEIGHT);svCameraViewLeft.getHolder().addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {if (mCameraHelperLeft != null) {mCameraHelperLeft.addSurface(holder.getSurface(), false);}}@Overridepublic void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {if (mCameraHelperLeft != null) {mCameraHelperLeft.removeSurface(holder.getSurface());}}});}private void setCameraViewRight() {svCameraViewRight = findViewById(R.id.svCameraViewRight);svCameraViewRight.setAspectRatio(DEFAULT_WIDTH, DEFAULT_HEIGHT);svCameraViewRight.getHolder().addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {if (mCameraHelperRight != null) {mCameraHelperRight.addSurface(holder.getSurface(), false);}}@Overridepublic void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {if (mCameraHelperRight != null) {mCameraHelperRight.removeSurface(holder.getSurface());}}});}private void setCameraViewCenter() {svCameraViewCenter = findViewById(R.id.svCameraViewCenter);svCameraViewCenter.setAspectRatio(DEFAULT_WIDTH, DEFAULT_HEIGHT);svCameraViewCenter.getHolder().addCallback(new SurfaceHolder.Callback() {@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {if (mCameraHelperCenter != null) {mCameraHelperCenter.addSurface(holder.getSurface(), false);}}@Overridepublic void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {if (mCameraHelperCenter != null) {mCameraHelperCenter.removeSurface(holder.getSurface());}}});}@Overrideprotected void onStart() {if (DEBUG) Log.d(TAG, "huahua--onStart:");super.onStart();}@Overrideprotected void onStop() {if (DEBUG) Log.d(TAG, "onStop:");super.onStop();clearCameraHelper();}public void initCameraHelper() {if (DEBUG) Log.d(TAG, "initCameraHelper:");if (mCameraHelperLeft == null) {mCameraHelperLeft = new CameraHelper();mCameraHelperLeft.setStateCallback(mStateListenerLeft);}if (mCameraHelperRight == null) {mCameraHelperRight = new CameraHelper();mCameraHelperRight.setStateCallback(mStateListenerRight);}if (mCameraHelperCenter == null) {mCameraHelperCenter = new CameraHelper();mCameraHelperCenter.setStateCallback(mStateListenerCenter);}}private void clearCameraHelper() {if (DEBUG) Log.d(TAG, "clearCameraHelper:");if (mCameraHelperLeft != null) {mCameraHelperLeft.release();mCameraHelperLeft = null;}if (mCameraHelperRight != null) {mCameraHelperRight.release();mCameraHelperRight = null;}if (mCameraHelperCenter != null) {mCameraHelperCenter.release();mCameraHelperCenter = null;}}private void selectDeviceLeft(final UsbDevice device) {if (DEBUG) Log.v(TAG, "selectDeviceLeft:device=" + device.getDeviceName());mUsbDeviceLeft = device;mAsyncHandler.post(() -> {waitCanSelectDevice(device);if (mCameraHelperLeft != null) {mCameraHelperLeft.selectDevice(device);}});}private void selectDeviceRight(final UsbDevice device) {if (DEBUG) Log.v(TAG, "selectDeviceRight:device=" + device.getDeviceName());mUsbDeviceRight = device;mAsyncHandler.post(() -> {waitCanSelectDevice(device);if (mCameraHelperRight != null) {mCameraHelperRight.selectDevice(device);}});}private void selectDeviceCenter(final UsbDevice device) {if (DEBUG) Log.v(TAG, "selectDeviceCenter:device=" + device.getDeviceName());mUsbDeviceCenter = device;mAsyncHandler.post(() -> {waitCanSelectDevice(device);if (mCameraHelperCenter != null) {mCameraHelperCenter.selectDevice(device);}});}/*** wait for only one camera need request permission** @param device*/private void waitCanSelectDevice(UsbDevice device) {mReadyUsbDeviceList.add(device);while (mReadyUsbDeviceList.size() > 1) {mReadyDeviceConditionVariable.block();mReadyDeviceConditionVariable.close();}}/*** remove ready camera that wait  for select** @param device*/private void removeSelectedDevice(UsbDevice device) {mReadyUsbDeviceList.remove(device);mReadyDeviceConditionVariable.open();}private final ICameraHelper.StateCallback mStateListenerLeft = new ICameraHelper.StateCallback() {private final String LOG_PREFIX = "ListenerLeft#";@Overridepublic void onAttach(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onAttach:");synchronized (mSync) {if (mUsbDeviceLeft == null && !device.equals(mUsbDeviceRight) && !device.equals(mUsbDeviceCenter)) {selectDeviceLeft(device);mCameraNameLeft.setText("左相机("+device.getDeviceName()+")");}}}@Overridepublic void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceOpen:");if (mCameraHelperLeft != null && device.equals(mUsbDeviceLeft)) {UVCParam param = new UVCParam();param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);mCameraHelperLeft.openCamera(param);}removeSelectedDevice(device);}@Overridepublic void onCameraOpen(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraOpen:");if (mCameraHelperLeft != null && device.equals(mUsbDeviceLeft)) {mCameraHelperLeft.startPreview();Size size = mCameraHelperLeft.getPreviewSize();if (size != null) {int width = size.width;int height = size.height;//auto aspect ratiosvCameraViewLeft.setAspectRatio(width, height);}mCameraHelperLeft.addSurface(svCameraViewLeft.getHolder().getSurface(), false);}}@Overridepublic void onCameraClose(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");if (device.equals(mUsbDeviceLeft)) {if (mCameraHelperLeft != null) {mCameraHelperLeft.removeSurface(svCameraViewLeft.getHolder().getSurface());}}}@Overridepublic void onDeviceClose(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");}@Overridepublic void onDetach(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");if (device.equals(mUsbDeviceLeft)) {mUsbDeviceLeft = null;}removeSelectedDevice(device);}@Overridepublic void onCancel(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCancel:");if (device.equals(mUsbDeviceLeft)) {mUsbDeviceLeft = null;}removeSelectedDevice(device);}};private final ICameraHelper.StateCallback mStateListenerRight = new ICameraHelper.StateCallback() {private final String LOG_PREFIX = "ListenerRight#";@Overridepublic void onAttach(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onAttach:");synchronized (mSync) {if (mUsbDeviceRight == null && !device.equals(mUsbDeviceLeft) && !device.equals(mUsbDeviceCenter)) {selectDeviceRight(device);mCameraNameRight.setText("右相机("+device.getDeviceName()+")");}}}@Overridepublic void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceOpen:");if (mCameraHelperRight != null && device.equals(mUsbDeviceRight)) {UVCParam param = new UVCParam();param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);mCameraHelperRight.openCamera(param);}removeSelectedDevice(device);}@Overridepublic void onCameraOpen(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraOpen:");if (mCameraHelperRight != null && device.equals(mUsbDeviceRight)) {mCameraHelperRight.startPreview();Size size = mCameraHelperRight.getPreviewSize();if (size != null) {int width = size.width;int height = size.height;//auto aspect ratiosvCameraViewRight.setAspectRatio(width, height);}mCameraHelperRight.addSurface(svCameraViewRight.getHolder().getSurface(), false);}}@Overridepublic void onCameraClose(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");if (device.equals(mUsbDeviceRight)) {if (mCameraHelperRight != null) {mCameraHelperRight.removeSurface(svCameraViewRight.getHolder().getSurface());}}}@Overridepublic void onDeviceClose(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");}@Overridepublic void onDetach(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");if (device.equals(mUsbDeviceRight)) {mUsbDeviceRight = null;}removeSelectedDevice(device);}@Overridepublic void onCancel(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCancel:");if (device.equals(mUsbDeviceRight)) {mUsbDeviceRight = null;}removeSelectedDevice(device);}};private final ICameraHelper.StateCallback mStateListenerCenter = new ICameraHelper.StateCallback() {private final String LOG_PREFIX = "ListenerCenter#";@Overridepublic void onAttach(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onAttach:");synchronized (mSync) {if (mUsbDeviceCenter == null && !device.equals(mUsbDeviceRight) && !device.equals(mUsbDeviceLeft)) {selectDeviceCenter(device);mCameraNameCenter.setText("中间相机("+device.getDeviceName()+")");}}}@Overridepublic void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceOpen:");if (mCameraHelperCenter != null && device.equals(mUsbDeviceCenter)) {UVCParam param = new UVCParam();param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);mCameraHelperCenter.openCamera(param);}removeSelectedDevice(device);}@Overridepublic void onCameraOpen(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraOpen:");if (mCameraHelperCenter != null && device.equals(mUsbDeviceCenter)) {mCameraHelperCenter.startPreview();Size size = mCameraHelperCenter.getPreviewSize();if (size != null) {int width = size.width;int height = size.height;//auto aspect ratiosvCameraViewCenter.setAspectRatio(width, height);}mCameraHelperCenter.addSurface(svCameraViewCenter.getHolder().getSurface(), false);}}@Overridepublic void onCameraClose(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");if (device.equals(mUsbDeviceCenter)) {if (mCameraHelperCenter != null) {mCameraHelperCenter.removeSurface(svCameraViewCenter.getHolder().getSurface());}}}@Overridepublic void onDeviceClose(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");}@Overridepublic void onDetach(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");if (device.equals(mUsbDeviceCenter)) {mUsbDeviceCenter = null;}removeSelectedDevice(device);}@Overridepublic void onCancel(UsbDevice device) {if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCancel:");if (device.equals(mUsbDeviceCenter)) {mUsbDeviceCenter = null;}removeSelectedDevice(device);}};}

对于较为标准的android系统调用,可以使用更加简洁的CameraX调用,博文链接:

Android相机调用-CameraX【外接摄像头】【USB摄像头】_安卓调取摄像头设备的方式-CSDN博客

这篇关于Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

使用Go调用第三方API的方法详解

《使用Go调用第三方API的方法详解》在现代应用开发中,调用第三方API是非常常见的场景,比如获取天气预报、翻译文本、发送短信等,Go作为一门高效并发的编程语言,拥有强大的标准库和丰富的第三方库,可以... 目录引言一、准备工作二、案例1:调用天气查询 API1. 注册并获取 API Key2. 代码实现3

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

在Android中使用WebView在线查看PDF文件的方法示例

《在Android中使用WebView在线查看PDF文件的方法示例》在Android应用开发中,有时我们需要在客户端展示PDF文件,以便用户可以阅读或交互,:本文主要介绍在Android中使用We... 目录简介:1. WebView组件介绍2. 在androidManifest.XML中添加Interne

Android协程高级用法大全

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

Java调用Python脚本实现HelloWorld的示例详解

《Java调用Python脚本实现HelloWorld的示例详解》作为程序员,我们经常会遇到需要在Java项目中调用Python脚本的场景,下面我们来看看如何从基础到进阶,一步步实现Java与Pyth... 目录一、环境准备二、基础调用:使用 Runtime.exec()2.1 实现步骤2.2 代码解析三、

Python如何调用另一个类的方法和属性

《Python如何调用另一个类的方法和属性》在Python面向对象编程中,类与类之间的交互是非常常见的场景,本文将详细介绍在Python中一个类如何调用另一个类的方法和属性,大家可以根据需要进行选择... 目录一、前言二、基本调用方式通过实例化调用通过类继承调用三、高级调用方式通过组合方式调用通过类方法/静

C#控制台程序同步调用WebApi实现方式

《C#控制台程序同步调用WebApi实现方式》控制台程序作为Job时,需同步调用WebApi以确保获取返回结果后执行后续操作,否则会引发TaskCanceledException异常,同步处理可避免异... 目录同步调用WebApi方法Cls001类里面的写法总结控制台程序一般当作Job使用,有时候需要控制

Python用Flask封装API及调用详解

《Python用Flask封装API及调用详解》本文介绍Flask的优势(轻量、灵活、易扩展),对比GET/POST表单/JSON请求方式,涵盖错误处理、开发建议及生产环境部署注意事项... 目录一、Flask的优势一、基础设置二、GET请求方式服务端代码客户端调用三、POST表单方式服务端代码客户端调用四