赞
踩
最终实现的效果如下:
开发板:RK3566
系统:Android11
需求:同时打开两个外接USB相机,屏幕上左右画面要和仪器上左右相机对应
背景:在项目初期用了UVCCamera的库打开了两个摄像头,对so包也做了一点更改,因为不懂C,尝试改了一点(UVCPreview.cpp里stopPreview方法中加了判断,防止插拔闪退),在RK3566上运行正常且可以热插拔,RK3568上运行正常,插拔闪退。因为我们是用3566,所以就没在3568上研究。后来生产的时候,厂家给的安卓板子有问题,USB信号老是会中断,导致摄像头黑屏,然后闪退,板子厂商后来给换了hub芯片,测了几台,目前正常。担心UVC的库不稳定,且CPU占有率很高(4核占了300%的cpu,应该是软解码导致),所以想用原生的Camera1来打开USB相机,于是,就有了以下方案的尝试。在文章末尾会给两种方式的资源包,仅供参考
首先获取了摄像头的个数
Camera.getNumberOfCameras()
发现获取到的数量是0,然后拿了别的USB摄像头是可以的,跟厂商反馈,给了好几版固件试了,终于能获取到数量了,满怀信心的打开,发现只能同时打开一个,想打开另外一个,就得把另一个关掉。怀疑是带宽的问题,电子和其他同事都觉得不应该,只是两个相机不会占用太多带宽。
继续和摄像头厂商反馈,他让我确定我调用的是图像什么格式的,debug获取预览格式是NV21
camera.getParameters().getPreviewFormat()
关于NV21图像格式属于YUV颜色空间中的YUV420SP格式,简言之就是YUV的一种格式,默认作为Android系统摄像头输出图像格式。
跟厂商反馈后,他们表示要降低30帧可以实现,目前我们对于帧率暂时没太多要求,可以接受。最后固件里给了,1280x720,640x480,640x400的三种分辨率。三种分辨率都可以同时打开两个摄像头,第一步需求完成。
打开两个摄像头之后,发现每次开关机,摄像头打开的顺序不一样,Camera类里对于cameraId的描述是从0~相机数量-1来提供的
- ...
- cameraId – the hardware camera to access, between 0 and getNumberOfCameras()-1.
-
- public static Camera open(int cameraId) {
- return new Camera(cameraId);
- }
那目前两个相机的cameraId分别就是0和1,打开顺序就按照0和1来顺序打开
- ...
- TexturePreviewView previewLeftView = findViewById(R.id.face_preview_view);
- TexturePreviewView previewRightView = findViewById(R.id.face_preview_view2);
-
- int cameraLeftId = 0;
- int cameraRightId = 1;
-
- cameraControl = new Camera1Control(this, cameraLeftId);
- cameraControl.setPreviewView(previewView);
- cameraControl.setPreferredPreviewSize(1280,720);
- cameraControl.setCameraFacing(ICameraControl.CAMERA_USB);
- cameraControl.start();
-
- cameraControl2 = new Camera1Control(this, cameraRightId);
- cameraControl2.setPreviewView(previewView);
- cameraControl2.setPreferredPreviewSize(1280,720);
- cameraControl2.setCameraFacing(ICameraControl.CAMERA_USB);
- cameraControl2.start();
然后会出现以下几种情况
a.左Camera镜像显示在左画面上,右Camera显示在右画面上
b. 左Camera显示在右画面上,右Camera镜像显示在左画面上
这两种情况都不是需求想要的, 需求就是左Camera对应显示在左画面,右Camera对应显示在右画面上。查资料通过修改安卓板底层能实现,咨询板子厂商,他们给了一个思路,让adb获取两个相机信息的前后置,是front还是back,然后看屏幕画面的顺序是否会随着读到的顺序变化而变化。
- adb shell
- dumpsys media.camera
通过若干次开关机上电发现现象如下:
adb获取到的前后置顺序 | cameraId打开顺序 | 屏幕对应的现象 |
front back | 0 1 | a |
back fornt | 0 1 | b |
分析如下:
a现象其实已经和需求接近了,左摄像头对应左画面,右摄像头对应右画面,只是左边摄像头镜像显示了。所以暂定front、back顺序的话,那cameraId对应就是0、1。
b现象是画面显示位置与左右摄像头是相反的,我们能改的就是把cameraId打开的顺序反一下改为1、0,然后就发现屏幕出现的现象就是a了,修改后表格如下
adb获取到的前后置顺序 | cameraId打开顺序 | 屏幕对应的现象 |
front back | 0 1 | a |
back fornt | 1 0 | a |
这样就能得出结论,在打开相机之前, 可以把front和0对应起来,back和1对应起来。
当两个顺序是front、back时,那cameraLeftId = 0、cameraRightId = 1;
当两个顺序是back、front时,那cameraLeftId = 1、cameraRightId = 0
所以在打开相机前,先对cameraLeftId和cameraRightId赋值,按照这个思路,代码如下:
- private void getCameraOrder() {
- try {
- Process p = Runtime.getRuntime().exec("dumpsys media.camera");
- BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
- String line;
- mCameraIdList.clear();
- while((line = in.readLine())!= null) {
- String deviceInfo = line.trim();
- String key = "Facing:";
- if (deviceInfo.contains(key)) {
- Log.d("333", deviceInfo);
- if (!TextUtils.isEmpty(deviceInfo) && deviceInfo.length() > 8) {
- String front = deviceInfo.substring(deviceInfo.indexOf(key) + 8, deviceInfo.length());
- Log.d("333", "截取到的值=" + front);
- if (front.contains("Front")) {
- mCameraLeftId = 0;
- mCameraRightId = 1;
- Log.d("333", "这只能执行一次" + front + "\nmCameraLeftId=" + mCameraLeftId + "\nmCameraRightId=" + mCameraRightId);
- break;
- }
- if (front.contains("Back")) {
- mCameraLeftId = 1;
- mCameraRightId = 0;
- Log.d("333", "这只能执行一次" + front + "\nmCameraLeftId=" + mCameraLeftId + "\nmCameraRightId=" + mCameraRightId);
- break;
- }
- }
- }
- //对获取的每行的设备信息进行过滤,获得自己想要的。
- }
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- ...
- TexturePreviewView previewLeftView = findViewById(R.id.face_preview_view);
- TexturePreviewView previewRightView = findViewById(R.id.face_preview_view2);
-
- int cameraLeftId = 0;
- int cameraRightId = 1;
-
- //--------在打开前更新一下左右的cameraId
-
- getCameraOrder();
-
- cameraControl = new Camera1Control(this, cameraLeftId);
- cameraControl.setPreviewView(previewView);
- cameraControl.setPreferredPreviewSize(1280,720);
- cameraControl.setCameraFacing(ICameraControl.CAMERA_USB);
- cameraControl.start();
-
- cameraControl2 = new Camera1Control(this, cameraRightId);
- cameraControl2.setPreviewView(previewView);
- cameraControl2.setPreferredPreviewSize(1280,720);
- cameraControl2.setCameraFacing(ICameraControl.CAMERA_USB);
- cameraControl2.start();
至此,每次上电USB的顺序就和屏幕上能对应起来了。
在此两个外接USB的基础上,又尝试了多接入一个USB摄像头,发现打不开第三个了,查资料说是安卓板子底层限制最大相机数量是2,想多接入就得改底层板子。 好像是在CameraHal_Module.h类中修改CAMERAS_SUPPORT_MAX数量,搞应用层的不太确定,欢迎大家指正。
下面是两种方式的下载链接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。