在使用外接USB摄像头时,在预览过程中,将外接摄像头移除,再插入该摄像头的ID会后移一位,这种情况发生是因为摄像头再拔出时没有触发驱动的release方法释放资源,导致再次插入摄像头时之前的ID被占用而后移。
common/drivers/media/usb/uvc/uvc_driver.c 这里是UVC驱动代码,插上USB时会触发usb_probe,拔出时会触发uvc_disconnet。
Uvc_probe 最终会调用到v4l2-dev.c 的函数__video_register_device中,每次新摄像头的节点是通过devnode_find来查找,通过函数devnode_set 把驱动节点标记为正在使用中,通过devnode_clear可以清除节点的占用状态。
但是我们发现异常拔出的Uvc_disconnect一路调用中并没有devnode_clear这个函数的调用,所以异常拔出的时候不会清除节点使用状态。这就是问题所在
/* Register the release callback that will be called when the last reference to the device goes away. */ vdev->dev.release = v4l2_device_release;
每个节点会注册一个release方法,而v4l2_device_release函数中会调用devnode_clear所以正常退出预览不会有问题。
在v4l2-dev.c 中video_unregister_device中加入devnode_clear,即可在摄像头拔出时清除掉暂用状态,但是这种办法仅仅适用于AOSP版本,如果是要过GMS认证的版本因为GKI的限制这部分标准驱动是不能被修改的,那么对于需要过GMS认证的版本需要采用第二种方法
HAL层分两种情况:
第一种相机使用legacy provider:
修改 hardware/amlogic/camera/AppCallbackNotifier.cpp
void AppCallbackNotifier::errorNotify(int error) { LOG_FUNCTION_NAME; CAMHAL_LOGEB("AppCallbackNotifier received error %d", error); // If it is a fatal error abort here! if((error == CAMERA_ERROR_FATAL) || (error == CAMERA_ERROR_HARD)) { //We kill media server if we encounter these errors as there is //no point continuing and apps also don't handle errors other //than media server death always. abort(); return; } if ( ( NULL != mCameraHal ) && ( NULL != mNotifyCb ) && ( mCameraHal->msgTypeEnabled(CAMERA_MSG_ERROR) ) ) { CAMHAL_LOGEB("AppCallbackNotifier mNotifyCb %d", error); mCameraHal->release(); // add 添加这行 mNotifyCb(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0, mCallbackCookie); } LOG_FUNCTION_NAME_EXIT; }
第二种,使用的external provider,这种Google原生相机服务没有做相关处理逻辑,自己添加节点检测,在检测到节点移除之后去对打开的节点执行close操作。
interfaces/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
添加
// xbh patch begin class MonitorThread : public android::Thread { private: const wp mParent; int mFd; int mCameraId; public: MonitorThread(wp parent, int fd, int cameraId) : mParent(parent), mFd(fd),