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工具

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84119.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

USART 串口通信全解析:原理、结构与代码实战

文章目录 USARTUSART简介USART框图USART基本结构数据帧起始位侦测数据采样波特率发生器串口发送数据 主要代码串口接收数据与发送数据主要代码 USART USART简介 一、USART 的全称与基本定义 英文全称 USART&#xff1a;Universal Synchronous Asynchronous Receiver Transmi…

LeetCode 152. 乘积最大子数组 - 动态规划解法详解

文章目录 问题描述解题思路动态规划状态定义状态转移方程完整代码实现复杂度分析示例解析关键点说明总结问题描述 给定一个整数数组 nums,请找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组对应的乘积。 示例: 输入: [2,3,-2,4] 输出: 6 解…

Python: 操作 Excel折叠

💡Python 操作 Excel 折叠(分组)功能详解(openpyxl & xlsxwriter 双方案) 在处理 Excel 报表或数据分析时,我们常常希望通过 折叠(分组)功能 来提升表格的可读性和组织性。本文将详细介绍如何使用 Python 中的两个主流 Excel 操作库 —— openpyxl 和 xlsxwriter …

28、元组的遍历

const_cast 只能用于指针或引用类型&#xff0c;而不能用于基本类型如 int。 在的代码中&#xff0c;试图将 i 转换为 const_cast<int>(i)&#xff0c;这是不合法的。 可以使用模板函数来获取元组中的元素&#xff0c;而不是使用 const_cast。以下是修正后的代码&#x…

sendDefaultImpl call timeout(rocketmq)

rocketmq 连接异常 senddefaultimpl call timeout-腾讯云开发者社区-腾讯云 第一种情况&#xff1a; 修改broker 的配置如下&#xff0c;注意brokerIP1 这个配置必须有&#xff0c;不然 rocketmq-console 显示依然是内网地址 caused by: org.apache.rocketmq.remoting.excep…

【仿生机器人】仿生机器人智能架构:从感知到个性的完整设计

仿生机器人智能架构&#xff1a;从感知到个性的完整设计 仿生机器人不仅需要模拟人类的外表&#xff0c;更需要具备类人的认知、情感和个性特征。本研究提出了一个综合性的软件架构&#xff0c;实现了从环境感知到情感生成、从实时交互到人格塑造的完整智能系统。该架构突破了…

Spring Boot微服务架构(十一):独立部署是否抛弃了架构优势?

Spring Boot 的独立部署&#xff08;即打包为可执行 JAR/WAR 文件&#xff09;本身并不会直接丧失架构优势&#xff0c;但其是否体现架构价值取决于具体应用场景和设计选择。以下是关键分析&#xff1a; 一、独立部署与架构优势的关系 内嵌容器的优势保留 Spring Boot 独立部署…

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…

2025年6月3日面试总结

1. 面试官问一台机器内存或者磁盘占用99% 再点一下就挂了&#xff0c;个人刚开始反应内存不足加内存&#xff0c;磁盘不足加磁盘&#xff0c;还有啥办法&#xff0c;有些时候没干过的事一定要大胆&#xff0c;敲命令都敲不成&#xff0c;只能换磁盘了和加内存了&#xff0c;要么…

从上下文学习和微调看语言模型的泛化:一项对照研究

大型语言模型表现出令人兴奋的能力&#xff0c;但也可以从微调中表现出令人惊讶的狭窄泛化。例如&#xff0c;他们可能无法概括为简单的关系反转&#xff0c;或者无法根据训练信息进行简单的逻辑推理。这些未能从微调中概括出来的失败可能会阻碍这些模型的实际应用。另一方面&a…

解决cocos 2dx/creator2.4在ios18下openURL无法调用的问题

由于ios18废弃了旧的openURL接口&#xff0c;我们需要修改CCApplication-ios.mm文件的Application::openURL方法&#xff1a; //修复openURL在ios18下无法调用的问题 bool Application::openURL(const std::string &url) {// NSString* msg [NSString stringWithCString:…

Go 语言并发编程基础:Goroutine 的创建与调度

Go 语言的并发模型是其最显著的语言特性之一。Goroutine 是 Go 实现并发的核心机制&#xff0c;它比线程更轻量&#xff0c;调度效率极高。 本章将带你了解 Goroutine 的基本概念、创建方式以及背后的调度机制。 一、什么是 Goroutine&#xff1f; Goroutine 是由 Go 运行时&a…

网页绘制表格

说明&#xff1a; border"1"&#xff1a;设置表格边框宽度为 1 像素&#xff08;可调整数值改变边框粗细&#xff09;。cellspacing"0"&#xff1a;设置单元格间距为 0&#xff08;去除边框间的空白间隙&#xff09;。<thead>&#xff1a;定义表头区…

Python爬虫实战:研究Unirest库相关技术

一、引言 在当今信息爆炸的时代,网络数据的获取与分析变得尤为重要。Python 作为一种功能强大且易于学习的编程语言,在网络爬虫领域有着广泛的应用。Unirest 库是一个轻量级的 HTTP 客户端库,它提供了简洁的 API,使得发送 HTTP 请求变得更加容易。本论文将详细分析如何使用…

二、【ESP32开发全栈指南:ESP32 GPIO深度使用】

GPIO&#xff08;通用输入输出&#xff09; 是ESP32最基础却最核心的功能。本文将带你深入ESP32的GPIO操作&#xff0c;通过按键读取和LED控制实现物理按键→ESP32→LED的完整信号链路。 一、ESP32 GPIO核心特性速览 34个可编程GPIO&#xff08;部分引脚受限&#xff09;输入模…

调用.net DLL让CANoe自动识别串口号

1.前言 CANoe9.0用CAPL控制数控电源_canoe读取程控电源电流值-CSDN博客 之前做CAPL通过串口控制数控电源&#xff0c;存在一个缺点&#xff1a;更换电脑需要改串口号 CSDN上有类似的博客&#xff0c;不过要收费&#xff0c;本文根据VID和PID来自动获取串口号&#xff0c;代码…

SpringBoot十二、SpringBoot系列web篇之过滤器Filte详解

一、前言 JavaWeb三大组件Servlet、Filter、Listener&#xff0c;其中之一便是过滤器Filter。 其实&#xff0c;Filter我们平常用的不多&#xff0c;一般多为项目初期搭建web架构的时候使用&#xff0c;后面用的就少了&#xff0c;在日常业务开发中不太可能碰到需要手写Filte…

Java实现飞机射击游戏:从设计到完整源代码

JAVA打飞机游戏毕业设计 一、游戏概述 本游戏基于Java Swing开发&#xff0c;实现了经典的飞机射击游戏。玩家控制一架战斗机在屏幕底部移动&#xff0c;发射子弹击落敌机&#xff0c;同时躲避敌机攻击。游戏包含多个关卡&#xff0c;随着关卡提升&#xff0c;敌机速度和数量…

通俗易懂linux环境变量

如果想要清楚的了解环境变量&#xff0c;我觉得我们需要先大致搞清楚一个简单的事——什么是会话&#xff1f; 会话大致是什么&#xff1f; 在这里我们的目的是更好的理解环境变量&#xff0c;所以适当讲解一下会话即可。通常我们都是用xshell连接远程服务器&#xff0c;都会打…

【补题】Codeforces Round 715 (Div. 2) C. The Sports Festival

题意&#xff1a;给你一个序列&#xff0c;你可以对它重新排序&#xff0c;然后使每个i&#xff0c;max(a0,a1……ai)-min(a0,a1……ai)最小。问答案是多少 思路&#xff1a; C. The Sports Festival&#xff08;区间DP&#xff09;-CSDN博客 区间dp&#xff0c;完全没想到…