(记录android9以后调试所遇到的常见问题,有错请批评指正)
UVC全称为USB video(device) class,是微软与另外几家设备厂商联合推出的为usb视频捕获设备定义的协议标准;所以说UVC仅仅是usb规范协议中设备类规范的其中一种,是用作usb接口的视频设备的一个统一的数据交换规范。
插入USB摄像头会生成对应的video节点,使用如下指令,可以列举出插入的usb设备:
rk3399:/ # grep -H '' /sys/class/video4linux/video*/name
grep -H '' /sys/class/video4linux/video*/name
/sys/class/video4linux/video0/name:rkisp1_mainpath
/sys/class/video4linux/video1/name:rkisp1_selfpath
/sys/class/video4linux/video10/name:YHX5M //第一个usb摄像头
/sys/class/video4linux/video11/name:YHX5M
/sys/class/video4linux/video12/name:USB 2.0 PC Camera //第二个usb摄像头
/sys/class/video4linux/video13/name:USB 2.0 PC Camera
.................
USB摄像头支持的格式有这几种:mjpg格式、yuv格式和h264;usb摄像头能够支持多种不同的分辨率,而且640x480是非常常见的分辨率;可以使用如下指令查询USB摄像头支持的格式,分辨率及帧率。USB camera的相机帧率一般是会根据光照自动调节帧率的;你用手电筒照下,帧率应该就会高了;如果你们需要固定帧率,需要USB camera的厂商控制;
v4l2-ctl -d /dev/videoX --list-formats-ext (videox 就是对应的usb设备节点)
新的SDK都有支持usb摄像头的插拔,一般应用在正常退出时会release摄像头,如果没有释放,再去用相机app打开摄像头时,会导致摄像头的video节点后移,出现打开异常现象。
一般这种插拔问题,会出现在旧版本的,可能是预览中间断开,没有执行正常退出,没有wakeup这个wait_event,所以一直休着;等待超时发现有冗余未释放camera资源,及时通知释放就好了。
常见摄像头打不开问题
首先配置方面先确保如下几点,具体可以参考文档 USB_UVC_Integrated_Cameras;
(1)以下设置是否都为true?/device/rockchip/rk3xxx/BoardConfig.mkBOARD_CAMERA_SUPPORT := trueBOARD_CAMERA_SUPPORT_EXT := true(2)cat /vendor/etc/vintf/manifest.xml | grep external //确定是否有external信息如果没有,则进行添加 /device/rockchip/rk3399/manifest.xml<interface><name>ICameraProvider</name><instance>legacy/0</instance><instance>external/0</instance> //有该配置项吗? </interface>(3) 其它型号的usb摄像头是否也打不开? 也有可能是摄像头的问题,所以试试usb camera 插电脑(PC)上,看是否能正常预览出图;可以下载一个usbcamera的apk去看看:adb install usbcamera的apk
其次,dumpsys media.camera看下是否注册上摄像头;若注册上了,摄像头还打不开,则需要具体logcat进行分析;
将下面三个文件的LOG_NDEBUG宏定义注释去掉
hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp
hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
hardware/interfaces/camera/device/3.4/default/ExternalCameraUtils.cpp
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
然后在hardware/interfaces/camera/device/3.4/default$ mm -j12 ;编译生成:camera.device@3.4-external-impl.so 在 vendor/lib目录下,所以修改库后,直接编译替换这个库即可!然后执行指令抓logcat
logcat -c && pkill camera* && pkill provider* && logcat
打开相机抓份logcat
一般打不开时,很大概率是external_camera_config.xml 文件中没有添加usb camera的相关分辨率以及帧率;在xml中也可以修改旋转角度以及jpeg buffer。USB分辨率,例如预览想要3840x2160,拍照也想要3840x2160,那么需要在xml文件中将MaxJpegBufferSize改大一点,默认是3MB(1MB=1024KB,1KB=1024B, 1B=8bit),可以修改成4MB,5MB.
<Orientation degree="90"/>
<MaxJpegBufferSize bytes="3145728"/> <!-- 3MB (~= 1080p YUV420) -->
ps:3MB = 3*1024 KB = 3*1024*1024 B = 3145728 B
查看内核log:表示usb设备已经识别到了;可以找到相关的video节点,用v4l2工具取流,看是否正常;
[ 194.108702] usb 1-1.3: new high-speed USB device number 5 using ehci-platform
[ 194.304772] usb 1-1.3: New USB device found, idVendor=046d, idProduct=082b, bcdDevice=28.25
[ 194.304899] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 194.304924] usb 1-1.3: Product: Webcam C170
[ 194.304946] usb 1-1.3: Manufacturer:
v4l2-ctl --verbose -d /dev/videox --set-fmt-video=width=640,height=480,pixelformat='MJPG' --stream-mmap=4 --set-selection=target=crop,flags=0,top=0,left=0,width=640,height=480
前后摄设置
默认是后摄,前摄如下修改
hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cppconst uint8_t facing = ANDROID_LENS_FACING_FRONT; //BACKUPDATE(ANDROID_LENS_FACING, &facing, 1);
前后摄切换
1.android9,android10如下修改
/hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -309,7 +309,15 @@ status_t ExternalCameraDevice::initDefaultCharsKeys(UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,&opticalStabilizationMode, 1);- const uint8_t facing = ANDROID_LENS_FACING_BACK;
+ const char* dev = mCameraId.c_str();
+ int index = (int) (*(dev + (strlen(dev) - 1)) - '0');
+ ALOGE("dev:%s index:%d", dev, index);
+ const uint8_t facing = (index / 2) % 2 ? ANDROID_LENS_FACING_FRONT : ANDROID_LENS_FACING_BACK;UPDATE(ANDROID_LENS_FACING, &facing, 1);
2.android11及12如下修改
/hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -309,7 +309,15 @@ status_t ExternalCameraDevice::initDefaultCharsKeys(UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,&opticalStabilizationMode, 1);- const uint8_t facing = ANDROID_LENS_FACING_BACK;
+ const char* dev = mCameraId.c_str();
+ int index = atoi(dev);
+ ALOGE("dev:%s index:%d", dev, index);
+ const uint8_t facing = (index / 2) % 2 ? ANDROID_LENS_FACING_FRONT : ANDROID_LENS_FACING_BACK;UPDATE(ANDROID_LENS_FACING, &facing, 1);
录像问题
录像分辨率及帧率在/device/rocchip/下的media_profiles_defaults.xml 里配置,编译时会拷到 /vendor/etc/media_profiles_V1_0.xml
xml中通过id来识别摄像头即,根据实际情况可以添加或删除分辨率
## 录像问题 录像分辨率及帧率在/device/rocchip/下的media_profiles_defaults.xml
里配置,编译时会拷到 /vendor/etc/media_profiles_V1_0.xml xml中通过id来识别摄像头即,根据实际情况可以添加或删除分辨率
<CamcorderProfiles cameraId="0">
<CamcorderProfiles cameraId="1">..........<EncoderProfile quality="480p" fileFormat="mp4" duration="30"><Video codec="h264"bitRate="3000000" //录像模糊时,可以增大bitRatewidth="640"height="480"frameRate="25" />..........</EncoderProfile>
例如usb摄像头是480p的,但是你录像时默认打开的分辨率为1080p,因此切换到录像时,会出现Can't connect to the camera报错,此时可以在xml中将对应sensor模块的1080p分辨率去除。
USB摄像头拍照是正常的,但是录像的时候会提示报错;这种有可能是帧率不对,不支持导致的,具体可以看logcat。例如:device/rockchip里的media_profiles_default.xml 里framerate 改成25就解决了(dumpsys media.camera 里 可以看到支持帧率有25 但是没30帧)
镜像问题
Hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp Hardware/interfaces/camera/device/3.4/default/ExternalCameraDevice.cpp
可以试下ExternalCameraDevice.cpp里 facing 改为BACK 后,看下预览是否会镜像了;
预览、拍照、录像这三种情况都会有镜像相关的问题(有相关patch)
1)预览镜像问题,在代码中修改成前置或后置就可以解决;
2)拍照镜像问题,libyuv::I420Scale 和 libyuv::I420MIrror 这段代码才是控制拍照镜像和翻转的
3)录像镜像问题:这是控制录像视频的mirror,即把 rga_nv12_scale_crop 里的 false 改成 (halBuf.usage & BufferUsage::VIDEO_ENCODER)
拉伸问题
USB摄像头预览变形,换其他型号的USB摄像头也一样;看log picturesize:1920x1080,previewBuffer:1920x1080 预览分辨率为1080P,整体屏幕也是1080P,为什么会拉伸收缩变形?
需要注意的是摄像头成像长边要跟显示屏长边平行摆放;
默认竖屏设备 前摄 orientation 要为270,后摄为90;
默认横屏设备 前后摄 orientation都为0;
因此在xml中修改下orientation即可。
video节点权限问题
抓取logat后,关键字查询 E/CAM 发现没有权限
06-21 18:19:17.164 E/CamPvdr@2.4-external( 256): deviceAdded open v4l2 device /dev/video12 failed:Permission denied
06-21 18:19:17.165 E/CamPvdr@2.4-external( 256): deviceAdded open v4l2 device /dev/video13 failed:Permission denied
ls -l /dev/video* 查看下权限
crw-rw---- 1 media camera 81, 10 2022-06-22 09:47 /dev/video10
crw-rw---- 1 media camera 81, 11 2022-06-22 09:47 /dev/video11
crw------- 1 root root 81, 16 2022-06-22 09:47 /dev/video12
crw------- 1 root root 81, 17 2022-06-22 09:47 /dev/video13
如下修改后即可
/device/rockchip/common/ueventd.rockchip.rc
#for external camera
/dev/video10 0660 media camera
/dev/video11 0660 media camera
+ /dev/video12 0660 media camera
+ /dev/video13 0660 media camera
dqbuf卡住问题
主要是针对usb摄像头插拔导致的一系列问题,例如插拔usb摄像头时,导致camera服务卡死,画面卡着不动;正常情况下插拔摄像头后预览画面可以恢复的。这种可能是预览中间断开,没有执行正常退出,没有wakeup这个wait_event,所以一直休着;等待超时发现有冗余未释放camera资源,应及时通知释放。(3588更新代码,会有这个补丁的)
此外还有可能要加上0001-DQBUF-add-select.patch,一般拔掉usb摄像头后,apk会弹窗报错自动退出;如果没有弹框报错,说明dqbuf还是被卡住了,线程得不到释放,导致apk出现anr;要检查下补丁是否有打进去,是否生效了。
后面有空介绍这些: