相关动态
Android监控虚拟键 android手机虚拟摄像头手机IM「Android监控虚拟键 android手机虚拟摄像头」
2025-02-12 14:40


        在工作中,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,返回给上面即可。

       

    以上就是本篇文章【Android监控虚拟键 android手机虚拟摄像头手机IM「Android监控虚拟键 android手机虚拟摄像头」】的全部内容了,欢迎阅览 ! 文章地址:http://sjzytwl.xhstdz.com/news/14821.html 
     栏目首页      相关文章      动态      同类文章      热门文章      网站地图      返回首页 物流园资讯移动站 http://sjzytwl.xhstdz.com/mobile/ , 查看更多   
最新文章
苹果手机怎么恢复备份?详细攻略为你整理好了!云备份怎么恢复到手机「苹果手机怎么恢复备份?详细攻略为你整理好了!」
随着智能手机和互联网的普及,手机中存储的个人信息、照片、视频、聊天记录等数据会变得越来越多。一旦手机丢失、损坏或系统出现
李亚鹏正式息影 投资50亿丽江当老板金立手机老板「李亚鹏正式息影 投资50亿丽江当老板」
  华西都市报4月28日讯 昨日,李亚鹏打造的“云南省文化产业试验园”项目北京签约“我每年只选一部戏来拍,这已经严格遵循了10
怎样采用比特币挖矿?手机挖矿「怎样采用比特币挖矿?」
好吧,废话不多说了,其实比特币 - Bitcoin 出现时间已经很久了,不过对于新手来说,还是需要讲解一下的。关于比特币。FORECE 在
定了!苹果 2022 秋季发布会定档,9月8日见iPhone 14 来了?苹果手机发布会「定了!苹果 2022 秋季发布会定档,9月8日见iPhone 14 来了?」
又是九月,丰收的季节,今年的苹果又该熟了.......正如此前传闻那样,今晚苹果正式向外界发送了邀请函,宣布将于当地时间 9月7日
苹果手机微信闪退怎么回事苹果手机闪退是什么原因「苹果手机微信闪退怎么回事」
  品牌型号:iPhone12  系统版本:IOS14  苹果手机如果出现微信闪退的状况,首先我们得寻找原因,接下来小编就带着你们来
ZArchiver手机解压缩工具chm文件手机怎么打开「ZArchiver手机解压缩工具」
ZArchiver是一款功能强大的解压缩工具APP,可用于解压文件或压缩文件,软件支持多种文件格式的压缩和解压缩,包括ZIP、RAR、7Z、
【原】一部手机最长能用几年?主要有三个因素,决定了手机的寿命什么手机寿命最长「【原】一部手机最长能用几年?主要有三个因素,决定了手机的寿命」
一部手机最长能用几年?主要取决于以下这几个重要因素,才能决定手机的使用寿命。在当今社会,智能手机已经成为我们生活中不可或
iQOO 3评测:旗舰机还能在哪提升?这部手机给了答案机械手机「iQOO 3评测:旗舰机还能在哪提升?这部手机给了答案」
  文/晓光 于泽 瑞豪 视频/贾乾 图/苏航  从去年成立至今,iQOO这品牌发布了不到十款产品,并成功在互联网渠道占据了自己的
2013-4-7发布华为模拟器eNSP月度更新版(V2.0)支持全系列AR路由器模拟华为手机模拟器「2013-4-7发布华为模拟器eNSP月度更新版(V2.0)支持全系列AR路由器模拟」
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.ne
ADB驱动源码深度解析,从原理探究到实践应用android手机驱动「ADB驱动源码深度解析,从原理探究到实践应用」
摘要:,,本文深入解析ADB(Android Debug Bridge)驱动源码,从原理到实践全面阐述。文章首先介绍了ADB的基本原理和主要功能,
相关文章