Android 弃用UVC,采用原生自带Api同时打开双路USB Camera

最终实现的效果如下:

开发板: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来提供的

...
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  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赋值,按照这个思路,代码如下:

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数量,搞应用层的不太确定,欢迎大家指正。

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

UVC打开方式Demo下载

Camera1打开方式Demo下载

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
wen_ov5640_r16_20161114_1744后插入UVC可以打开ov5640和USB摄像头.7z 20161114全志R16配置为前ov5640后UVC的双摄像头 1、 Z:\home\wwt\uvc_r16_project\android\device\softwinner\astar-evb20\configs\camera.cfg 修改: number_of_camera = 1 为: number_of_camera = 2 如果不改这里,兄弟,你在camera这个APP里面是绝对看不到前后摄像头的切换选项的!!!!^_ 修改ov5640的分辨率: used_preview_size = 1 key_support_preview_size = 640x480 key_default_preview_size = 640x480 used_picture_size = 1 key_support_picture_size = 640x480 key_default_picture_size = 640x480 为(根据你驱动里面的摄像头的寄存器配置分辨率而实际修改): used_preview_size = 1 key_support_preview_size = 2592x1936, 2048x1536, 1600x1200, 1280x960, 1280x960, 1024x768, 1920x1080 ,1280x720, 800x600, 640x480 key_default_preview_size = 640x480 used_picture_size = 1 key_support_picture_size = 2592x1936, 2048x1536, 1600x1200, 1280x960, 1280x960, 1024x768, 1920x1080 ,1280x720, 800x600, 640x480 key_default_picture_size = 640x480 2、 Z:\home\wwt\uvc_r16_project\android\device\softwinner\astar-evb20\astar_evb20.mk #include device/softwinner/polaris-common/prebuild/google/products/gms_minimal.mk 注释掉这里干掉Google Play。可以不改。 3、这里讲UVC配置为模块了,请注意UVC所需要的模块的加载顺序。 Z:\home\wwt\uvc_r16_project\android\device\softwinner\astar-evb20\init.sun8i.rc 默认为: #csi module insmod /system/vendor/modules/videobuf-core.ko insmod /system/vendor/modules/videobuf-dma-contig.ko insmod /system/vendor/modules/cam_detect.ko # insmod /system/vendor/modules/actuator.ko # insmod /system/vendor/modules/ad5820_act.ko insmod /system/vendor/modules/cci.ko insmod /system/vendor/modules/vfe_os.ko insmod /system/vendor/modules/vfe_subdev.ko insmod /system/vendor/modules/gc0307.ko # insmod /system/vendor/modules/ov2035.ko insmod /system/vendor/modules/vfe_v4l2.ko 修改为: #csi module # /dev/video0 ov5640 insmod /system/vendor/modules/videobuf-core.ko insmod /system/vendor/modules/videobuf-dma-contig.ko #insmod /system/vendor/modules/cam_detect.ko insmod /system/vendor/modules/cci.ko insmod /system/vendor/modules/vfe_os.ko insmod /system/vendor/modules/vfe_subdev.ko insmod /system/vendor/modules/ov5640.ko insmod /system/vendor/modules/vfe_v4l2.ko # /dev/video1 uvc insmod /system/vendor/modules/videobuf2-core.ko insmod /system/vendor/modules/videobuf2-memops.ko insmod /system/vendor/modules/videobuf2-vmalloc.ko insmod /system/vendor/modules/uvcvideo.ko 4、 Z:\home\wwt\uvc_r16_project\lichee\tools\pack\chips\sun8iw5p1\configs\default\env.cfg 推荐修改: bootdelay=0 为: bootdelay=3 5、不用修改: Z:\home\wwt\uvc_r16_project\lichee\tools\pack\chips\sun8iw5p1\configs\evb-20\sys_config.fex ;-------------------------------------------------------------------------------- ;vip (video input port) configuration ;vip_used: 0:disable 1:enable ;vip_mode: 0:sample one interface to one buffer 1:sample two interface to one buffer ;vip_dev_qty: The quantity of devices linked to capture bus ; ;vip_define_sensor_list: If you want use sensor detect function, please set vip_define_sensor_list = 1, and ; verify that file /system/etc/hawkview/sensor_list_cfg.ini is properly configured! ; ;vip_dev(x)_pos: sensor position, "rear" or "front", if vip_define_sensor_list = 1,vip_dev(x)_pos must be configured! ; ;vip_dev(x)_isp_used 0:not use isp 1:use isp ;vip_dev(x)_fmt: 0:yuv 1:bayer raw rgb ;vip_dev(x)_stby_mode: 0:not shut down power at standby 1:shut down power at standby ;vip_dev(x)_vflip: flip in vertical direction 0:disable 1:enable ;vip_dev(x)_hflip: flip in horizontal direction 0:disable 1:enable ;vip_dev(x)_iovdd: camera module io power handle string, pmu power supply ;vip_dev(x)_iovdd_vol: camera module io power voltage, pmu power supply ;vip_dev(x)_avdd: camera module analog power handle string, pmu power supply ;vip_dev(x)_avdd_vol: camera module analog power voltage, pmu power supply ;vip_dev(x)_dvdd: camera module core power handle string, pmu power supply ;vip_dev(x)_dvdd_vol: camera module core power voltage, pmu power supply ;vip_dev(x)_afvdd: camera module vcm power handle string, pmu power supply ;vip_dev(x)_afvdd_vol: camera module vcm power voltage, pmu power supply ;x indicates the index of the devices which are linked to the same capture bus ;fill voltage in uV, e.g. iovdd = 2.8V, vip_devx_iovdd_vol = 2800000 ;fill handle string as below: ;axp22_eldo3 ;axp22_dldo4 ;axp22_eldo2 ;fill handle string "" when not using any pmu power supply ;-------------------------------------------------------------------------------- [csi0] vip_used = 1 vip_mode = 0 vip_dev_qty = 1 vip_define_sensor_list = 0 vip_csi_pck = port:PE00 vip_csi_mck = port:PE01 vip_csi_hsync = port:PE02 vip_csi_vsync = port:PE03 vip_csi_d0 = port:PE04 vip_csi_d1 = port:PE05 vip_csi_d2 = port:PE06 vip_csi_d3 = port:PE07 vip_csi_d4 = port:PE08 vip_csi_d5 = port:PE09 vip_csi_d6 = port:PE10 vip_csi_d7 = port:PE11 vip_csi_sck = port:PE12 vip_csi_sda = port:PE13 vip_dev0_mname = "ov5640" vip_dev0_pos = "rear" vip_dev0_lane = 1 vip_dev0_twi_id = 2 vip_dev0_twi_addr = 0x78 vip_dev0_isp_used = 0 vip_dev0_fmt = 0 vip_dev0_stby_mode = 1 vip_dev0_vflip = 0 vip_dev0_hflip = 0 vip_dev0_iovdd = "axp22_dldo3" vip_dev0_iovdd_vol = 2800000 vip_dev0_avdd = "" vip_dev0_avdd_vol = 2800000 vip_dev0_dvdd = "" vip_dev0_dvdd_vol = 1800000 vip_dev0_afvdd = "" vip_dev0_afvdd_vol = 2800000 vip_dev0_power_en = vip_dev0_reset = port:PE14 vip_dev0_pwdn = port:PE15 vip_dev0_flash_en = vip_dev0_flash_mode = vip_dev0_af_pwdn = [usbc1] usb_used = 1 usb_drv_vbus_gpio = port:PD12 usb_restrict_gpio = usb_host_init_state = 1 usb_restric_flag = 0 usb_regulator_io = "nocare" usb_regulator_vol = 0 usb_not_suspend = 0 编译内核之后, rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee$ ./build.sh config Welcome to mkscript setup progress All available chips: 0. sun8iw5p1 Choice: 0 All available platforms: 0. android 1. dragonboard 2. linux 3. tina Choice: 0 All available kernel: 0. linux-3.4 Choice: 0 All available boards: 0. bell-one 1. evb 2. evb-20 3. evb-rtl8723bs 4. sc3813r Choice: 2 rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee$ ./build.sh 配置USB摄像头为模块(也可以选择*直接编译进内核): rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee$ cd linux-3.4/ rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee/linux-3.4$ make ARCH=arm menuconfig Device Drivers ---> Multimedia support ---> [*] Video capture adapters ---> 修改: [ ] V4L USB devices ---> 为: [*] V4L USB devices ---> 修改: USB Video Class (UVC) (NEW) 为 USB Video Class (UVC) rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee$ cd linux-3.4/ rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee/linux-3.4$ cd .. rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee$ rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee$ ./build.sh rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/lichee$ cd ../android/ rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/android$ source build/envsetup.sh including device/softwinner/bellone-sc3813r/vendorsetup.sh including device/softwinner/astar-evb20/vendorsetup.sh including device/softwinner/r16-bell-one/vendorsetup.sh including device/softwinner/astar-evb/vendorsetup.sh including device/softwinner/polaris-common/vendorsetup.sh including device/lge/mako/vendorsetup.sh including device/lge/hammerhead/vendorsetup.sh including device/samsung/manta/vendorsetup.sh including device/generic/x86/vendorsetup.sh including device/generic/mips/vendorsetup.sh including device/generic/armv7-a-neon/vendorsetup.sh including device/asus/tilapia/vendorsetup.sh including device/asus/deb/vendorsetup.sh including device/asus/grouper/vendorsetup.sh including device/asus/flo/vendorsetup.sh including sdk/bash_completion/adb.bash rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/android$ lunch You're building on Linux Lunch menu... pick a combo: 1. aosp_arm-eng 2. aosp_x86-eng 3. aosp_mips-eng 4. vbox_x86-eng 5. bellone_sc3813r-eng 6. astar_evb20-eng 7. r16_bell_one-eng 8. astar_evb-eng 9. aosp_mako-userdebug 10. aosp_hammerhead-userdebug 11. aosp_manta-userdebug 12. mini_x86-userdebug 13. mini_mips-userdebug 14. mini_armv7a_neon-userdebug 15. aosp_tilapia-userdebug 16. aosp_deb-userdebug 17. aosp_grouper-userdebug 18. aosp_flo-userdebug Which would you like? [aosp_arm-eng] 6 ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=4.4.2 TARGET_PRODUCT=astar_evb20 TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a-neon TARGET_CPU_VARIANT=cortex-a7 HOST_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty HOST_BUILD_TYPE=release BUILD_ID=KVT49L OUT_DIR=out ============================================ rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/android$ extract-bsp rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/android$ make -j12 rootroot@cm-System-Product-Name:/home/wwt/uvc_r16_project/android$ pack 编译好系统之后,刷机之后请注意先让开发板的Android4.4启动完成之后再插入USB摄像头。 全志R16的android4.4启动之后再插入USB摄像头。 这个配置就可以设置 ov5640为后置摄像头:/dev/video0 UVC为前置摄像头:/dev/video1 如果接上USB摄像头再启动,android是被: ov5640为前置摄像头,有设备节点/dev/video1,打开失败。 UVC为后置摄像头:/dev/video0 原因未知。 参考资料: http://blog.csdn.net/u010257920/article/details/49925807 A20 linux(dragonboard)同时使用Parallel CSI CameraUVC http://blog.csdn.net/guoyihoney/article/details/46966603 A20平台增加camera http://blog.csdn.net/it_fish_man/article/details/17395469 Android usb camera设备添加 http://blog.csdn.net/zmnqazqaz/article/details/49535531 RK3288 uvc摄像头调试 http://blog.csdn.net/edsam49/article/details/8886543 USB Cameraandroid车机上应用前景及初试小结
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值