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


            有的自定义系统,对于自己外接的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. "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 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 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博客

  • 相关阅读:
    微服务架构|go-zero 的自适应熔断器
    面试系列分布式事务:谈谈3PC的理解
    苏州大学:从PostgreSQL到TDengine
    Delphi 编程实现拖动排序并输出到文档
    开启更高效之路,美创科技暗数据发现和数据分类分级系统全新升级
    七月集训(4)贪心
    模拟器抓HTTP/S的包时如何绕过单向证书校验(XP框架)
    程序启动-大数据平台搭建
    水库大坝除险加固安全监测系统解决方案
    Springboot疫苗接种管理系统毕业设计-附源码191451
  • 原文地址:https://blog.csdn.net/lsh670660992/article/details/136261508