当前位置:   article > 正文

Android相机调用-libusbCamera【外接摄像头】【USB摄像头】 【多摄像头预览】_com.herohan:uvcandroid

com.herohan:uvcandroid

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

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

0,测试效果:

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

3,增加配置
android.enableJetifier = true

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

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

6,布局源码:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent">
  7. <LinearLayout
  8. android:layout_width="wrap_content"
  9. android:layout_height="wrap_content"
  10. android:layout_gravity="center"
  11. android:orientation="vertical">
  12. <LinearLayout
  13. android:layout_width="wrap_content"
  14. android:layout_height="wrap_content"
  15. android:orientation="horizontal">
  16. <LinearLayout
  17. android:layout_width="wrap_content"
  18. android:layout_height="wrap_content"
  19. android:layout_gravity="center"
  20. android:orientation="vertical">
  21. <TextView
  22. android:id="@+id/textViewLeft"
  23. android:text="左相机"
  24. android:layout_gravity="center"
  25. android:layout_width="wrap_content"
  26. android:layout_height="wrap_content"/>
  27. <com.serenegiant.widget.AspectRatioSurfaceView
  28. android:id="@+id/svCameraViewLeft"
  29. android:layout_gravity="center"
  30. android:layout_width="440dp"
  31. android:layout_height="220dp"
  32. />
  33. </LinearLayout>
  34. <LinearLayout
  35. android:layout_width="wrap_content"
  36. android:layout_height="wrap_content"
  37. android:layout_gravity="center"
  38. android:layout_marginLeft="10dp"
  39. android:orientation="vertical">
  40. <TextView
  41. android:id="@+id/textViewRight"
  42. android:text="右相机"
  43. android:layout_gravity="center"
  44. android:layout_width="wrap_content"
  45. android:layout_height="wrap_content"/>
  46. <com.serenegiant.widget.AspectRatioSurfaceView
  47. android:id="@+id/svCameraViewRight"
  48. android:layout_gravity="center"
  49. android:layout_width="440dp"
  50. android:layout_height="220dp"
  51. />
  52. </LinearLayout>
  53. </LinearLayout>
  54. <LinearLayout
  55. android:layout_width="wrap_content"
  56. android:layout_height="wrap_content"
  57. android:layout_gravity="center"
  58. android:layout_marginTop="5dp"
  59. android:orientation="vertical">
  60. <TextView
  61. android:id="@+id/textViewCenter"
  62. android:text="中间相机"
  63. android:layout_gravity="center"
  64. android:layout_width="wrap_content"
  65. android:layout_height="wrap_content"/>
  66. <com.serenegiant.widget.AspectRatioSurfaceView
  67. android:id="@+id/svCameraViewCenter"
  68. android:layout_gravity="center"
  69. android:layout_width="440dp"
  70. android:layout_height="220dp"
  71. />
  72. </LinearLayout>
  73. </LinearLayout>
  74. </androidx.coordinatorlayout.widget.CoordinatorLayout>
7,页面源码
  1. package com.qz.camera;
  2. import androidx.annotation.NonNull;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.Manifest;
  5. import android.content.Intent;
  6. import android.hardware.usb.UsbDevice;
  7. import android.os.Bundle;
  8. import android.os.ConditionVariable;
  9. import android.os.Handler;
  10. import android.os.HandlerThread;
  11. import android.util.Log;
  12. import android.view.SurfaceHolder;
  13. import android.view.View;
  14. import android.widget.Button;
  15. import android.widget.TextView;
  16. import com.herohan.uvcapp.CameraHelper;
  17. import com.herohan.uvcapp.ICameraHelper;
  18. import com.hjq.permissions.XXPermissions;
  19. import com.serenegiant.usb.Size;
  20. import com.serenegiant.usb.UVCCamera;
  21. import com.serenegiant.usb.UVCParam;
  22. import com.serenegiant.widget.AspectRatioSurfaceView;
  23. import java.util.ArrayList;
  24. import java.util.List;
  25. import java.util.concurrent.ConcurrentLinkedQueue;
  26. public class MainActivity extends AppCompatActivity {
  27. private static final boolean DEBUG = true;
  28. private static final String TAG = MainActivity.class.getSimpleName();
  29. private static final int DEFAULT_WIDTH = 640;
  30. private static final int DEFAULT_HEIGHT = 480;
  31. private TextView mCameraNameLeft,mCameraNameRight, mCameraNameCenter;
  32. private UsbDevice mUsbDeviceLeft,mUsbDeviceRight, mUsbDeviceCenter;
  33. private ICameraHelper mCameraHelperLeft, mCameraHelperRight, mCameraHelperCenter;
  34. private AspectRatioSurfaceView svCameraViewLeft, svCameraViewRight, svCameraViewCenter;
  35. private ConcurrentLinkedQueue<UsbDevice> mReadyUsbDeviceList = new ConcurrentLinkedQueue<>();
  36. private ConditionVariable mReadyDeviceConditionVariable = new ConditionVariable();
  37. private final Object mSync = new Object();
  38. private HandlerThread mHandlerThread;
  39. private Handler mAsyncHandler;
  40. @Override
  41. protected void onCreate(Bundle savedInstanceState) {
  42. super.onCreate(savedInstanceState);
  43. setContentView(R.layout.activity_main);
  44. //setTitle(R.string.entry_multi_camera_new);
  45. if (DEBUG) Log.d(TAG, "huahua--onCreate:");
  46. mCameraNameLeft = findViewById(R.id.textViewLeft);
  47. mCameraNameRight = findViewById(R.id.textViewRight);
  48. mCameraNameCenter = findViewById(R.id.textViewCenter);
  49. List<String> needPermissions = new ArrayList<>();
  50. needPermissions.add(Manifest.permission.CAMERA);
  51. XXPermissions.with(this)
  52. .permission(needPermissions)
  53. .request((permissions, all) -> {
  54. if (!all) {
  55. return;
  56. }
  57. initViews();
  58. mHandlerThread = new HandlerThread(TAG);
  59. mHandlerThread.start();
  60. mAsyncHandler = new Handler(mHandlerThread.getLooper());
  61. initCameraHelper();
  62. });
  63. }
  64. @Override
  65. protected void onDestroy() {
  66. super.onDestroy();
  67. mHandlerThread.quitSafely();
  68. mAsyncHandler.removeCallbacksAndMessages(null);
  69. }
  70. private void initViews() {
  71. setCameraViewLeft();
  72. setCameraViewRight();
  73. setCameraViewCenter();
  74. }
  75. private void setCameraViewLeft() {
  76. svCameraViewLeft = findViewById(R.id.svCameraViewLeft);
  77. svCameraViewLeft.setAspectRatio(DEFAULT_WIDTH, DEFAULT_HEIGHT);
  78. svCameraViewLeft.getHolder().addCallback(new SurfaceHolder.Callback() {
  79. @Override
  80. public void surfaceCreated(@NonNull SurfaceHolder holder) {
  81. if (mCameraHelperLeft != null) {
  82. mCameraHelperLeft.addSurface(holder.getSurface(), false);
  83. }
  84. }
  85. @Override
  86. public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
  87. }
  88. @Override
  89. public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
  90. if (mCameraHelperLeft != null) {
  91. mCameraHelperLeft.removeSurface(holder.getSurface());
  92. }
  93. }
  94. });
  95. }
  96. private void setCameraViewRight() {
  97. svCameraViewRight = findViewById(R.id.svCameraViewRight);
  98. svCameraViewRight.setAspectRatio(DEFAULT_WIDTH, DEFAULT_HEIGHT);
  99. svCameraViewRight.getHolder().addCallback(new SurfaceHolder.Callback() {
  100. @Override
  101. public void surfaceCreated(@NonNull SurfaceHolder holder) {
  102. if (mCameraHelperRight != null) {
  103. mCameraHelperRight.addSurface(holder.getSurface(), false);
  104. }
  105. }
  106. @Override
  107. public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
  108. }
  109. @Override
  110. public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
  111. if (mCameraHelperRight != null) {
  112. mCameraHelperRight.removeSurface(holder.getSurface());
  113. }
  114. }
  115. });
  116. }
  117. private void setCameraViewCenter() {
  118. svCameraViewCenter = findViewById(R.id.svCameraViewCenter);
  119. svCameraViewCenter.setAspectRatio(DEFAULT_WIDTH, DEFAULT_HEIGHT);
  120. svCameraViewCenter.getHolder().addCallback(new SurfaceHolder.Callback() {
  121. @Override
  122. public void surfaceCreated(@NonNull SurfaceHolder holder) {
  123. if (mCameraHelperCenter != null) {
  124. mCameraHelperCenter.addSurface(holder.getSurface(), false);
  125. }
  126. }
  127. @Override
  128. public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
  129. }
  130. @Override
  131. public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
  132. if (mCameraHelperCenter != null) {
  133. mCameraHelperCenter.removeSurface(holder.getSurface());
  134. }
  135. }
  136. });
  137. }
  138. @Override
  139. protected void onStart() {
  140. if (DEBUG) Log.d(TAG, "huahua--onStart:");
  141. super.onStart();
  142. }
  143. @Override
  144. protected void onStop() {
  145. if (DEBUG) Log.d(TAG, "onStop:");
  146. super.onStop();
  147. clearCameraHelper();
  148. }
  149. public void initCameraHelper() {
  150. if (DEBUG) Log.d(TAG, "initCameraHelper:");
  151. if (mCameraHelperLeft == null) {
  152. mCameraHelperLeft = new CameraHelper();
  153. mCameraHelperLeft.setStateCallback(mStateListenerLeft);
  154. }
  155. if (mCameraHelperRight == null) {
  156. mCameraHelperRight = new CameraHelper();
  157. mCameraHelperRight.setStateCallback(mStateListenerRight);
  158. }
  159. if (mCameraHelperCenter == null) {
  160. mCameraHelperCenter = new CameraHelper();
  161. mCameraHelperCenter.setStateCallback(mStateListenerCenter);
  162. }
  163. }
  164. private void clearCameraHelper() {
  165. if (DEBUG) Log.d(TAG, "clearCameraHelper:");
  166. if (mCameraHelperLeft != null) {
  167. mCameraHelperLeft.release();
  168. mCameraHelperLeft = null;
  169. }
  170. if (mCameraHelperRight != null) {
  171. mCameraHelperRight.release();
  172. mCameraHelperRight = null;
  173. }
  174. if (mCameraHelperCenter != null) {
  175. mCameraHelperCenter.release();
  176. mCameraHelperCenter = null;
  177. }
  178. }
  179. private void selectDeviceLeft(final UsbDevice device) {
  180. if (DEBUG) Log.v(TAG, "selectDeviceLeft:device=" + device.getDeviceName());
  181. mUsbDeviceLeft = device;
  182. mAsyncHandler.post(() -> {
  183. waitCanSelectDevice(device);
  184. if (mCameraHelperLeft != null) {
  185. mCameraHelperLeft.selectDevice(device);
  186. }
  187. });
  188. }
  189. private void selectDeviceRight(final UsbDevice device) {
  190. if (DEBUG) Log.v(TAG, "selectDeviceRight:device=" + device.getDeviceName());
  191. mUsbDeviceRight = device;
  192. mAsyncHandler.post(() -> {
  193. waitCanSelectDevice(device);
  194. if (mCameraHelperRight != null) {
  195. mCameraHelperRight.selectDevice(device);
  196. }
  197. });
  198. }
  199. private void selectDeviceCenter(final UsbDevice device) {
  200. if (DEBUG) Log.v(TAG, "selectDeviceCenter:device=" + device.getDeviceName());
  201. mUsbDeviceCenter = device;
  202. mAsyncHandler.post(() -> {
  203. waitCanSelectDevice(device);
  204. if (mCameraHelperCenter != null) {
  205. mCameraHelperCenter.selectDevice(device);
  206. }
  207. });
  208. }
  209. /**
  210. * wait for only one camera need request permission
  211. *
  212. * @param device
  213. */
  214. private void waitCanSelectDevice(UsbDevice device) {
  215. mReadyUsbDeviceList.add(device);
  216. while (mReadyUsbDeviceList.size() > 1) {
  217. mReadyDeviceConditionVariable.block();
  218. mReadyDeviceConditionVariable.close();
  219. }
  220. }
  221. /**
  222. * remove ready camera that wait for select
  223. *
  224. * @param device
  225. */
  226. private void removeSelectedDevice(UsbDevice device) {
  227. mReadyUsbDeviceList.remove(device);
  228. mReadyDeviceConditionVariable.open();
  229. }
  230. private final ICameraHelper.StateCallback mStateListenerLeft = new ICameraHelper.StateCallback() {
  231. private final String LOG_PREFIX = "ListenerLeft#";
  232. @Override
  233. public void onAttach(UsbDevice device) {
  234. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onAttach:");
  235. synchronized (mSync) {
  236. if (mUsbDeviceLeft == null && !device.equals(mUsbDeviceRight) && !device.equals(mUsbDeviceCenter)) {
  237. selectDeviceLeft(device);
  238. mCameraNameLeft.setText("左相机("+device.getDeviceName()+")");
  239. }
  240. }
  241. }
  242. @Override
  243. public void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {
  244. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceOpen:");
  245. if (mCameraHelperLeft != null && device.equals(mUsbDeviceLeft)) {
  246. UVCParam param = new UVCParam();
  247. param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);
  248. mCameraHelperLeft.openCamera(param);
  249. }
  250. removeSelectedDevice(device);
  251. }
  252. @Override
  253. public void onCameraOpen(UsbDevice device) {
  254. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraOpen:");
  255. if (mCameraHelperLeft != null && device.equals(mUsbDeviceLeft)) {
  256. mCameraHelperLeft.startPreview();
  257. Size size = mCameraHelperLeft.getPreviewSize();
  258. if (size != null) {
  259. int width = size.width;
  260. int height = size.height;
  261. //auto aspect ratio
  262. svCameraViewLeft.setAspectRatio(width, height);
  263. }
  264. mCameraHelperLeft.addSurface(svCameraViewLeft.getHolder().getSurface(), false);
  265. }
  266. }
  267. @Override
  268. public void onCameraClose(UsbDevice device) {
  269. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");
  270. if (device.equals(mUsbDeviceLeft)) {
  271. if (mCameraHelperLeft != null) {
  272. mCameraHelperLeft.removeSurface(svCameraViewLeft.getHolder().getSurface());
  273. }
  274. }
  275. }
  276. @Override
  277. public void onDeviceClose(UsbDevice device) {
  278. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");
  279. }
  280. @Override
  281. public void onDetach(UsbDevice device) {
  282. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");
  283. if (device.equals(mUsbDeviceLeft)) {
  284. mUsbDeviceLeft = null;
  285. }
  286. removeSelectedDevice(device);
  287. }
  288. @Override
  289. public void onCancel(UsbDevice device) {
  290. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCancel:");
  291. if (device.equals(mUsbDeviceLeft)) {
  292. mUsbDeviceLeft = null;
  293. }
  294. removeSelectedDevice(device);
  295. }
  296. };
  297. private final ICameraHelper.StateCallback mStateListenerRight = new ICameraHelper.StateCallback() {
  298. private final String LOG_PREFIX = "ListenerRight#";
  299. @Override
  300. public void onAttach(UsbDevice device) {
  301. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onAttach:");
  302. synchronized (mSync) {
  303. if (mUsbDeviceRight == null && !device.equals(mUsbDeviceLeft) && !device.equals(mUsbDeviceCenter)) {
  304. selectDeviceRight(device);
  305. mCameraNameRight.setText("右相机("+device.getDeviceName()+")");
  306. }
  307. }
  308. }
  309. @Override
  310. public void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {
  311. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceOpen:");
  312. if (mCameraHelperRight != null && device.equals(mUsbDeviceRight)) {
  313. UVCParam param = new UVCParam();
  314. param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);
  315. mCameraHelperRight.openCamera(param);
  316. }
  317. removeSelectedDevice(device);
  318. }
  319. @Override
  320. public void onCameraOpen(UsbDevice device) {
  321. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraOpen:");
  322. if (mCameraHelperRight != null && device.equals(mUsbDeviceRight)) {
  323. mCameraHelperRight.startPreview();
  324. Size size = mCameraHelperRight.getPreviewSize();
  325. if (size != null) {
  326. int width = size.width;
  327. int height = size.height;
  328. //auto aspect ratio
  329. svCameraViewRight.setAspectRatio(width, height);
  330. }
  331. mCameraHelperRight.addSurface(svCameraViewRight.getHolder().getSurface(), false);
  332. }
  333. }
  334. @Override
  335. public void onCameraClose(UsbDevice device) {
  336. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");
  337. if (device.equals(mUsbDeviceRight)) {
  338. if (mCameraHelperRight != null) {
  339. mCameraHelperRight.removeSurface(svCameraViewRight.getHolder().getSurface());
  340. }
  341. }
  342. }
  343. @Override
  344. public void onDeviceClose(UsbDevice device) {
  345. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");
  346. }
  347. @Override
  348. public void onDetach(UsbDevice device) {
  349. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");
  350. if (device.equals(mUsbDeviceRight)) {
  351. mUsbDeviceRight = null;
  352. }
  353. removeSelectedDevice(device);
  354. }
  355. @Override
  356. public void onCancel(UsbDevice device) {
  357. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCancel:");
  358. if (device.equals(mUsbDeviceRight)) {
  359. mUsbDeviceRight = null;
  360. }
  361. removeSelectedDevice(device);
  362. }
  363. };
  364. private final ICameraHelper.StateCallback mStateListenerCenter = new ICameraHelper.StateCallback() {
  365. private final String LOG_PREFIX = "ListenerCenter#";
  366. @Override
  367. public void onAttach(UsbDevice device) {
  368. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onAttach:");
  369. synchronized (mSync) {
  370. if (mUsbDeviceCenter == null && !device.equals(mUsbDeviceRight) && !device.equals(mUsbDeviceLeft)) {
  371. selectDeviceCenter(device);
  372. mCameraNameCenter.setText("中间相机("+device.getDeviceName()+")");
  373. }
  374. }
  375. }
  376. @Override
  377. public void onDeviceOpen(UsbDevice device, boolean isFirstOpen) {
  378. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceOpen:");
  379. if (mCameraHelperCenter != null && device.equals(mUsbDeviceCenter)) {
  380. UVCParam param = new UVCParam();
  381. param.setQuirks(UVCCamera.UVC_QUIRK_FIX_BANDWIDTH);
  382. mCameraHelperCenter.openCamera(param);
  383. }
  384. removeSelectedDevice(device);
  385. }
  386. @Override
  387. public void onCameraOpen(UsbDevice device) {
  388. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraOpen:");
  389. if (mCameraHelperCenter != null && device.equals(mUsbDeviceCenter)) {
  390. mCameraHelperCenter.startPreview();
  391. Size size = mCameraHelperCenter.getPreviewSize();
  392. if (size != null) {
  393. int width = size.width;
  394. int height = size.height;
  395. //auto aspect ratio
  396. svCameraViewCenter.setAspectRatio(width, height);
  397. }
  398. mCameraHelperCenter.addSurface(svCameraViewCenter.getHolder().getSurface(), false);
  399. }
  400. }
  401. @Override
  402. public void onCameraClose(UsbDevice device) {
  403. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCameraClose:");
  404. if (device.equals(mUsbDeviceCenter)) {
  405. if (mCameraHelperCenter != null) {
  406. mCameraHelperCenter.removeSurface(svCameraViewCenter.getHolder().getSurface());
  407. }
  408. }
  409. }
  410. @Override
  411. public void onDeviceClose(UsbDevice device) {
  412. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDeviceClose:");
  413. }
  414. @Override
  415. public void onDetach(UsbDevice device) {
  416. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onDetach:");
  417. if (device.equals(mUsbDeviceCenter)) {
  418. mUsbDeviceCenter = null;
  419. }
  420. removeSelectedDevice(device);
  421. }
  422. @Override
  423. public void onCancel(UsbDevice device) {
  424. if (DEBUG) Log.v(TAG, LOG_PREFIX + "onCancel:");
  425. if (device.equals(mUsbDeviceCenter)) {
  426. mUsbDeviceCenter = null;
  427. }
  428. removeSelectedDevice(device);
  429. }
  430. };
  431. }

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/472568
推荐阅读
相关标签
  

闽ICP备14008679号