当前位置: 首页 > news >正文

相机可用性变化监听AvailabilityCallback流程分析

相机可用性变化监听及流程分析

一、接口说明

​ 相机可用性变化监听可以通过CameraManager中的接口registerAvailabilityCallback()来设置回调,接口如下:

/**
*注册一个回调以获得有关相机设备可用性的通知。
*
*<p>再次注册相同的回调将用提供的新回调替换处理程序</p>
*
*<p>第一次注册回调时,会立即调用回调,并显示当前已知的所有相机设备的可用性状态</p>
*
*任何相机API客户端打开相机设备时,都会调用<p>{@linkAvailabilityCallback#onCameraUnavailable(String)}。从API级别23开始,其他相机API客户端可能仍然能够打开这样的相机设备,如果它们的优先级高于相机设备的现有客户端,则会逐出现有客户端。有关详细信息,请参阅open()</p>
*
*<p>由于此回调将在相机服务中注册,请记住在不再需要时注销它;否则,回调将无限期地继续接收事件,并可能阻止其他资源被释放。具体来说,回调将调用各个CameraManager实例的状态</p>
*
*@param callback 向发送相机可用性通知的新回调。
*@param handler 应该调用回调的handler,或者为{@code null}的话使用当前线程的{@linkandroid.os.Looper Looper}。
*
*如果handler为{@code null},但当前线程没有Looper,则@throws IllegalArgumentException。
*/
public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, @Nullable Handler handler)

AvailabilityCallback主要api如下:

    /***摄像机设备变为可用或不可用的回调。**<p>当不再使用相机或连接新的可移动相机时,相机将可用。当某些应用程序或服务开始使用相机时,或者当可移动相机断开连接时,它们将不可用</p>**<p>扩展此回调,并将子类的一个实例传递给{@link CameraManager#registerAvailabilityCallback},以便收到此类可用性更改的通知</p>**@参见#registerAvailabilityCallback*/public static abstract class AvailabilityCallback {/***一台新相机已经可以使用了。**<p>此方法的默认实现不执行任何操作</p>**@param cameraId新相机的唯一标识符。*/public void onCameraAvailable(@NonNull String cameraId) {// default empty implementation}/***以前可用的相机已无法使用。**<p>*如果一个应用程序有一个活动的CameraDevice实例用于现在断开连接的相机,该应用程序将收到{@link CameraDevice.StateCallback#onDisconnected disconnection error}*</p>**<p>此方法的默认实现不执行任何操作</p>**@param cameraId断开连接的摄像机的唯一标识符。*/public void onCameraUnavailable(@NonNull String cameraId) {// default empty implementation}/***每当摄像机访问优先级更改时调用。**<p>通知相机访问优先级已更改,相机现在可以打开。先前由于较高优先级的用户已经在使用相机而被拒绝访问相机的应用程序,或者由于较高优先级用户试图打开相机而与活动相机会话断开连接的应用程序如果仍想使用相机,则应尝试再次打开相机。请注意,多个应用程序可能同时接收此回调,并且在实践中,根据确切的访问优先级和时间,只有其中一个应用程序能够成功打开相机。如果多个应用程序可能同时处于恢复状态,并且用户在它们之间切换焦点,或者使用应用程序的当前相机在全屏和画中画(PiP)状态之间移动,则此方法非常有用。在这种情况下,摄像机可用/不可用回调将不会被调用,但另一个应用程序现在可能比当前使用摄像机的应用程序具有更高的摄像机访问优先级</p>**<p>此方法的默认实现不执行任何操作</p>*/public void onCameraAccessPrioritiesChanged() {// default empty implementation}/***一台物理相机已可再次使用。**<p>默认情况下,逻辑多摄像机的所有物理摄像机都可用,因此当调用逻辑多摄像机用的{@link#onCameraAvailable}时,不会为逻辑多摄像机中的任何物理摄像机调用{@link#onPhysicalCameraAvailable}。但是,如果某些特定的物理摄影机一开始就不可用,则可以在{@link#onCameraAvailable}之后调用{@link#onPhysicalCameraUnavailable}</p>**<p>此方法的默认实现不执行任何操作</p>**@param cameraId逻辑多摄像机的唯一标识符。*@param physicalCameraId物理相机的唯一标识符。**@请参阅#onCameraAvailable*@请参阅#onPhysicalCamera不可用*/public void onPhysicalCameraAvailable(@NonNull String cameraId,@NonNull String physicalCameraId) {// default empty implementation}/***以前可用的物理相机已无法使用。**<p>默认情况下,逻辑多摄像机的所有物理摄像机都可用,因此当调用逻辑多摄像机用的{@link#onCameraAvailable}时,不会为逻辑多摄像机中的任何物理摄像机调用{@link#onPhysicalCameraAvailable}。如果某些特定的物理相机一开始就不可用,则可以在{@link#onCameraAvailable}之后调用{@link#onPhysicalCameraUnavailable}</p>**<p>此方法的默认实现不执行任何操作</p>**@param cameraId逻辑多摄像机的唯一标识符。*@param physicalCameraId物理相机的唯一标识符。**@请参阅#onCameraAvailable*@请参阅#onPhysicalCameraAvailable*/public void onPhysicalCameraUnavailable(@NonNull String cameraId,@NonNull String physicalCameraId) {// default empty implementation}}

注意这里physical cameralogical multi-camera的区别:

  • physical camera:物理摄像头,对应实际的物理硬件。

  • logical multi-camera:是在某些支持的 Android 设备上引入的一项功能,它允许开发者同时使用多个摄像头来进行更高级的图像处理和功能。在逻辑多摄像头系统中,多个物理摄像头可以捆绑在一起,并被视为单个逻辑摄像头设备。这些物理摄像头可以包括不同的焦距、不同的传感器类型(例如彩色相机和红外相机)等。由于这些物理摄像头协同工作,它们可以为开发者提供更丰富的功能和更灵活的图像处理能力。

二、源码调用链分析

1.回调设置的过程

\frameworks\base\core\java\android\hardware\camera2\CameraManager.java

public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, @Nullable Handler handler) {CameraManagerGlobal.get().registerAvailabilityCallback(callback,                   CameraDeviceImpl.checkAndWrapHandler(handler));
}

调用到CameraManager的内部类CameraManagerGlobal的方法registerAvailabilityCallback:

\frameworks\base\core\java\android\hardware\camera2\CameraManager.java

public void registerAvailabilityCallback(AvailabilityCallback callback,Executor executor) {synchronized (mLock) {/*1.连接到CameraService,如果已经连接,不执行任何操作。*/connectCameraServiceLocked();/*2.将设置的callback存入mCallbackMap中。mCallbackMap专门用于存储可用性回调以及执行它们的Executor。*/Executor oldExecutor = mCallbackMap.put(callback, executor);// For new callbacks, provide initial availability informationif (oldExecutor == null) {/*3.如果oldExecutor为空,说明是第一次设置该可用性回调。将当前已知的所有相机的状态触发设置的callback回调,以便使监听者了解当前所有相机状态。*/updateCallbackLocked(callback, executor);}// If not connected to camera service, schedule a reconnect to camera service.if (mCameraService == null) {/*4.如果mCameraService为空说明连接CameraService失败,计划一次新的重连尝试。*/scheduleCameraServiceReconnectionLocked();}}
}

​ 到这里设置的可用性回调已经被存储到mCallbackMap当中,设置回调的流程完毕,后续相机状态变化触发回调时,将遍历mCallbackMap取出callback并执行相应的回调方法。
 说一点题外话,这里可以关注一下Google对CameraManager类的设计,该类整体比较简单,主要就是对外暴露方法的定义以及CameraManagerGlobal类的定义,CameraManager对外暴露的方法基本上都是调用静态内部类CameraManagerGlobal当中的对应实现。CameraManagerGlobal类私有化了构造方法,其实例化的方法封装到了get方法当中,实现了一个单例。这样做的主要目的是确保一个进程中CameraManagerGlobal只被实例化一次,从而与CameraService的AIDL连接也只会建立一次。从该类的注释中可以看出。“每个进程的全局CameraManager实例,用于持有到CameraService的连接,并将相机可用性通知分发给api注册的回调”。

 /*** A per-process global camera manager instance, to retain a connection to the camera service,
* and to distribute camera availability notices to API-registered callbacks
*/
private static final class CameraManagerGlobal extends ICameraServiceListener.Stub implements IBinder.DeathRecipient {/*略*/}

2.回调触发的过程

​ 这里主要关注回调AvailabilityCallback中的onCameraAvailable和onCameraUnavailable方法的触发。我将从这两个方法最终被调用的地方开始往前梳理调用链。

​ 发现方法最终被调用的地方只有一个,即为CameraManager的内部类CameraManagerGlobal的内部类中的private方法postSingleUpdate:

\frameworks\base\core\java\android\hardware\camera2\CameraManager.java

private void postSingleUpdate(final AvailabilityCallback callback,final Executor executor,final String id, final String physicalId, final int status) {/*略*/}

继续分析,发现调用postSingleUpdate的方法的地方为CameraManager的内部类CameraManagerGlobal中的另外3个private方法:

\frameworks\base\core\java\android\hardware\camera2\CameraManager.java

private void updateCallbackLocked(AvailabilityCallback callback,Executor executor) {/*略*/}
private void onStatusChangedLocked(int status, String id) {/*略*/}
private void onPhysicalCameraStatusChangedLocked(int status, String id, String physicalId) {/*略*/}

updateCallbackLocked方法只在注册回调时调用,忽略。关注onStatusChangedLocked和onPhysicalCameraStatusChangedLocked两个方法,从名称上可以看出这两个方法的用意,这里我们主要关注onStatusChangedLocked方法的调用。

发现调用onStatusChangedLocked方法的均为CameraManager的内部类CameraManagerGlobal中方法,包括以下4个方法:

\frameworks\base\core\java\android\hardware\camera2\CameraManager.java

private void connectCameraServiceLocked() {/*略*/}
public String[] getCameraIdListNoLazy() {/*略*/}
@Override
public void onStatusChanged(int status, String cameraId) throws RemoteException {/*略*/}
public void binderDied() {/*略*/}

其中onStatusChanged方法重写自CameraManagerGlobal实现的ICameraServiceListener.Stub接口,即该方法为相机框架中4个关键AIDL文件之一的CameraServiceListener.aidl中定义的方法,通过CameraServiceListener.aidl,CameraService可以调用CameraManager中的方法。(相机框架4个关键AIDL文件包括:ICameraService.aidl、ICameraDeviceCallback.aidl、ICameraDeviceUser.aidl、ICameraServiceListener.aidl)

所以现在直接追溯到CameraService中通过AIDL调用onStatusChanged的地方:

void CameraService::updateStatus(StatusInternal status, const String8& cameraId,std::initializer_list<StatusInternal>rejectSourceStates) {/*……略……*/for (auto& listener : mListenerList) {/*……略……*/listener->getListener()->onStatusChanged(mapToInterface(status),String16(cameraId));/*……略……*/}/*……略……*/
}

未完待续……

相关文章:

相机可用性变化监听AvailabilityCallback流程分析

相机可用性变化监听及流程分析 一、接口说明 ​ 相机可用性变化监听可以通过CameraManager中的接口registerAvailabilityCallback()来设置回调&#xff0c;接口如下&#xff1a; /** *注册一个回调以获得有关相机设备可用性的通知。 * *<p>再次注册相同的回调将用提供…...

使用Python多线程实现生产者消费者模型

“Talk is cheap, show me the code.” 废话不多说&#xff0c;直接上代码&#xff1a; """ 生产者消费者模型 Python实现 """ import queue import threading import random import timeclass ConsProd:# 队列参数_que None # 队列# 生产者…...

Notepad++工具通过正则表达式批量替换内容

1.每行末尾新增特定字符串 CtrlH弹出小窗口&#xff1b;查找目标输入$&#xff0c;替换为输入特定字符串&#xff1b;选中循环查找&#xff0c;查找模式选正则表达式&#xff1b;最后点击全部替换 2.每行行首新增特定字符串 CtrlH弹出小窗口&#xff1b;查找目标输入^&…...

从零构建深度学习推理框架-3 手写算子relu

Relu介绍&#xff1a; relu是一个非线性激活函数&#xff0c;可以避免梯度消失&#xff0c;过拟合等情况。我们一般将thresh设为0。 operator类&#xff1a; #ifndef KUIPER_COURSE_INCLUDE_OPS_OP_HPP_ #define KUIPER_COURSE_INCLUDE_OPS_OP_HPP_ namespace kuiper_infer {…...

想做上位机,学C#还是QT?

学习C#还是Qt&#xff0c;取决于你的具体需求和偏好。 如果你计划开发跨平台的桌面应用程序&#xff0c;并且希望使用一种更轻量级、直观的界面框架&#xff0c;那么Qt可能是一个不错的选择。Qt是一个功能丰富且成熟的跨平台框架&#xff0c;支持多种开发语言&#xff08;包括…...

Ansible —— playbook 剧本

Ansible —— playbook 剧本 一、playbook的概述1.playbook简介2.什么是Ansible playbook剧本&#xff1f;3.Ansible playbook剧本的特点4.如何使用Ansible playbook剧本&#xff1f;5.playbooks 本身由以下各部分组成 二、playbook示例1.运行playbook2.定义、引用变量3.指定远…...

ARM寻址方式

寻址方式 寻址方式是根据指令中给出的地址码字段来实现寻找操作数地址的方式&#xff0c;ARM中有以下8种基本的寻址方式。 1、寄存器寻址 将寄存器中的值作为操作数&#xff0c;指令中的地址码字段是寄存器编号。 MOV R1,R2 ;R1 R2 ADD R0,R1,R2 ;R0 R1 R22、立即寻…...

【JAVA】String ,StringBuffer 和 StringBuilder 三者有何联系?

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 文章目录 前言StringBufferStringBuffer方法 StringBuilderStringBuilder方法 String &#xff0c;StringBuffer 和 StringBuilder的区别String和StringBuffer互相转换 前言 在之前的文章…...

关于计数以及Index返回订单号升级版(控制字符长度,控制年月标记)

数据库表操作&#xff1a; EXEC sys.sp_dropextendedproperty nameNName , level0typeNSCHEMA,level0nameNdbo, level1typeNTABLE,level1nameNSetNoIndexGOEXEC sys.sp_dropextendedproperty nameNMS_Description , level0typeNSCHEMA,level0nameNdbo, level1typeNTABLE,level…...

【计算机网络】11、网桥(bridge)、集线器(hub)、交换机(switch)、路由器(router)、网关(gateway)

文章目录 一、网桥&#xff08;bridge)二、集线器&#xff08;hub&#xff09;三、交换机&#xff08;switch)四、路由器&#xff08;router&#xff09;五、网关&#xff08;gateway&#xff09; 对于hub&#xff0c;一个包过来后&#xff0c;直接将包转发到其他口。 对于桥&…...

第九篇-自我任务数据准备

格式化自我意识数据用于ChatGLM微调 准备数据源 https://github.com/hiyouga/ChatGLM-Efficient-Tuning cd data self_cognition.json代码self_process.py #!/usr/bin/python # -*- coding: UTF-8 -*- # 读取self_cognition自我认知解析并写入转换新文件import json# 读取se…...

2023.8.1号论文阅读

文章目录 MCPA: Multi-scale Cross Perceptron Attention Network for 2D Medical Image Segmentation摘要本文方法实验结果 SwinMM: Masked Multi-view with SwinTransformers for 3D Medical Image Segmentation摘要本文方法实验结果 MCPA: Multi-scale Cross Perceptron Att…...

webpack优化前端框架性能

webpack优化目的 webpack优化目的1. 提升开发体验提升开发体验使用 SourceMap 2. 提升打包构建速度提升打包构建速度&#xff08;开发模式&#xff09;提升打包速度 oneOf提升打包速度 include&#xff08;包含&#xff09;/exclude&#xff08;排除&#xff09;提升第二次打包…...

Unity UGUI的Outline(描边)组件的介绍及使用

Unity UGUI的Outline(描边)组件的介绍及使用 1. 什么是Outline(描边)组件&#xff1f; Outline(描边)组件是Unity UGUI中的一种特效组件&#xff0c;用于给UI元素添加描边效果。通过设置描边的颜色、宽度和模糊程度&#xff0c;可以使UI元素在视觉上更加突出。 2. Outline(描…...

爆改vue3 setup naiveui可编辑table

使用naiveui官网的可编辑table总是报错&#xff0c;所以手写了一个 思路&#xff1a;table数据数组unitMsgArr对应一个布尔的数组isEditArr &#xff0c;点击table可编辑的行数据的时候&#xff0c;更改对应的isEdit为true&#xff0c;此时渲染组件EditCom&#xff0c;在EditC…...

功率放大器的种类有哪三种类型

功率放大器是一种能将输入信号转换为更高功率输出的电子设备。在电子工程和音频领域中&#xff0c;功率放大器通常被分为三种类型&#xff1a;A类、B类和AB类。下面安泰电子将详细介绍这三种类型的功率放大器及其特点。 A类功率放大器 A类功率放大器是一种基本的线性功率放大器…...

HDFS 分布式存储 spark storm HBase

HDFS 分布式存储 spark storm HBase 分布式结构 master slave name node client 负责文件的拆分 128MB 3份 data node MapReduce 分布式计算 离线计算 2.X之前 速度比较慢 对比spark 编程思想 Map 分 Reduce 合 hadoop streaming Mrjob Yarn 资源管理 cpu 内存 MapReduc…...

Vue3文字实现左右和上下滚动

可自定义设置以下属性&#xff1a; 滚动文字数组&#xff08;sliderText&#xff09;&#xff0c;类型&#xff1a;Array<{title: string, link?: string}>&#xff0c;必传&#xff0c;默认[] 滚动区域宽度&#xff08;width&#xff09;&#xff0c;类型&#xff1a…...

Docker Sybase修改中文编码

镜像&#xff1a;datagrip/sybase 镜像默认用户名sa&#xff0c;密码myPassword&#xff0c;服务名MYSYBASE 1.进入容器 docker exec -it <container_name> /bin/bash2.加载Sybase环境变量 source /opt/sybase/SYBASE.sh3.查看是否安装了中文字符集 isql -Usa -PmyP…...

【SpringCloud Alibaba】(六)使用 Sentinel 实现服务限流与容错

今天&#xff0c;我们就使用 Sentinel 实现接口的限流&#xff0c;并使用 Feign 整合 Sentinel 实现服务容错的功能&#xff0c;让我们体验下微服务使用了服务容错功能的效果。 因为内容仅仅围绕着 SpringCloud Alibaba技术栈展开&#xff0c;所以&#xff0c;这里我们使用的服…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

Vue 3 + WebSocket 实战:公司通知实时推送功能详解

&#x1f4e2; Vue 3 WebSocket 实战&#xff1a;公司通知实时推送功能详解 &#x1f4cc; 收藏 点赞 关注&#xff0c;项目中要用到推送功能时就不怕找不到了&#xff01; 实时通知是企业系统中常见的功能&#xff0c;比如&#xff1a;管理员发布通知后&#xff0c;所有用户…...

项目进度管理软件是什么?项目进度管理软件有哪些核心功能?

无论是建筑施工、软件开发&#xff0c;还是市场营销活动&#xff0c;项目往往涉及多个团队、大量资源和严格的时间表。如果没有一个系统化的工具来跟踪和管理这些元素&#xff0c;项目很容易陷入混乱&#xff0c;导致进度延误、成本超支&#xff0c;甚至失败。 项目进度管理软…...

MCP和Function Calling

MCP MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09; &#xff0c;2024年11月底&#xff0c;由 Anthropic 推出的一种开放标准&#xff0c;旨在统一大模型与外部数据源和工具之间的通信协议。MCP 的主要目的在于解决当前 AI 模型因数据孤岛限制而…...

Linux信号保存与处理机制详解

Linux信号的保存与处理涉及多个关键机制&#xff0c;以下是详细的总结&#xff1a; 1. 信号的保存 进程描述符&#xff08;task_struct&#xff09;&#xff1a;每个进程的PCB中包含信号相关信息。 pending信号集&#xff1a;记录已到达但未处理的信号&#xff08;未决信号&a…...