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

camera功能真的那么难用吗

背景

        Android开发工作过程中,经常需要用到camera相关能力,比如:人脸识别,ai识别,拍照预览,摄像头录制等等需求。都需要使用到camera,且需要拿到camera的预览数据。但是每次开发这块代码都比较繁琐,一大堆的接口(尤其是camera2),用错一个就容易出现意想不到的结果。所以这里我们将Android的camera做一次简单易用的封装,再也不用担心API用错了。

一、Camera的历史

在封装之前,我们先简单了解下camera的发展历史。目前Android有camera1和camera2两个不同版本的API。且camera1已经逐渐被抛弃了。那她两到底啥区别?

  • Camera1(2010年推出)
    • 简单但僵化:采用同步阻塞模型,调用takePicture()时整个相机管线阻塞,导致延迟高、功耗大。
    • 有限控制:参数调整(如曝光、对焦)通过Camera.Parameters实现,仅支持基础设置,无法精细控制。
    • 高延迟:拍照后需等待图像处理完成才能继续操作。
    • 资源浪费:预览和拍照无法并行,导致CPU/GPU利用率低。
    • 硬件抽象层(HAL)简单:无法适配多摄像头、高帧率传感器(>30fps)或RAW格式。
    • 功能缺失:不支持HDR+、人像模式等计算摄影需求。
    • 独占式访问:仅允许单应用占用相机,其他应用需等待释放(如扫码时无法同时视频通话)。
  • Camera2(2014年推出,Android 5.0+)
    • 异步管道模型:引入CaptureRequestCaptureSession,支持非阻塞操作(如连拍、实时预览并行处理)。
    • 精准控制:可独立配置传感器、闪光灯、处理算法(如手动调节ISO、快门速度)。
    • 零复制流水线:图像数据直接传递到Surface(如TextureView),减少内存拷贝。
    • 批处理请求:单次提交多个CaptureRequest(如同时预览+对焦+测光),提升帧率和能效比。
    • 标准化HAL接口:统一控制不同厂商的相机硬件(如双摄、TOF传感器)。
    • 高级功能支持:原生实现RAW拍摄、手动对焦轨迹、逻辑多摄像头(融合多个传感器数据)。
    • 并发共享机制:通过CameraManager协调多应用访问(如后台AR应用与前台相机APP共存)。
特性Camera1Camera2
架构模型同步阻塞异步非阻塞管道
性能高延迟、低吞吐量低延迟、高吞吐量(支持4K/60fps)
硬件适配仅基础单摄多摄/RAW/高帧率传感器
功能扩展基础拍照/录像HDR+/手动模式/计算摄影
多应用支持独占访问并发共享

 二、封装核心能力

工作场景下对camera最常用的核心能力:开启摄像头,切换摄像头,预览,关闭摄像头,获取摄像头预览数据。

所以我们要封装的话就直接将这几个能力抽象成对应的接口。

package com.qt.camera.baseimport android.graphics.SurfaceTexture
import android.hardware.Camera
import android.util.Range
import com.qt.camera.FUCameraConstants
import com.qt.camera.enumeration.FUCameraFacingEnum
import com.qt.camera.listener.OnFUCameraListener/**** DESC:Camera抽象类* Created on 2021/10/22* @author Jason Lu*/
abstract class FUAbstractCamera {/*** 前置相机id*/@Volatilevar mFrontCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT/*** 后置相机id*/@Volatilevar mBackCameraId = Camera.CameraInfo.CAMERA_FACING_BACK/*** 曝光补偿*/@Volatilevar mExposureCompensation = FUCameraConstants.EXPOSURE_COMPENSATION/*** 相机采集帧率模式* true:最大帧率输出 false:最大可选范围区间输出*/@Volatilevar mIsHighestRate = false/*** 相机后置角度*/@Volatilevar mBackCameraOrientation = FUCameraConstants.BACK_CAMERA_ORIENTATION/*** 当前相机前置角度*/@Volatilevar mFrontCameraOrientation = FUCameraConstants.FRONT_CAMERA_ORIENTATION/*** 当前相机朝向*/@Volatilevar mCameraFacing = FUCameraFacingEnum.CAMERA_FRONT/*** 当前相机输出分辨率-宽*/@Volatilevar mCameraWidth: Int = 1280/*** 当前相机输出分辨率-高*/@Volatilevar mCameraHeight: Int = 720/*** 当前相机角度*/@Volatilevar mCameraOrientation = mFrontCameraOrientation/*** 当前相机绑定纹理 Id*/@Volatilevar mCameraTexId = 100/*** 当前相机绑定 SurfaceTexture*/@Volatilevar mSurfaceTexture: SurfaceTexture? = null/*** 用户设置的相机绑定 SurfaceTexture*/@Volatilevar mCustomSurfaceTexture: SurfaceTexture? = null/*** 是否正在预览状态*/@Volatileprotected var mIsPreviewing = false/*** 是否只读ImageReader流*/@Volatilevar onlyReadImage = false/*** 是否需要停止预览*/@Volatileprotected var mIsNeedStopPreviewing = false/*** 事件回调*/@Volatileprotected var mCameraListener: OnFUCameraListener? = null/*** 自定义摄像头帧率范围* 针对camera2*/var mRangeFps: Range<Int>? = null/*** 绑定数据回调* @param listener OnFUCameraListener*/fun bindCameraListener(listener: OnFUCameraListener?) {this.mCameraListener = listener}/*** 资源释放*/open fun release() {if (mIsPreviewing) {closeCamera()}mCameraListener = null}/*** 初始化相机*/abstract fun initCameraInfo()/*** 打开相机*/abstract fun openCamera()/*** 开启预览*/abstract fun startPreview()/*** 对焦* @param viewWidth Int* @param viewHeight Int* @param rawX Float* @param rawY Float* @param areaSize Int*/abstract fun handleFocus(viewWidth: Int, viewHeight: Int, rawX: Float, rawY: Float, areaSize: Int)/*** 获取亮度* @return Float*/abstract fun getExposureCompensation(): Float/*** 设置亮度* @param value Float*/abstract fun setExposureCompensation(value: Float)/*** 分辨率变更处理* @param cameraWidth Int* @param cameraHeight Int*/abstract fun changeResolution(cameraWidth: Int, cameraHeight: Int)/*** 关闭相机* @param releaseSurface 是否释放SurfaceTexture资源*/abstract fun closeCamera(releaseSurface:Boolean = true)/*** 切换相机前后置*/fun switchCamera(surfaceTexture: SurfaceTexture?) {closeCamera(mCustomSurfaceTexture == null || surfaceTexture !=null)//如果使用用户自定义的surfaceTexture或者之前设置过surfaceTexture就releasemCameraFacing = if (mCameraFacing == FUCameraFacingEnum.CAMERA_FRONT) FUCameraFacingEnum.CAMERA_BACK else FUCameraFacingEnum.CAMERA_FRONTmCameraOrientation = if (mCameraFacing == FUCameraFacingEnum.CAMERA_FRONT) mFrontCameraOrientation else mBackCameraOrientationif(surfaceTexture!= null){mCustomSurfaceTexture = surfaceTexture}openCamera()}/*** 设置相机放大等级*/abstract fun setZoomRatio(zoomRatio: Float)}

核心能力抽象出来后,剩下要做的就是camera1和camera2分别实现了。具体的实现这里就不贴代码了,给个github链接,各位自己下载直接用吧:GitHub - 279154451/Camera: Camera工具

相关文章:

camera功能真的那么难用吗

背景 Android开发工作过程中&#xff0c;经常需要用到camera相关能力&#xff0c;比如&#xff1a;人脸识别&#xff0c;ai识别&#xff0c;拍照预览&#xff0c;摄像头录制等等需求。都需要使用到camera&#xff0c;且需要拿到camera的预览数据。但是每次开发这块代码都比较繁…...

Model Context Protocol (MCP) 是一个前沿框架

微软发布了 Model Context Protocol (MCP) 课程&#xff1a;mcp-for-beginners。 Model Context Protocol (MCP) 是一个前沿框架&#xff0c;涵盖 C#、Java、JavaScript、TypeScript 和 Python 等主流编程语言&#xff0c;规范 AI 模型与客户端应用之间的交互。 MCP 课程结构 …...

SQL Server 日期时间类型全解析:从精确存储到灵活转换

SQL Server 日期时间类型全解析&#xff1a;从精确存储到灵活转换 一、引言&#xff1a;日期时间处理的核心挑战 在数据管理中&#xff0c;日期时间类型是最常用却最容易出错的数据类型之一。不同业务场景对时间精度、时区感知、存储效率的需求差异极大&#xff1a; 金融交易…...

Android Test3 获取的ANDROID_ID值不同

Android Test3 获取的ANDROID_ID值不同 这篇文章来说明上一篇文章中说到的一个现象&#xff1a;在同一个项目中&#xff0c;创建不同的 app module&#xff0c;运行同一段测试代码&#xff0c;获取到的 ANDROID_ID 的值不同。 我也是第一次认真研究这个现象&#xff0c;这个还…...

[蓝桥杯 2024 国 B] 立定跳远

问题描述 在运动会上&#xff0c;小明从数轴的原点开始向正方向立定跳远。项目设置了 n 个检查点 a1,a2,...,an且 ai≥ai−1>0。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时&#xff0c;小明可以自行再增加 m 个检查点让自己跳得更轻松。在运动会前&#xf…...

内容力重塑品牌增长:开源AI大模型驱动下的智能名片与S2B2C商城赋能抖音生态种草范式

摘要&#xff1a;内容力已成为抖音生态中品牌差异化竞争的核心能力&#xff0c;通过有价值、强共鸣的内容实现产品"种草"与转化闭环。本文基于"开源AI大模型AI智能名片S2B2C商城小程序源码"技术架构&#xff0c;提出"技术赋能内容"的新型种草范式…...

手机号在网状态查询接口如何用PHP实现调用?

一、什么是手机号在网状态查询接口 通过精准探测手机号的状态&#xff0c;帮助平台减少此类问题的发生&#xff0c;提供更个性化的服务或进行地域性营销 二、应用场景 1. 金融风控 通过运营商在网态查询接口&#xff0c;金融机构可以核验贷款申请人的手机状态&#xff0c;拦…...

【Java微服务组件】分布式协调P4-一文打通Redisson:从API实战到分布式锁核心源码剖析

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录 引言Redisson基本信息Redisson网站 Redisson应用…...

一个简单的德劳内三角剖分实现

德劳内&#xff08;Delaunay&#xff09;三角剖分是一种经典的将点集进行三角网格化预处理的手段&#xff0c;在NavMesh、随机地牢生成等场景下都有应用。 具体内容百度一大堆&#xff0c;就不介绍了。 比较知名的算法是Bowyer-Watson算法&#xff0c;也就是逐点插入法。 下雨闲…...

Python入门手册:异常处理

在编程过程中&#xff0c;异常处理是一个非常重要的环节。它可以帮助我们处理程序运行时可能出现的错误和异常情况&#xff0c;确保程序的稳定性和可靠性。Python提供了强大的异常处理机制&#xff0c;使得我们能够优雅地处理各种异常情况。今天&#xff0c;就让我们一起深入学…...

C#子线程更新主线程UI及委托回调使用示例

1.声明线程方法 2.线程中传入对象 3.声明委托与使用 声明委托对象 委托作为参数传入方法 4.在线程中传入委托 5.调用传入的委托...

使用VuePress2.X构建个人知识博客,并且用个人域名部署到GitHub Pages中

使用VuePress2.X构建个人知识博客&#xff0c;并且用个人域名部署到GitHub Pages中 什么是VuePress VuePress 是一个以 Markdown 为中心的静态网站生成器。你可以使用 Markdown 来书写内容&#xff08;如文档、博客等&#xff09;&#xff0c;然后 VuePress 会帮助你生成一个…...

手写Promise.all

前言 之前在看远方os大佬直播的时候看到有让手写的Promise.all的问题&#xff0c;然后心血来潮自己准备手写一个 开始 首先&#xff0c;我们需要明确原本js提供的Promise.all的特性 Promise.all返回的是一个Promise如果传入的数据中有一个reject即整个all返回的就是reject&…...

调试器基本原理

调试器基本原理 前言 调试器(debugger)&#xff0c;是一种用于控制其他程序执行流程、监控和修改其他程序状态的软件工具。 调试器通过实时分析程序的执行状态&#xff0c;协助开发者定位代码错误、了解程序工作原理、性能调优及逆向工程等。 1. 调试器核心功能 1.1 控制程…...

2025年6月|注意力机制|面向精度与推理速度提升的YOLOv8模型结构优化研究:融合ACmix的自研改进方案

版本&#xff1a; 8.3.143(Ultralytics YOLOv8框架) ACmix模块原理 在目标检测任务中&#xff0c;小目标&#xff08;如裂缝、瑕疵、零件边缘等&#xff09;由于其尺寸较小、纹理信息稀疏&#xff0c;通常更容易受到图像中复杂背景或噪声的干扰&#xff0c;从而导致漏检或误检…...

JAVA开发代码小工具集合

目录 前言编号生成工具EasyExcel 工具断言工具HTTP 工具字符串 工具验证码生成工具Excel 工具Class 工具Enum 工具分页工具断言工具2IP 地址工具Map 工具 前言 这些工具都是日常开发中能用到的&#xff0c;前后端都有&#xff0c;觉得好用就拿过来了… 编号生成工具 import j…...

利用qcustomplot绘制曲线图

本文详细介绍了qcustomplot绘制曲线图的流程&#xff0c;一段代码一段代码运行看效果。通过阅读本文&#xff0c;读者可以了解到每一项怎么用代码进行配置&#xff0c;进而实现自己想要的图表效果。&#xff08;本文只针对曲线图&#xff09; 1 最简单的图形&#xff08;入门&…...

【基础算法】枚举(普通枚举、二进制枚举)

文章目录 一、普通枚举1. 铺地毯(1) 解题思路(2) 代码实现 2. 回文日期(1) 解题思路思路一&#xff1a;暴力枚举思路二&#xff1a;枚举年份思路三&#xff1a;枚举月日 (2) 代码实现 3. 扫雷(2) 解题思路(2) 代码实现 二、二进制枚举1. 子集(1) 解题思路(2) 代码实现 2. 费解的…...

智能对联网页小程序的仓颉之旅

#传统楹联遇上AI智能体&#xff1a;我的Cangjie Magic开发纪实 引言&#xff1a;一场跨越千年的数字对话 "云对雨&#xff0c;雪对风&#xff0c;晚照对晴空"。昨天晚上星空璀璨&#xff0c;当我用仓颉语言写下第一个智能对联网页小程序的Agent DSL代码时&#xff0…...

Go字符串切片操作详解:str1[:index]

在Go语言中&#xff0c;return str1[:index] 是一个​​字符串切片操作​​&#xff0c;它截取字符串的一部分。让我们深入解析这个操作的含义和原理&#xff1a; 基本语法和含义 str1&#xff1a;原始字符串[:index]&#xff1a;切片操作符str1[:index]&#xff1a; ​​起始…...

JavaScript 本地存储 (localStorage) 完全指南

文章目录 JavaScript 本地存储 (localStorage) 完全指南 &#x1f510;一、什么是 localStorage&#xff1f;&#x1f4a1;二、如何使用 localStorage&#xff1f;&#x1f527;1. 存储数据2. 读取数据3. 删除数据4. 清空所有数据 三、存储对象和数组的技巧 &#x1f3a8;1. 存…...

从golang的sync.pool到linux的slab分配器

最近学习golang的时候&#xff0c;看到golang并发编程中有一个sync.pool&#xff0c;即对象池&#xff0c;猛地一看这不跟linux的slab分配器类似嘛&#xff0c;赶紧学习记录下 这里先总结下设计sync.pool和slab的目的 sync.pool 为了缓解特定类型的对象频繁创建和销毁&#x…...

Python分形几何可视化—— 复数迭代、L系统与生物分形模拟

Python分形几何可视化—— 复数迭代、L系统与生物分形模拟 本节将深入探索分形几何的奇妙世界&#xff0c;实现Mandelbrot集生成器和L系统分形树工具&#xff0c;并通过肺部血管分形案例展示分形在医学领域的应用。我们将使用Python的NumPy进行高效计算&#xff0c;结合Matplo…...

【超详细】英伟达Jetson Orin NX-YOLOv8配置与TensorRT测试

文章主要内容如下&#xff1a; 1、基础运行环境配置 2、Torch-GPU安装 3、ultralytics环境配置 4、Onnx及TensorRT导出详解 5、YOLOv8推理耗时分析 基础库版本&#xff1a;jetpack5.1.3, torch-gpu2.1.0, torchvision0.16.0, ultralytics8.3.146 设备的软件开发包基础信息 需…...

Go语言学习-->项目中引用第三方库方式

Go语言学习–&#xff1e;项目中引用第三方库方式 1 执行 go mod tidy 分析引入的依赖有没有正常放在go.mod里面 找到依赖的包会自动下载到本地 并添加在go.mod里面 执行结果&#xff1a; 2 执行go get XXXX&#xff08;库的名字&#xff09;...

Vue Fragment vs React Fragment

文章目录 前言&#x1f9e9; 一、概念对比&#xff1a;Vue Fragment vs React Fragment&#x1f4e6; 二、使用示例对比✅ Vue 3 中使用 Fragment✅ React 中使用 Fragment &#x1f50d; 三、差异解析1. **使用方式**2. **传递属性&#xff08;如 key&#xff09;**3. **插槽系…...

【LRU】 (最近最少使用)

LRU (最近最少使用) 文章目录 LRU (最近最少使用)一、LRU是什么&#xff1f;二、实现1.常规算法2.双栈更替总结 一、LRU是什么&#xff1f; LRU&#xff08;Least Recently Used&#xff09;是一种常见的缓存淘汰策略&#xff0c;核心思想是 “淘汰最长时间未被使用的缓存数据…...

每日Prompt:云朵猫

提示词 仰视&#xff0c;城镇的天空&#xff0c;一片形似猫咪的云朵&#xff0c;用黑色的简笔画&#xff0c;勾勒出猫咪的形状&#xff0c;可爱&#xff0c;俏皮&#xff0c;极简...

AI浪潮下的IT行业:威胁、转变与共生之道

目录 前言1 AI在IT行业的具体应用场景1.1 软件开发中的AI助手1.2 运维与监控的智能化1.3 测试自动化与质量保障1.4 安全防护中的智能威胁识别 2 AI对IT从业者的实际影响2.1 工作内容的结构性变化2.2 技能结构的再平衡 3 IT从业者不可替代的能力与价值3.1 复杂系统的架构与抽象能…...

基于功能基团的3D分子生成扩散模型 - D3FG 评测

D3FG 是一个在口袋中基于功能团的3D分子生成扩散模型。与通常分子生成模型直接生成分子坐标和原子类型不同&#xff0c;D3FG 将分子分解为两类组成部分&#xff1a;官能团和连接体&#xff0c;然后使用扩散生成模型学习这些组成部分的类型和几何分布。 一、背景介绍 D3FG 来源…...