曾经在全志平台上调试过UVC摄像头,当时调试过程比较流畅,丝毫没有碰上异常情况,这一次在RK上碰到较大的困难,下面介绍一下我的调试过程。
首先,不用说当然在内核配置中配置上UVC摄像头,重新编译内核,烧录。
-
- Device Drivers --->
- <*> Multimedia support --->
- <*> Video For Linux
- [*] Enable Video For Linux API 1 (DEPRECATED)
- [*] Video capture adapters --->
- [*] V4L USB devices --->
- <*> USB Video Class (UVC)
- [*] UVC input events device support
然后查看内核信息,cat /proc/kmsg 然后接上摄像头,会看到类似的设备信息,说明我们的摄像头已经可以正常使用了。
- usb 1-1.1: new full speed USB device using address 3
- usb 1-1.1: New USB device found, idVendor=0ac8, idProduct=3450
- usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
- usb 1-1.1: Product: Deasy USB2.0 Camera
- uvcvideo: Found UVC 1.00 device Deasy USB2.0 Camera (0ac8:3450)
接着我们可以在/dev 目录下看到 videoX 的节点。
然后,尝试一下用系统相机看看是否能点亮摄像头,这里提示我无法连接上摄像头。
- E/SensorService( 471): Error activating sensor 0 (Operation not permitted)
- V/CAM_PhotoModule( 1041): On resume.
- V/CAM_PhotoModule( 1041): Executing onResumeTasks.
- V/CAM_PhotoModule( 1041): Open camera device.
- V/CameraHolder( 1041): open camera 0
- E/CameraService( 163): CameraService::connect X (pid 1041) rejected (invalid cameraId 0).
这里只能看出来CameraService 连接相机0失败,invalid
cameraId 0 除此之外,不太明白为什么会有这样的信息。
抛开系统相机我们先自己写一个小应用来测试一下video是否正常工作。
linux下的摄像头驱动框架是V4L2,只要根据相关的API来写测试程序,然后封装成JNI函数,交给Android层调用即可。
这里我比较懒用了一下一个开源项目的相机demo来验证我的相机在当前环境下是工作正常的。
SimpleWebCam
https:///neuralassembly/simplewebcam/src
附件也会提供这个项目稍微修改过的工程,因为涉及到Jni代码的编译,直接提供的工程就省去很多麻烦。
这里存在一个权限的问题,只是测试用,chmod 777 /dev/video* 防止因为权限打不开相机.
这里用的640x480 resolution with YUYV format 的可能有些摄像头不支持,就需要研究一下改一下JNI代码了,
然后确认了LINUX驱动层不存在问题,我们就开始考虑一下故障的地方在哪里了。
首先进入
- frameworks/av/services/camera/libcameraservice/CameraService.cpp 查看异常的日志是哪里打印出来,很快就发现
-
- if (cameraId < 0 || cameraId >= mNumberOfCameras) {
- ALOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
- callingPid, cameraId);
- return -ENODEV;
- }
然后 我们知道cameraId==0, 那么 Cameras的数量是0
为了验证相机的数量,我们在上一次启动相机的时候打印确认一下是不是真的是0
然后打印调试信息,发现确实是获取Camera的数量是0,这里相机的数量是直接调用HAL层相机的层层封装函数得到的。
那么很有可能uvc热插拔信息并没有在HAL层更新出来,从而导致并不知道存在这一个相机。
这个推理是通过我反复重启发现有事确实可以打开相机,但是死机了。
packages/apps/LegacyCamera/src/com/android/camera/CameraHolder.java
这个是相机程序的代码,可以看出是直接获取相机数量 。
android.hardware.Camera.getNumberOfCameras();
- private CameraHolder() {
- HandlerThread ht = new HandlerThread("CameraHolder");
- ht.start();
- mHandler = new MyHandler(ht.getLooper());
- mNumberOfCameras = android.hardware.Camera.getNumberOfCameras();
- mInfo = new CameraInfo[mNumberOfCameras];
- for (int i = 0; i < mNumberOfCameras; i++) {
- mInfo[i] = new CameraInfo();
- android.hardware.Camera.getCameraInfo(i, mInfo[i]);
- if (mBackCameraId == -1 && mInfo[i].facing == CameraInfo.CAMERA_FACING_BACK) {
- mBackCameraId = i;
- }
- if (mFrontCameraId == -1 && mInfo[i].facing == CameraInfo.CAMERA_FACING_FRONT) {
- mFrontCameraId = i;
- }
- }
- }
这里稍微增加cameraopne的时候去读相机的信息。
- 1.死机后的信息
- D/CameraHolder( 1043): CameraHoler().go
- D/CameraHolder( 1043): mMockCameraInfo ==null, getNumberOfCameras()
- D/CameraHolder( 1043): return number === 1
- 2.提示打不开的信息
- D/CameraHolder( 1043): CameraHoler().go
- D/CameraHolder( 1043): mMockCameraInfo ==null, getNumberOfCameras()
- D/CameraHolder( 1043): return number === 0
说明了一切问题的根源在于相机打开的过程中获取相机数量是不正确,这里又查看了CameraHal代码被加载的流程分析,发现
uvc摄像头是在CameraHal代码被加载后才发现的,非常关键的信息是存储在HAL层的一个数组中的。
那么,我们肯定了HAL层不支持热插拔,那么如何要支持热插拔呢,我们需要分析一下cameraService中的流程。
frameworks/av/services/camera/libcameraservice/CameraService.cpp
-
void CameraService::onFirstRef()
-
{
-
BnCameraService::onFirstRef();
-
-
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
-
(const hw_module_t **)&mModule) < 0) {
-
ALOGE("Could not load camera HAL module");
-
mNumberOfCameras = 0;
-
}
-
else {
-
mNumberOfCameras = mModule->get_number_of_cameras();
-
if (mNumberOfCameras > MAX_CAMERAS) {
-
ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
-
mNumberOfCameras, MAX_CAMERAS);
-
mNumberOfCameras = MAX_CAMERAS;
-
}
-
for (int i = 0; i < mNumberOfCameras; i++) {
-
setCameraFree(i);
-
}
-
}
-
}
这个函数非常关键,我们发现这里加载的HAL的初始化代码,我们也通过上面的日志得出hal实际上能获取数量的,只是当时确实是没有相机。所以,我们修改了getNumberOfCameras函数,每次发现没有摄像头说明,就应该重新初始化一次这样就解决了热插拔的问题。
那么问题来了,当我有两个随意的摄像头时,随意热插拔还是有问题,那么改成<2 吧,最大只支持两个相机。
- int32_t CameraService::getNumberOfCameras() {
- if(mNumberOfCameras == 0) {
- ALOGE("no camera found before! check again...");
- onFirstRef();
- }
- return mNumberOfCameras;
- }
|