南七星之家 发表于 2024-6-22 07:58:12

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

        有的自界说系统,对于自己外接的USB摄像头,android原生的camera和camera2都无法打开,CameraX也用不了。这时候就要用libusbCamera,这个库可以打开摄像头,还可以多摄像头同时预览。本文主要是同时打开3个USB摄像头的项目记录,详细的接口先容请拜见原博客。
        特别感谢(原博客):UVCAndroid,安卓UVC相机通用开发库(支持多预览和多摄像头)_android com.herohan.uvcapp-CSDN博客
0,测试效果:

https://img-blog.csdnimg.cn/direct/5f720cf5e0fb401d8609dab84b221183.png
1,new一个project

2,增加依赖

   implementation 'com.herohan:UVCAndroid:1.0.5'
implementation 'com.github.getActivity:XXPermissions:13.5'https://img-blog.csdnimg.cn/direct/df3bef7abc0d4993b396fd6c86d072b3.png​
3,增加配置

   android.enableJetifier = truehttps://img-blog.csdnimg.cn/direct/77b8005b2ecc45ff915274427cb58a85.png​
4,增加堆栈

maven { url 'https://jitpack.io' } https://img-blog.csdnimg.cn/direct/935c87101d1448c480f49824ccec4467.png
5,存储权限(这个我以为不是必须的)

android:requestLegacyExternalStorage="true" https://img-blog.csdnimg.cn/direct/3c2502e8a526482db68011dd148bfa83.png
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">

    <LinearLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_gravity="center"
      android:orientation="vertical">

      <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:orientation="vertical">

                <TextView
                  android:id="@+id/textViewLeft"
                  android:text="左相机"
                  android:layout_gravity="center"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"/>

                <com.serenegiant.widget.AspectRatioSurfaceView
                  android:id="@+id/svCameraViewLeft"
                  android:layout_gravity="center"
                  android:layout_width="440dp"
                  android:layout_height="220dp"
                  />

            </LinearLayout>


            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginLeft="10dp"
                android:orientation="vertical">

                <TextView
                  android:id="@+id/textViewRight"
                  android:text="右相机"
                  android:layout_gravity="center"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"/>

                <com.serenegiant.widget.AspectRatioSurfaceView
                  android:id="@+id/svCameraViewRight"
                  android:layout_gravity="center"
                  android:layout_width="440dp"
                  android:layout_height="220dp"
                  />

            </LinearLayout>


      </LinearLayout>


      <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="5dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/textViewCenter"
                android:text="中间相机"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

            <com.serenegiant.widget.AspectRatioSurfaceView
                android: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;

    @Override
    protected 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();

                });
    }

    @Override
    protected 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() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder holder) {
                if (mCameraHelperLeft != null) {
                  mCameraHelperLeft.addSurface(holder.getSurface(), false);
                }
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public 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() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder holder) {
                if (mCameraHelperRight != null) {
                  mCameraHelperRight.addSurface(holder.getSurface(), false);
                }
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public 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() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder holder) {
                if (mCameraHelperCenter != null) {
                  mCameraHelperCenter.addSurface(holder.getSurface(), false);
                }
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
                if (mCameraHelperCenter != null) {
                  mCameraHelperCenter.removeSurface(holder.getSurface());
                }
            }
      });
    }

    @Override
    protected void onStart() {
      if (DEBUG) Log.d(TAG, "huahua--onStart:");
      super.onStart();

    }

    @Override
    protected 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 waitfor 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#";

      @Override
      public 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()+")");
                }
            }
      }

      @Override
      public 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);
      }

      @Override
      public 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 ratio
                  svCameraViewLeft.setAspectRatio(width, height);
                }

                mCameraHelperLeft.addSurface(svCameraViewLeft.getHolder().getSurface(), false);
            }
      }

      @Override
      public void onCameraClose(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");
            if (device.equals(mUsbDeviceLeft)) {
                if (mCameraHelperLeft != null) {
                  mCameraHelperLeft.removeSurface(svCameraViewLeft.getHolder().getSurface());
                }
            }
      }

      @Override
      public void onDeviceClose(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");
      }

      @Override
      public void onDetach(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");
            if (device.equals(mUsbDeviceLeft)) {
                mUsbDeviceLeft = null;
            }

            removeSelectedDevice(device);
      }

      @Override
      public 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#";

      @Override
      public 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()+")");
                }
            }
      }

      @Override
      public 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);
      }

      @Override
      public 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 ratio
                  svCameraViewRight.setAspectRatio(width, height);
                }

                mCameraHelperRight.addSurface(svCameraViewRight.getHolder().getSurface(), false);
            }
      }

      @Override
      public void onCameraClose(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");
            if (device.equals(mUsbDeviceRight)) {
                if (mCameraHelperRight != null) {
                  mCameraHelperRight.removeSurface(svCameraViewRight.getHolder().getSurface());
                }
            }
      }

      @Override
      public void onDeviceClose(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");
      }

      @Override
      public void onDetach(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");
            if (device.equals(mUsbDeviceRight)) {
                mUsbDeviceRight = null;
            }

            removeSelectedDevice(device);
      }

      @Override
      public 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#";

      @Override
      public 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()+")");
                }
            }
      }

      @Override
      public 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);
      }

      @Override
      public 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 ratio
                  svCameraViewCenter.setAspectRatio(width, height);
                }

                mCameraHelperCenter.addSurface(svCameraViewCenter.getHolder().getSurface(), false);
            }
      }

      @Override
      public void onCameraClose(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");
            if (device.equals(mUsbDeviceCenter)) {
                if (mCameraHelperCenter != null) {
                  mCameraHelperCenter.removeSurface(svCameraViewCenter.getHolder().getSurface());
                }
            }
      }

      @Override
      public void onDeviceClose(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");
      }

      @Override
      public void onDetach(UsbDevice device) {
            if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");
            if (device.equals(mUsbDeviceCenter)) {
                mUsbDeviceCenter = null;
            }

            removeSelectedDevice(device);
      }

      @Override
      public 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博客


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览