Android APP CameraX应用(02)预览流程

说明:camera子系统 系列文章针对Android12.0系统,主要针对 camerax API框架进行解读。


1 CameraX简介

1.1 CameraX 预览流程简要解读

CameraX 是 Android 上的一个 Jetpack 支持库,它提供了一套统一的 API 来处理相机功能,无论 Android 设备上的相机硬件和 Android 版本如何。CameraX 旨在简化相机应用的开发流程,提供更好的兼容性和扩展性。以下是 CameraX 预览的基本流程的简要解读:

  1. 添加依赖: 在项目的 build.gradle 文件中添加 CameraX 库的依赖。

  2. 获取 CameraX 核心实例: 使用 CameraX的getCameraProvider() 方法获取 CameraProvider 实例,这是访问 CameraX 功能的基础。

  3. 配置预览用 Surface: 创建一个 PreviewSurfaceViewPreviewView 作为相机预览的界面,并配置一个 Surface 以供相机输出。

  4. 构建预览用例: 使用 PreviewConfig.Builder 构建一个预览配置,并将其与 PreviewSurface 结合,创建一个 PreviewUseCase

  5. 设置预览配置: 通过 CameraProviderbindToLifecycle 方法,将预览用例绑定到 Activity 或 Fragment 的生命周期上。注意,在bindToLifecycle 前要先进行unbind操作。

  6. 启动预览与关闭预览: 调用 PreviewUseCasestart() 方法开始预览,这会在界面上显示相机捕获的实时画面。 当不再需要预览时,调用 PreviewUseCasestop() 方法停止预览,并释放相关资源。

  7. 处理预览数据: 如果需要对预览数据进行处理,比如应用滤镜或进行图像分析,可以通过实现 Preview.PreviewSurfaceProvider 接口来获取 Surface 并进行自定义处理。

CameraX 的设计使得相机功能的集成变得更加模块化和易于管理,同时也支持高级功能,如自动对焦、自动曝光和自动白平衡等。

1.2  CameraX与camera2之间的关系

CameraX 和 Camera2 API 都是用于在 Android 设备上访问和控制相机硬件的解决方案,但它们在设计目的、使用方式和目标用户上有所不同。以下是 CameraX 和 Camera2 API 之间的关系说明:

  1. Camera2 API

    • 底层访问:Camera2 API 是 Android 平台提供的一个低级相机访问接口,它允许开发者直接与相机硬件交互,进行详细的相机参数配置和控制。
    • 复杂性:由于 Camera2 API 提供了对相机硬件的直接控制,使用它需要处理许多复杂的细节,比如处理不同的相机状态、同步问题和性能优化。
    • 兼容性:Camera2 API 从 Android 5.0(Lollipop)开始引入,因此它需要在不同版本的 Android 设备上进行兼容性处理。
  2. CameraX

    • 简化访问:CameraX 是一个 Jetpack 支持库,旨在简化 Camera2 API 的使用,提供更简单、更一致的相机访问接口。
    • 跨版本兼容:CameraX 通过抽象 Camera2 API 的复杂性,为开发者提供一个统一的 API 集,使其能够更容易地在不同版本的 Android 设备上实现相机功能。
    • 生命周期感知:CameraX 与 Android 生命周期感知组件(如 Activity 和 Fragment)集成,使得相机功能的管理更加自然和方便。
  3. 关系

    • 基于 Camera2:CameraX 实际上是在 Camera2 API 的基础上构建的,它封装了 Camera2 API 的复杂性,提供了更高级的抽象。
    • 简化开发:对于大多数应用开发者来说,CameraX 提供了一个更简单、更易于使用的接口,使得他们可以不必深入了解 Camera2 API 的细节,就能实现相机功能。
    • 扩展性:尽管 CameraX 简化了相机访问,但它仍然保留了扩展性,允许开发者在需要时访问底层的 Camera2 API 功能。
  4. 使用场景

    • Camera2 API:适合那些需要对相机硬件进行精细控制的应用,比如专业的摄影应用或需要特定相机功能的应用。
    • CameraX:适合大多数需要相机功能的应用,特别是那些希望快速集成相机功能并减少开发复杂性的应用。

总结来说,CameraX 可以看作是 Camera2 API 的一个高级封装,它为开发者提供了一个更简单、更一致的接口来访问和控制 Android 设备上的相机硬件。通过使用 CameraX,开发者可以更容易地实现相机功能,同时减少对底层 Camera2 API 的依赖。

2 预览流程代码完整解读(android Q)

2.1 添加deps依赖

在项目的 build.gradle 文件中添加 CameraX 库的依赖。build.gradle 中添加deps,具体如下:

dependencies {...implementation libs.camera.viewimplementation "androidx.camera:camera-core:1.3.4"
// CameraX Camera2 extensions[可选]拓展库可实现人像、HDR、夜间和美颜、滤镜但依赖于OEMimplementation "androidx.camera:camera-camera2:1.3.4"
// CameraX Lifecycle library[可选]避免手动在生命周期释放和销毁数据implementation "androidx.camera:camera-lifecycle:1.3.4"
// CameraX View class[可选]最佳实践,最好用里面的PreviewView,它会自行判断用SurfaceView还是TextureView来实现implementation libs.androidx.camera.view.v100alpha23...
}

2.2 layout布局文件的构建

布局文件 h264_encode_camerax.xml(可自定义) 内容如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/main"tools:context=".MainActivity"><androidx.camera.view.PreviewViewandroid:id="@+id/viewFinder"android:layout_width="372dp"android:layout_height="240dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:layout_width="match_parent"android:layout_height="50dp"android:text="@string/startCapture"android:id="@+id/button"app:layout_constraintTop_toBottomOf="@id/viewFinder"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintHorizontal_bias="0.5"/></androidx.constraintlayout.widget.ConstraintLayout>

2.3 关于权限部分的处理

关于权限,需要在AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.CAMERA"/>

关于权限的请求等,这里给出一个工具类参考代码:

public class Permission {public static final int REQUEST_MANAGE_EXTERNAL_STORAGE = 1;//需要申请权限的数组private static final String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.CAMERA};//保存真正需要去申请的权限private static final List<String> permissionList = new ArrayList<>();public static int RequestCode = 100;public static void requestManageExternalStoragePermission(Context context, Activity activity) {if (!Environment.isExternalStorageManager()) {showManageExternalStorageDialog(activity);}}private static void showManageExternalStorageDialog(Activity activity) {AlertDialog dialog = new AlertDialog.Builder(activity).setTitle("权限请求").setMessage("请开启文件访问权限,否则应用将无法正常使用。").setNegativeButton("取消", null).setPositiveButton("确定", (dialogInterface, i) -> {Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);activity.startActivityForResult(intent, REQUEST_MANAGE_EXTERNAL_STORAGE);}).create();dialog.show();}public static void checkPermissions(Activity activity) {for (String permission : permissions) {if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {permissionList.add(permission);}}if (!permissionList.isEmpty()) {requestPermission(activity);}}public static void requestPermission(Activity activity) {ActivityCompat.requestPermissions(activity,permissionList.toArray(new String[0]),RequestCode);}
}

该代码主要是给后面即将提到的主代码使用。

2.4 CameraX主流程代码参考实现

这里以 H264encoderCameraXActivity 为例,给出一个预览流程代码的参考实现。代码如下:

public class H264encoderCameraXActivity extends AppCompatActivity {private Button mButton;Context mContext;private PreviewView previewView;private ImageAnalysis imageAnalysis;private ExecutorService executor;private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;private boolean isCapturePreview = false;ProcessCameraProvider mCameraProvider;Preview mPreview;H264Encode h264Encode = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);EdgeToEdge.enable(this);mContext = this;setContentView(R.layout.h264_encode_camerax);ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);return insets;});//权限处理Permission.checkPermissions(this);Permission.requestManageExternalStoragePermission(getApplicationContext(), this);executor = Executors.newSingleThreadExecutor();previewView = findViewById(R.id.viewFinder);mButton = findViewById(R.id.button);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {isCapturePreview = !isCapturePreview;if(isCapturePreview){mButton.setText(R.string.startCapture);startCamera();}else{mButton.setText(R.string.stopCapture);stopCamera();}}});// 初始化 ImageAnalysisimageAnalysis = new ImageAnalysis.Builder().setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build();imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {@Overridepublic void analyze(@NonNull ImageProxy imageProxy) {Log.d("XXXX","-----------------get Data");// 处理图像数据}});}private void startCamera() {// 请求 CameraProvidercameraProviderFuture = ProcessCameraProvider.getInstance(this);//检查 CameraProvider 可用性,验证它能否在视图创建后成功初始化cameraProviderFuture.addListener(() -> {try {mCameraProvider = cameraProviderFuture.get();bindPreview(mCameraProvider);} catch (ExecutionException | InterruptedException e) {e.printStackTrace();}}, ContextCompat.getMainExecutor(this));}//选择相机并绑定生命周期和用例private void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {mPreview = new Preview.Builder().build();CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();cameraProvider.unbindAll();cameraProvider.bindToLifecycle(this, cameraSelector, mPreview, imageAnalysis);mPreview.setSurfaceProvider(previewView.getSurfaceProvider());}private void stopCamera() {if ((mCameraProvider != null) && mCameraProvider.isBound(mPreview)) {mCameraProvider.unbindAll();imageAnalysis.clearAnalyzer();executor.shutdown();}}@Overrideprotected void onDestroy() {super.onDestroy();if (imageAnalysis != null) {imageAnalysis.clearAnalyzer(); // 清除分析器}if (executor != null) {executor.shutdown(); // 关闭线程池}}
}

这里和CameraX相关的方法主要是startCamera、bindPreview和stopCamera。

2.5 CameraX预览demo实现效果

实际运行效果展示如下:

ef426a66ce804f1e9a03f3b07367dbc5.png

 

 

 

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

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

相关文章

爬虫学习3:爬虫的深度爬取

爬虫的深度爬取和爬取视频的方式 深度爬取豆瓣读书 import time import fake_useragent import requests from lxml import etree head {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 …

双向链表(C语言版)

1. 双向链表的结构 注意&#xff1a;这里的“带头”跟单链表的“头结点”是两个概念&#xff0c;实际上在单链表阶段称呼不太严谨&#xff0c;但是为了更好地理解就直接称为单链表的头结点。带头链表里的头结点&#xff0c;实际为“哨兵位”&#xff0c;哨兵位结点不存储任何有…

MaxSite CMS v180 文件上传漏洞(CVE-2022-25411)

前言 CVE-2022-25411 是一个影响 Maxsite CMS v180 的远程代码执行漏洞。攻击者可以通过上传一个特制的 PHP 文件来利用这个漏洞&#xff0c;从而在受影响的系统上执行任意代码。 漏洞描述 该漏洞存在于 Maxsite CMS v180 的文件上传功能中。漏洞利用主要通过允许上传带有危…

Vue 3项目安装Element-Plus

Element Plus 是一个基于 Vue 3 的现代前端UI框架&#xff0c;它旨在提升开发体验&#xff0c;并为开发者提供高效、优雅的组件。如果你正在使用 Vue 3 进行项目开发&#xff0c;那么安装和集成 Element Plus 是一个不错的选择。在本文中&#xff0c;博主将详细介绍如何在 Vue …

【SASS/SCSS(三)】样式的复用与动态计算(@mixin和@function)

目录 一、mixin 1、定义复用的样式代码&#xff0c;接受传参&#xff0c;搭配include使用。 位置传参 关键词传参 ...语法糖接受传入的任意参数 2、在mixin中使用content&#xff0c;获取外部对mixin的追加内容 二、function 三、字符串——值得注意的点 很多时候&#…

智慧大棚数据库版

创建一个SMartBigHouse数据库 在数据库创建一个表用来存储数据 这边将id设为主键并将标识增量设为1 搭建Winfrom 搭建历史查询界面 串口数据&#xff0c;(这边是用的一个虚拟的串口工具&#xff0c;需要的话私) ModbusSerialMaster master;DataPointCollection wenduValues; //…

细说MCU用DMA控制ADC采样和串口传送的实现方法

目录 一、建立工程 1.相同的配置 2.配置ADC 3.配置DMA 二、代码修改 1.定义存储ADC采样结果的数组 2.启动ADC与定时器 3.编写主程序代码 4.重定义回调函数 5.查看结果 三、修改DMA模式 1. 修改DMA模式为Circular 2.查看结果 采用DMA(Direct Memory Access&#xf…

WSL2 Centos7 Docker服务启动失败怎么办?

wsl 安装的CentOS7镜像,安装了Docker之后,发现用systemctl start docker 无法将docker启动起来。 解决办法 1、编辑文件 vim /usr/lib/systemd/system/docker.service将13行注释掉,然后在下面新增14行的内容。然后保存退出。 2、再次验证 可以发现,我们已经可以正常通过s…

关于Mysql的面试题(实时更新中~)

一、主键约束与“not null unique”区别 1、作为Primary Key的域/域组不能为null&#xff0c;而Unique Key可以。 2、在一个表中只能有一个Primary Key&#xff0c;而多个Unique Key可以同时存在。unique not null 可以 将表的一列或多列定义为唯一性属性&#xff0c;而prima…

redis的集群模式

目录 1. 为什么使用redis集群 2. 主从模式 2.1修改配置文件 2.2 开启三台redis服务 2.3配置主从关系 3. 哨兵模式 3.1 监控功能 3.2 选举的机制 3.3 准备条件 4. 去中心化模式 4.1 准备三主三从 4.2 启动redis 4.3 分配槽以及主从关系 4.4 命令行的客户端 redis提供…

CAD框架介绍

1、适用范围&#xff1a;矢量编辑软件如 服装模板软件、CAD软件、绘图软件 2、支持PLT,DXF,PDF,GCode&#xff08;服装裁割指令)等矢量文件导入 3、支持简易的自动手动排料 4、直线&#xff0c;曲线等编辑功能 5、分页输出绘图指令 6、良好的框架结构&#xff1a;绘图引擎…

d3d12.dll 文件缺失如何解决?五种修复丢失问题的方法

d3d12.dll 文件缺失如何解决&#xff1f;它为什么会不见呢&#xff1f;今天&#xff0c;我们将探讨 d3d12.dll 文件的重要性、原因以及丢失时的解决策略。本文将全面介绍 d3d12.dll 文件&#xff0c;并提供五种修复丢失问题的方法。 d3d12.dll文件是什么的详细介绍 d3d12.dll …

laravel为Model设置全局作用域

如果一个项目中存在这么一个sql条件在任何情况下或大多数情况都会被使用&#xff0c;同时很容易被开发者遗忘&#xff0c;那么就非常适用于今天要提到的这个功能&#xff0c;Eloquent\Model的全局作用域。 首先看一个示例&#xff0c;有个数据表&#xff0c;结构如下&#xff1…

深入浅出WebRTC—NACK

WebRTC 中的 NACK&#xff08;Negative Acknowledgment&#xff09;机制是实时通信中处理网络丢包的关键组件。网络丢包是常见的现象&#xff0c;尤其是在无线网络或不稳定连接中。NACK 机制旨在通过请求重传丢失的数据包来减少这种影响&#xff0c;从而保持通信的连续性和质量…

vue学习笔记(十一)——开发心得(axios的封装、promise细节、vue-router开发中的使用)

1. axios的网络请求的封装 1.1 为什么要封装api? 代码分层&#xff0c;便于以后的修改&#xff0c;无需触碰逻辑页面 目标&#xff1a; 网络请求&#xff0c;不散落在各个逻辑页面里&#xff0c;封装起来方便以后修改 1.2 封装api步骤 ① 在项目 src 下新建目录 utlis &am…

C++——初识模板

前言 模板是C中的重大板块&#xff0c;是使C真正超越C语言的工具&#xff0c;在C模板没有设计出来之前其实C是没有那么被行业和社会所认可的&#xff0c;本节我们将初步了解C中的模板&#xff08;仅作大致讲解&#xff0c;具体的细枝末节将会再过几节讲解&#xff09;&#xf…

Qt多语言功能实现

本文介绍Qt多语言功能实现。 应用程序多语言支持是常用功能&#xff0c;比如产品需要出口到不同语种的国家。采用Qt的多语言支持工具可以方便实现应用程序的多语言功能。本文以中英文语言切换为例&#xff0c;简要介绍Qt的多语言功能实现。 1.界面设计 界面设计需要考虑使用…

【数据分享】2013-2022年我国省市县三级的逐日SO2数据(excel\shp格式\免费获取)

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2000——2022年的省市县三级的逐日PM2.5数据和2013-2022年的省市县三级的逐日CO数据&#xff08;均可查看之前的文章获悉详情&#xff09;&#xff01; 本次我们分享的是我国2013——2022年的省…

数据隐私保护与区块链技术的结合:新兴趋势分析

在当今数字化时代&#xff0c;数据隐私保护成为了一个备受关注的重要话题。随着个人数据的不断生成和流通&#xff0c;如何有效保护用户的隐私成为了技术创新的一个重要方向。区块链技术作为一种去中心化、安全性高且可追溯的技术手段&#xff0c;正在逐渐成为解决数据隐私保护…

golang 基础 泛型编程

&#xff08;一&#xff09; 示例1 package _caseimport "fmt"// 定义用户类型的结构体 type user struct {ID int64Name stringAge uint8 }// 定义地址类型的结构体 type address struct {ID intProvince stringCity string }// 集合转列表函数&#…