当前位置:   article > 正文

Android 弃用UVC,采用原生自带Api同时打开双路USB Camera_camera api 调用usbcamera

camera api 调用usbcamera

最终实现的效果如下:

开发板:RK3566

系统:Android11

需求:同时打开两个外接USB相机,屏幕上左右画面要和仪器上左右相机对应 

背景:在项目初期用了UVCCamera的库打开了两个摄像头,对so包也做了一点更改,因为不懂C,尝试改了一点(UVCPreview.cpp里stopPreview方法中加了判断,防止插拔闪退),在RK3566上运行正常且可以热插拔,RK3568上运行正常,插拔闪退。因为我们是用3566,所以就没在3568上研究。后来生产的时候,厂家给的安卓板子有问题,USB信号老是会中断,导致摄像头黑屏,然后闪退,板子厂商后来给换了hub芯片,测了几台,目前正常。担心UVC的库不稳定,且CPU占有率很高(4核占了300%的cpu,应该是软解码导致),所以想用原生的Camera1来打开USB相机,于是,就有了以下方案的尝试。在文章末尾会给两种方式的资源包,仅供参考

1. 实现同时打开两个USB相机

首先获取了摄像头的个数

Camera.getNumberOfCameras()

 发现获取到的数量是0,然后拿了别的USB摄像头是可以的,跟厂商反馈,给了好几版固件试了,终于能获取到数量了,满怀信心的打开,发现只能同时打开一个,想打开另外一个,就得把另一个关掉。怀疑是带宽的问题,电子和其他同事都觉得不应该,只是两个相机不会占用太多带宽。

继续和摄像头厂商反馈,他让我确定我调用的是图像什么格式的,debug获取预览格式是NV21

camera.getParameters().getPreviewFormat()

 关于NV21图像格式属于YUV颜色空间中的YUV420SP格式,简言之就是YUV的一种格式,默认作为Android系统摄像头输出图像格式。

跟厂商反馈后,他们表示要降低30帧可以实现,目前我们对于帧率暂时没太多要求,可以接受。最后固件里给了,1280x720,640x480,640x400的三种分辨率。三种分辨率都可以同时打开两个摄像头,第一步需求完成。

2.固定摄像头显示顺序

打开两个摄像头之后,发现每次开关机,摄像头打开的顺序不一样,Camera类里对于cameraId的描述是从0~相机数量-1来提供的

  1. ...
  2. cameraId – the hardware camera to access, between 0 and getNumberOfCameras()-1.
  3. public static Camera open(int cameraId) {
  4. return new Camera(cameraId);
  5. }

 那目前两个相机的cameraId分别就是0和1,打开顺序就按照0和1来顺序打开

  1. ...
  2. TexturePreviewView previewLeftView = findViewById(R.id.face_preview_view);
  3. TexturePreviewView previewRightView = findViewById(R.id.face_preview_view2);
  4. int cameraLeftId = 0;
  5. int cameraRightId = 1;
  6. cameraControl = new Camera1Control(this, cameraLeftId);
  7. cameraControl.setPreviewView(previewView);
  8. cameraControl.setPreferredPreviewSize(1280,720);
  9. cameraControl.setCameraFacing(ICameraControl.CAMERA_USB);
  10. cameraControl.start();
  11. cameraControl2 = new Camera1Control(this, cameraRightId);
  12. cameraControl2.setPreviewView(previewView);
  13. cameraControl2.setPreferredPreviewSize(1280,720);
  14. cameraControl2.setCameraFacing(ICameraControl.CAMERA_USB);
  15. cameraControl2.start();

然后会出现以下几种情况

a.左Camera镜像显示在左画面上,右Camera显示在右画面上

b. 左Camera显示在右画面上,右Camera镜像显示在左画面上

这两种情况都不是需求想要的, 需求就是左Camera对应显示在左画面,右Camera对应显示在右画面上。查资料通过修改安卓板底层能实现,咨询板子厂商,他们给了一个思路,让adb获取两个相机信息的前后置,是front还是back,然后看屏幕画面的顺序是否会随着读到的顺序变化而变化。

  1. adb shell
  2. dumpsys media.camera

 通过若干次开关机上电发现现象如下:

adb获取到的前后置顺序cameraId打开顺序屏幕对应的现象
front  back0  1a
back  fornt0  1b

分析如下:

a现象其实已经和需求接近了,左摄像头对应左画面,右摄像头对应右画面,只是左边摄像头镜像显示了。所以暂定front、back顺序的话,那cameraId对应就是0、1。

b现象是画面显示位置与左右摄像头是相反的,我们能改的就是把cameraId打开的顺序反一下改为1、0,然后就发现屏幕出现的现象就是a了,修改后表格如下

adb获取到的前后置顺序cameraId打开顺序屏幕对应的现象
front  back0  1a
back  fornt1  0a

这样就能得出结论,在打开相机之前, 可以把front和0对应起来,back和1对应起来。

当两个顺序是front、back时,那cameraLeftId = 0、cameraRightId = 1;

当两个顺序是back、front时,那cameraLeftId = 1、cameraRightId = 0

所以在打开相机前,先对cameraLeftId和cameraRightId赋值,按照这个思路,代码如下:

  1. private void getCameraOrder() {
  2. try {
  3. Process p = Runtime.getRuntime().exec("dumpsys media.camera");
  4. BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
  5. String line;
  6. mCameraIdList.clear();
  7. while((line = in.readLine())!= null) {
  8. String deviceInfo = line.trim();
  9. String key = "Facing:";
  10. if (deviceInfo.contains(key)) {
  11. Log.d("333", deviceInfo);
  12. if (!TextUtils.isEmpty(deviceInfo) && deviceInfo.length() > 8) {
  13. String front = deviceInfo.substring(deviceInfo.indexOf(key) + 8, deviceInfo.length());
  14. Log.d("333", "截取到的值=" + front);
  15. if (front.contains("Front")) {
  16. mCameraLeftId = 0;
  17. mCameraRightId = 1;
  18. Log.d("333", "这只能执行一次" + front + "\nmCameraLeftId=" + mCameraLeftId + "\nmCameraRightId=" + mCameraRightId);
  19. break;
  20. }
  21. if (front.contains("Back")) {
  22. mCameraLeftId = 1;
  23. mCameraRightId = 0;
  24. Log.d("333", "这只能执行一次" + front + "\nmCameraLeftId=" + mCameraLeftId + "\nmCameraRightId=" + mCameraRightId);
  25. break;
  26. }
  27. }
  28. }
  29. //对获取的每行的设备信息进行过滤,获得自己想要的。
  30. }
  31. } catch (Exception e) {
  32. // TODO: handle exception
  33. e.printStackTrace();
  34. }
  35. }
  1. ...
  2. TexturePreviewView previewLeftView = findViewById(R.id.face_preview_view);
  3. TexturePreviewView previewRightView = findViewById(R.id.face_preview_view2);
  4. int cameraLeftId = 0;
  5. int cameraRightId = 1;
  6. //--------在打开前更新一下左右的cameraId
  7. getCameraOrder();
  8. cameraControl = new Camera1Control(this, cameraLeftId);
  9. cameraControl.setPreviewView(previewView);
  10. cameraControl.setPreferredPreviewSize(1280,720);
  11. cameraControl.setCameraFacing(ICameraControl.CAMERA_USB);
  12. cameraControl.start();
  13. cameraControl2 = new Camera1Control(this, cameraRightId);
  14. cameraControl2.setPreviewView(previewView);
  15. cameraControl2.setPreferredPreviewSize(1280,720);
  16. cameraControl2.setCameraFacing(ICameraControl.CAMERA_USB);
  17. cameraControl2.start();

至此,每次上电USB的顺序就和屏幕上能对应起来了。

拓展

在此两个外接USB的基础上,又尝试了多接入一个USB摄像头,发现打不开第三个了,查资料说是安卓板子底层限制最大相机数量是2,想多接入就得改底层板子。 好像是在CameraHal_Module.h类中修改CAMERAS_SUPPORT_MAX数量,搞应用层的不太确定,欢迎大家指正。

下面是两种方式的下载链接

UVC打开方式Demo下载

Camera1打开方式Demo下载

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

闽ICP备14008679号