RK3288 android 6.0 同时打开两个摄像头

问题描述

  • 平台: RK3288
  • 系统: Android 6.0
  • 需求: 同时打开两个摄像头

业务需求,要支持同时打开多个摄像头,期间遇到一些问题,在这里记录下。

问题分析

支持多摄像头

首先,Android系统默认只支持同时打开一个摄像头,并且最大只识别两个摄像头。所以,为了支持多摄像头,需要修改摄像头相关的 HAL 层。

这个我参考 [AndroidO] [RK3399] Support 4 way camera preview 解决了。patch 如下:

diff --git a/device/rockchip/common/ueventd.rockchip.rc b/device/rockchip/common/ueventd.rockchip.rc
index 7316ebf..e73da8d 100755
--- a/device/rockchip/common/ueventd.rockchip.rc
+++ b/device/rockchip/common/ueventd.rockchip.rc
@@ -19,6 +19,23 @@
 /dev/video1               0660   media      camera
 /dev/video2               0660   media      camera
 /dev/video3               0660   media      camera
+/dev/video4               0660   media      camera
+/dev/video5               0660   media      camera
+/dev/video6               0660   media      camera
+/dev/video7               0660   media      camera
+/dev/video8               0660   media      camera
+/dev/video9               0660   media      camera
+/dev/video10              0660   media      camera
+/dev/video11              0660   media      camera
+/dev/video12              0660   media      camera
+/dev/video13              0660   media      camera
+/dev/video14              0660   media      camera
+/dev/video15              0660   media      camera
+/dev/video16              0660   media      camera
+/dev/video17              0660   media      camera
+/dev/video18              0660   media      camera
+/dev/video19              0660   media      camera
+/dev/video20              0660   media      camera
 /dev/pmem_cam             0660   system     camera
 /dev/vpu                  0660   system     system
 /dev/vpu_service          0666   media      media
diff --git a/hardware/rockchip/camera/CameraHal/CameraHal_Module.cpp b/hardware/rockchip/camera/CameraHal/CameraHal_Module.cpp
index 3365339..012d14e 100755
--- a/hardware/rockchip/camera/CameraHal/CameraHal_Module.cpp
+++ b/hardware/rockchip/camera/CameraHal/CameraHal_Module.cpp
@@ -712,9 +712,10 @@ int usb_camera_hotplug(void)
                      (strcmp(usbcameraPlug, "remove") == 0);
     return plugstate;
 }
-
+//modify by fujianyong for [Supporting multiple cameras] start
 int camera_get_number_of_cameras(void)
 {
+    char cam_sys[40];
     char cam_path[20];
     char cam_num[3],i;
     int cam_cnt=0,fd=-1,rk29_cam[CAMERAS_SUPPORT_MAX];
@@ -770,9 +771,11 @@ int camera_get_number_of_cameras(void)
         delete camEngVerItf;
 
     }
-    
-    memset(&camInfoTmp[0],0x00,sizeof(rk_cam_info_t));
-    memset(&camInfoTmp[1],0x00,sizeof(rk_cam_info_t));
+    for(int i=0;i<CAMERAS_SUPPORT_MAX;i++){
+        memset(&camInfoTmp[i],0x00,sizeof(rk_cam_info_t));
+    }
+    //memset(&camInfoTmp[0],0x00,sizeof(rk_cam_info_t));
+    //memset(&camInfoTmp[1],0x00,sizeof(rk_cam_info_t));
 
     profiles = camera_board_profiles::getInstance();
     nCamDev = profiles->mDevieVector.size();
@@ -787,18 +790,18 @@ int camera_get_number_of_cameras(void)
             if(profiles->mDevieVector[i]->mIsConnect==1){
                 rk_sensor_info *pSensorInfo = &(profiles->mDevieVector[i]->mHardInfo.mSensorInfo);
                 
-                camInfoTmp[cam_cnt&0x01].pcam_total_info = profiles->mDevieVector[i];     
-                strncpy(camInfoTmp[cam_cnt&0x01].device_path, pSensorInfo->mCamsysDevPath, sizeof(camInfoTmp[cam_cnt&0x01].device_path));
-                strncpy(camInfoTmp[cam_cnt&0x01].driver, pSensorInfo->mSensorDriver, sizeof(camInfoTmp[cam_cnt&0x01].driver));
+                camInfoTmp[cam_cnt].pcam_total_info = profiles->mDevieVector[i];
+                strncpy(camInfoTmp[cam_cnt].device_path, pSensorInfo->mCamsysDevPath, sizeof(camInfoTmp[cam_cnt].device_path));
+                strncpy(camInfoTmp[cam_cnt].driver, pSensorInfo->mSensorDriver, sizeof(camInfoTmp[cam_cnt].driver));
                 unsigned int SensorDrvVersion = profiles->mDevieVector[i]->mLoadSensorInfo.mpI2cInfo->sensor_drv_version;
                 memset(version,0x00,sizeof(version));
                 sprintf(version,"%d.%d.%d",((SensorDrvVersion&0xff0000)>>16),
                         ((SensorDrvVersion&0xff00)>>8),SensorDrvVersion&0xff);
                          
                 if(pSensorInfo->mFacing == RK_CAM_FACING_FRONT){     
-                    camInfoTmp[cam_cnt&0x01].facing_info.facing = CAMERA_FACING_FRONT;                    
+                    camInfoTmp[cam_cnt].facing_info.facing = CAMERA_FACING_FRONT;
                 } else {
-                    camInfoTmp[cam_cnt&0x01].facing_info.facing = CAMERA_FACING_BACK;
+                    camInfoTmp[cam_cnt].facing_info.facing = CAMERA_FACING_BACK;
                 } 
 
                 memset(sensor_ver,0x00,sizeof(sensor_ver));
@@ -808,7 +811,7 @@ int camera_get_number_of_cameras(void)
                     sprintf(sensor_ver,"%s",pSensorInfo->mSensorName);                
                 property_set(sensor_ver, version);    
                 
-                camInfoTmp[cam_cnt&0x01].facing_info.orientation = pSensorInfo->mOrientation;
+                camInfoTmp[cam_cnt].facing_info.orientation = pSensorInfo->mOrientation;
                 cam_cnt++;
 
                 unsigned int CamsysDrvVersion = profiles->mDevieVector[i]->mCamsysVersion.drv_ver;
@@ -833,13 +836,34 @@ int camera_get_number_of_cameras(void)
             i++;
         }
         
-        for (i=0; i<10; i++) {
+        for (i=0; i<20; i++) {
             cam_path[0] = 0x00;
-            unsigned int pix_format_tmp = V4L2_PIX_FMT_NV12;
-            strcat(cam_path, CAMERA_DEVICE_NAME);
+            //unsigned int pix_format_tmp = V4L2_PIX_FMT_NV12;
+            //strcat(cam_path, CAMERA_DEVICE_NAME);
+            cam_sys[0] = 0x00;
+            strcat(cam_sys, CAM_SYS_NAME);
             sprintf(cam_num, "%d", i);
+            strcat(cam_sys,cam_num);
+            strcat(cam_sys,"/index");
+            FILE* ifp;
+            ifp = fopen(cam_sys, "r");
+            if (ifp == NULL){
+                LOGD("fail to open sys file:%s",cam_sys);
+                continue;
+            }
+            unsigned char index;
+            fread(&index, sizeof(char),1, ifp);
+            fclose(ifp);
+            LOGD("open %s index %x",cam_sys,index);
+            if(index == 0x31){
+                LOGD("%s wrong index continue",cam_sys);
+                continue;
+            }
+            strcat(cam_path, CAMERA_DEVICE_NAME);
+
             strcat(cam_path,cam_num);
             fd = open(cam_path, O_RDONLY);
+            unsigned int pix_format_tmp = V4L2_PIX_FMT_NV12;
             if (fd < 0) {
                 LOGE("Open %s failed! strr: %s",cam_path,strerror(errno));
                 break;
@@ -856,31 +880,31 @@ int camera_get_number_of_cameras(void)
                 LOGD("Video device(%s): video capture not supported.\n",cam_path);
             } else {
                 rk_cam_total_info* pNewCamInfo = new rk_cam_total_info();
-                memset(camInfoTmp[cam_cnt&0x01].device_path,0x00, sizeof(camInfoTmp[cam_cnt&0x01].device_path));
-                strcat(camInfoTmp[cam_cnt&0x01].device_path,cam_path);
-                memset(camInfoTmp[cam_cnt&0x01].fival_list,0x00, sizeof(camInfoTmp[cam_cnt&0x01].fival_list));
-                memcpy(camInfoTmp[cam_cnt&0x01].driver,capability.driver, sizeof(camInfoTmp[cam_cnt&0x01].driver));
-                camInfoTmp[cam_cnt&0x01].version = capability.version;
+                memset(camInfoTmp[cam_cnt].device_path,0x00, sizeof(camInfoTmp[cam_cnt].device_path));
+                strcat(camInfoTmp[cam_cnt].device_path,cam_path);
+                memset(camInfoTmp[cam_cnt].fival_list,0x00, sizeof(camInfoTmp[cam_cnt].fival_list));
+                memcpy(camInfoTmp[cam_cnt].driver,capability.driver, sizeof(camInfoTmp[cam_cnt].driver));
+                camInfoTmp[cam_cnt].version = capability.version;
                 if (strstr((char*)&capability.card[0], "front") != NULL) {
-                    camInfoTmp[cam_cnt&0x01].facing_info.facing = CAMERA_FACING_FRONT;
+                    camInfoTmp[cam_cnt].facing_info.facing = CAMERA_FACING_FRONT;
 #ifdef LAPTOP
                 } else if (strstr((char*)&capability.card[0], "HP HD") != NULL
                     || strstr((char*)&capability.card[0], "HP IR")) {
-                    camInfoTmp[cam_cnt&0x01].facing_info.facing = CAMERA_FACING_FRONT;
+                    camInfoTmp[cam_cnt].facing_info.facing = CAMERA_FACING_FRONT;
                     if (strstr((char*)&capability.card[0], "HP IR"))
                         gCamerasUnavailabled++;
-                    gUsbCameraNames[cam_cnt&0x01] = String8((char*)&capability.card[0]);
-                    LOGD("Camera %d name: %s", (cam_cnt&0x01), gUsbCameraNames[cam_cnt&0x01].string());
+                    gUsbCameraNames[cam_cnt] = String8((char*)&capability.card[0]);
+                    LOGD("Camera %d name: %s", (cam_cnt), gUsbCameraNames[cam_cnt].string());
 #endif
                 } else {
-                    camInfoTmp[cam_cnt&0x01].facing_info.facing = CAMERA_FACING_BACK;
+                    camInfoTmp[cam_cnt].facing_info.facing = CAMERA_FACING_BACK;
                 }  
                 ptr = strstr((char*)&capability.card[0],"-");
                 if (ptr != NULL) {
                     ptr++;
-                    camInfoTmp[cam_cnt&0x01].facing_info.orientation = atoi(ptr);
+                    camInfoTmp[cam_cnt].facing_info.orientation = atoi(ptr);
                 } else {
-                    camInfoTmp[cam_cnt&0x01].facing_info.orientation = 0;
+                    camInfoTmp[cam_cnt].facing_info.orientation = 0;
                 }
 
                 memset(version,0x00,sizeof(version));
@@ -1168,7 +1192,7 @@ int camera_get_number_of_cameras(void)
                 camInfoTmp[cam_cnt].pcam_total_info = pNewCamInfo;
                 cam_cnt++;
                 if (cam_cnt >= CAMERAS_SUPPORT_MAX)
-                    i = 10;
+                    i = 20;
             }
     loop_continue:
             if (fd > 0) {
@@ -1215,8 +1239,11 @@ int camera_get_number_of_cameras(void)
     }
     #endif
     
-    memcpy(&gCamInfos[0], &camInfoTmp[0], sizeof(rk_cam_info_t));
-    memcpy(&gCamInfos[1], &camInfoTmp[1], sizeof(rk_cam_info_t));
+    //memcpy(&gCamInfos[0], &camInfoTmp[0], sizeof(rk_cam_info_t));
+    //memcpy(&gCamInfos[1], &camInfoTmp[1], sizeof(rk_cam_info_t));
+    for(int i=0;i<CAMERAS_SUPPORT_MAX;i++){
+        memcpy(&gCamInfos[i], &camInfoTmp[i], sizeof(rk_cam_info_t));
+    }
 
 
     property_get("ro.sf.hwrotation", property, "0");
@@ -1240,7 +1267,7 @@ camera_get_number_of_cameras_end:
 #else
     return gCamerasNumber;
 #endif
-}
+}//modify by fujianyong for [Supporting multiple cameras] end
 
 #if 0
 int camera_get_number_of_cameras(void)
diff --git a/hardware/rockchip/camera/CameraHal/CameraHal_Module.h b/hardware/rockchip/camera/CameraHal/CameraHal_Module.h
index 45c81ec..3927ddf 100755
--- a/hardware/rockchip/camera/CameraHal/CameraHal_Module.h
+++ b/hardware/rockchip/camera/CameraHal/CameraHal_Module.h
@@ -11,13 +11,14 @@ using namespace android;
 #define CAMERA_DEFAULT_PREVIEW_FPS_MIN    8000        //8 fps
 #define CAMERA_DEFAULT_PREVIEW_FPS_MAX    15000
 #endif
-#define CAMERAS_SUPPORT_MAX             2
+#define CAMERAS_SUPPORT_MAX             4
 #if defined(TARGET_RK3399)
-    #define CAMERAS_SUPPORTED_SIMUL_MAX     2
+    #define CAMERAS_SUPPORTED_SIMUL_MAX     4
 #else
     #define CAMERAS_SUPPORTED_SIMUL_MAX     1
 #endif
 #define CAMERA_DEVICE_NAME              "/dev/video"
+#define CAM_SYS_NAME                    "/sys/class/video4linux/video"
 #define CAMERA_MODULE_NAME              "RK29_ICS_CameraHal_Module"
 
 typedef struct rk_cam_info_s {

通过该 patch 就支持了4个摄像头。

带宽不足

加入以上patch后,确实可以同时识别多个摄像头,但是同时预览不一定成功,我测试了多组摄像头,不同组合结果不一样,有成功的,也有失败的。

失败的时候,会报以下错误。

uvcvideo: Failed to submit URB 0 (-28).

错误码 28 说明空间不足,这个可以从头文件 errno.h 中查找到其定义。搜索发现与 USB 带宽分配相关。使用 lsusb 可以看到

Bus 001 Device 002: ID 1a40:0101
Bus 003 Device 002: ID 0bda:0179
Bus 001 Device 001: ID 1d6b:0002
Bus 002 Device 001: ID 1d6b:0002
Bus 003 Device 001: ID 1d6b:0002
Bus 001 Device 003: ID 058f:5608
Bus 001 Device 004: ID 058f:5608

最后两个对应摄像头,使用的是同一个usb bus,对应同一个usb控制器。

usb 2.0 速率为480Mbps,一个摄像头占用带宽可以粗略估算:长(640)*宽(480)*帧率(30)*像素点数据长度(24) + 协议头部

调试许久,最后通过添加kernel调试代码,打印带宽信息,对比成功和失败的案例,最终确定是出错摄像头默认配置带宽过高导致的,解决方案如下:

diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 669d81c..b1b381e 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1684,6 +1684,11 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
                /* Isochronous endpoint, select the alternate setting. */
                bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
 
+               if (bandwidth > UVC_LIMITED_BANDWIDTH) {
+                       printk(KERN_ERR "UVC_DBG: limit bandwidth from %d to %d \n",
+                              bandwidth, UVC_LIMITED_BANDWIDTH);
+                       bandwidth = UVC_LIMITED_BANDWIDTH;
+               }
                if (bandwidth == 0) {
                        uvc_trace(UVC_TRACE_VIDEO, "Device requested null "
                                "bandwidth, defaulting to lowest.\n");
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 033c775..86d11f4 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -142,6 +142,9 @@
 #define UVC_FMT_FLAG_COMPRESSED                0x00000001
 #define UVC_FMT_FLAG_STREAM            0x00000002
 
+/* Limit bandwith */
+#define UVC_LIMITED_BANDWIDTH   800
+
 /* ------------------------------------------------------------------------
  * Structures.
  */

以上 bandwidth 在出错情况下为 3072, 不出错的摄像头对应 800, 因此我将其限制在 800, 重新编译后解决问题。

参考

  1. [AndroidO] [RK3399] Support 4 way camera preview
  2. uvc camera在usb带宽不足的情况下,如何正常出图