推广 热搜: 行业  设备    系统  参数  经纪    教师  机械  中国 

Android监控虚拟键 android手机虚拟摄像头手机IM「Android监控虚拟键 android手机虚拟摄像头」

   日期:2025-02-12     作者:caijiyuan    caijiyuan   评论:0    移动:http://sjzytwl.xhstdz.com/mobile/news/14821.html
核心提示:在工作中,camera这一块上,可能会有各种各样的需求。比如有人想新增一个虚拟摄像头,当用户app打开摄像头设备时,打开的不是系


        在工作中,camera这一块上,可能会有各种各样的需求。比如有人想新增一个虚拟摄像头,当用户app打开摄像头设备时,打开的不是系统默认的camera hal代码,而是自己指定的代码,用自己事先准备好的视频数据,来喂给app;也有人想在系统默认的一套app框架上,新增一个外接的usbcamera,并且要能溶入到camera框架中。app只需要指定usbcamera的id,就能像打开普通摄像头那样,去打开我们的usbcamera;也有人,想在现有的框架上,同时兼容老的hal1+api1流程的android8.0之前的camera,又想新增一个符合android8.0的hidl接口规范的camera模块。

        上面所有的需求,归纳起来,核心的就是一点,即如何去新增一个camera hal模块。我这篇博客,是以在mtk android8.0上新增一个usbcamera hal模块来讲的。当然,新增虚拟摄像头,流程跟这个也是一模一样的。

        好了,既然是想在android8.0上新增一套符合hidl接口规范的camera流程,那么我们先要了解一下,android原生的hidl接口下的camera流程,下面我们先讲一讲这块。

        在android8.0之前,frameworks层的cameraservice和hal层的camera代码是在同一个进程的,这样不利于hal层部份独立升级。针对这个问题,8.0后,就推出了hidl机制,将frameworks层和hal层分成了两个进程,从而进行了解耦。借用网上的一张图片来大致的表明下这个区别:

Android监控虚拟键 android手机虚拟摄像头_androidO camera

        这么一来,看似调用变复杂了,但其实是殊途同归,hal层代码和之前基本上没有变化。具体到camera而言,就是在frameworks层和hal层中间,增加了一个cameraProvider来做为两方联系的桥梁。现在的调用流程,再借网上一张图一用:

Android监控虚拟键 android手机虚拟摄像头_androidO camera_02

        接下来以上面这张图来大致的说一下调用流程:

        1.) 开机注册cameraProvider(cameraProvider里会和具体的camera hal层对应起来)

        2.) 开机实例化cameraService

        3.) 查找并列出所有的cameraProvider(这一步会通过hw_get_module来将camera的hal层代码load出来)

        这基本上就是camera开机后从frameworks加载到hal层的路线了。下面再具体一步步来分析。

 

开机注册cameraProvider

        在我们的hardwareinterfacescameraprovider2.4default目录下,有一个android.hardware.camera.provider@2.4-service.rc文件

        当开机时,会自动调用这个文件去启动服务camera-provider-2-4,然后它会调用到/vendor/bin/hw/android.hardware.camera.provider@2.4-service这个文件。然后会调到hardwareinterfacescameraprovider2.4defaultservice.cpp

        然后这里会用hidl的标准接口去将我们的"legacy/0"注册到服务上去。

        在这里有一点要注意,这里的"legacy/0"必须要先在工程根目录 device芯片名/manifest.xml里先声明,否则即使这里注册了,后面也会因为找不到而报错.

 

开机实例化cameraService

        在frameworksavcameracameraserver里有个cameraserver.rc, 它在开机的时候,也会自动启动.

        然后它会调用到frameworksavcameracameraservermain_cameraserver.cpp

       在这个main函数里,我们只需要关注CameraService::instantiate();这行代码. 我们的CameraService继承了BinderService.h.这个:instantiate()调用到了BinderService.h里的代码

        从这个文件可以看出,instantiate最终还是调用到了IServiceManager里的addService, 将我们的cameraService注册到了系统的服务管理器里去了.

        这里调用到CameraService后, 因为是开机第一次调用,它的引用计数为1,所以会调用到CameraService::onFirstRef()这个函数. 这个函数是从CameraService的父类Refbase里继承过来的.该函数在强引用sp新增引用计数时调用,什么意思?就是当 有sp包装的类初始化的时候调用.我们再看看cameraService::onFirstRef()

        在这个函数里,我们只关注enumerateProviders(),这里就到了列出所有cameraProvider.

 

查找并列出所有的cameraProvider


        这个函数里,创建了一个CameraProviderManager对象,并调进行了初始化.

        在这个初始化函数里,我们只关注addProviderLocked, 我们可以看到,这个函数传进了一个kLegacyProviderName, 它的值定义在这个文件的上面:

        const std::string kLegacyProviderName("legacy/0");

        大家注意到了没有,它的值和我们之前hardwareinterfacescameraprovider2.4defaultservice.cpp里注册服务时return defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0", 6); 以及manifest.xml里<instance>legacy/0</instance>的值都是一致的. 如果这个值不致,则会调用不成功.

        好了,再回到addProviderLocked这个函数来, 这个函数的作用, 就是去加载camera对应的hal层代码, 并将它的信息保存在ProviderInfo里,后面我们就可以通过这个ProviderInfo, 去实行addDevice、getCameraInfo等操作。

        这里先检查一下,传进来的newProvider是不是已经添加过,如果已经添加了,就不再处理,直接返回。如果没添加过,就会进行下一步的操作。这里的interface = mServiceProxy->getService(newProvider);,会调用到hardwareinterfacescameraprovider2.4defaultCameraProvider.cpp的HIDL_FETCH_ICameraProvider函数。

        在这个函数里,会创建一个CameraProvider对象。

        在这个初始化函数中,会看到一个我们非常熟悉的函数hw_get_module。到这里,就跟我们android8.0之前的流程一模一样的了,都是去直接和hal层打交道了。

        在CameraProvider里有一个地方值得大家注意

        从这里看来,如果我们的camera使用了hidl和hal打交道的话,我们hal里的版本号,必须是1.0或者是大于3.2的,如果我们的hal层的的版本号为3.0或3.1的话,是不能正确的加载成功的。

 

        上面用到的图片,引用了这个博客的,大家也可以去这篇博客看看。启动流程都是一致的,这博主也讲得比较详细。

 

        好了,上面就将android8.0上camera hal层代码的加载流程基本讲完了。有了上面的基础,下面我们再来一步步的讲下,怎么去新增一个camera hal。

###############################################################################################################################################################################################################################################################################################################

移植一个camera hal,需要做的有以下几点:

1.)在devicemediatekmt6580manifest.xml里新增要增加的camera的instance

2.)在frameworksavservicescameralibcameraservicecommonCameraProviderManager.cpp里,将要添加的camera provider给addProviderLocked进来

3.)在hardwareinterfacescameraprovider2.4defaultCameraProvider.cpp里将要增加的camera,通过hw_get_module这样给load进来。

4.)准备好对应的camera hal代码

 

配置manifest.xml

        因为mtkcamera已经有了一个camera hal1,名字为internal/0, 所以我们的usbcamera对应的名字跟在它的后面即可。注意,“legacy/1”这个名字的前面“legacy”这串,可以随便取,比如可以叫”abc/1",只要其他用到的地方都叫这个名字就可以。但是这个后面的“1”,不能弄错。前面已经为0了,这个就必须为1,同理,如果还有一个摄像头,就要为2了。因为在CameraProviderManager.cpp里的ProviderInfo::parseDeviceName,是通过后面这个数字,来取对应的id值的。如果我们将这个usbcamera的id也写为0,即名字为“legacy/0”,那么在ProviderInfo::parseDeviceName这里取出来的id,就会和前面的已经有了的主摄冲突。

 

添加camera的ProviderInfo

        在frameworksavservicescameralibcameraservicecommonCameraProviderManager.cpp的initialize函数里,将kLegacyProviderName改成"legacy/1"

        在hardwareinterfacescameraprovider2.4defaultservice.cpp里的main函数里,将"legacy/1"注册上来

        在hardwareinterfacescameraprovider2.4defaultCameraProvider.cpp里,将kLegacyProviderName改成"legacy/1";它会被HIDL_FETCH_ICameraProvider调用。

 

hw_get_module对应camera的hal代码

        在hardwareinterfacescameraprovider2.4defaultCameraProvider.cpp里的initialize()函数里,hw_get_module参数传进去的名字,改成我们usbcamera hal里指定的名字

        int err = hw_get_module("usbcamera", (const hw_module_t **)&rawModule);

 

准备好对应的camera hal代码

       我们的usbcamera hal代码,我们放在hardwarelibhardwaremodulescameralibuvccamera下面。在这个目录里,有个HalModule.cpp文件,里面定义了camera_module_t的结构体,它的id就是"usbcamera", 在CameraProvider.cpp里hw_get_module时,发现这里定义的id和它要找的id一致,就会load到我们的usbcamera了。

        大家可能会发现,在getCameraInfo函数里,我将cameraId写死成了0,但是前面我们不是刚说过,我们的usbcamera是第二个摄像头,id要为1么?其实这里的id,和前面说的那个id,不是同一个意思。在这里之所以写成0,是因为我们这套usbcamera hal代码上面,只挂了一个摄像头,这个摄像头对应的代码放在Camera *cams[]数组里,这个数组里只放了一个对象,所以id自然就要为0了。然后我们在我们的halModule.cpp里操作getCameraInfo或openDevice时,就会通过这个数组调用到static Camera mainCamera;这里定义的这个Camera对象了。这个Camera,也是我们自己写的代码:

 

 

        大家请注意,在Camera.cpp的Camera()里调用了common.version  = CAMERA_DEVICE_API_VERSION_3_2;  在cameraInfo里调用了info->device_version = CAMERA_DEVICE_API_VERSION_3_2; 这里表示,我们的hal的版本定义为了hal3.2。

        我们的HalModule.cpp的get_camera_info指向了HalModule::getCameraInfo,  getCameraInfo里又调用到了Camera::cameraInfo,然后Camera::cameraInfo通过staticCharacteristics来,获取我们usbcamera的属性。这样在app上就可以通过getCameraInfo来获取我们usbcamera的属性了。也可以使用下面的方法来获取我们预览或者拍尺寸等:

        我这个usbcamera,可以同时兼容api1和api2,当然,如果想要让api2也来调用的话,camera_metadata_t *mStaticCharacteristics;这个值要配好,必须按api2的规范来,该有的值一个都不能少,要不然app在调用getStreamConfigurationMap去获取属性时,就有可能会因为获取不到对应的值而报错。

       比如一开始,我在staticCharacteristics这个函数里,没有配置ANDROID_REQUEST_AVAILABLE_CAPABILITIES相关的属性。然后app在用api2的接口去getStreamConfigurationMap的时候,就因为找不到REQUEST_AVAILABLE_CAPABILITIES而报错了。至于api2都需要哪些配置项,大家可以参考frameworksbasecorejavaandroidhardwarecamera2implCamerametadataNative.java里的getStreamConfigurationMap()这个函数,这里需要的,都给加上,都必须加上。

        后来报错后,我在staticCharacteristics这个函数里,加下了如下代码,就可以了:

        到这里,我们一个完整的usbcamera hal就添加完成了。当然,虚拟摄像头也是一样的。唯一不同的是camera.cpp里的processCaptureRequest这个函数。我们的usbcamera是真正的一个摄像头,是可以取到实景的,所以就按照v4l2的标准来读取,然后按camera hal的规范来填充就可以。 但是虚拟摄像头因为是没有真正的摄像头的,它取的景,是底层事先录好一个视频,然后喂给buff的。所以虚拟摄像头,需要修改processCaptureRequest这个函数。

        虚拟摄像头,只需要在这个函数里,按照app设置的帧率来循环读取视频里的数据,然后abgr的格式,喂给processCaptureResult这个函数,这个函数,再通过回调mCallbackOps->process_capture_result,返回给上面即可。

       

本文地址:http://sjzytwl.xhstdz.com/news/14821.html    物流园资讯网 http://sjzytwl.xhstdz.com/ , 查看更多

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。

 
 
更多>同类最新文章
0相关评论

文章列表
相关文章
最新动态
推荐图文
最新文章
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号