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实现效果

实际运行效果展示如下:

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

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

相关文章

【HarmonyOS NEXT】网络请求 - 分页加载

分页加载关键字&#xff1a;onReachEnd 一、申请网络权限 在 module.json5 文件中&#xff0c;添加网络权限&#xff1a; {"module": {..."requestPermissions": [{"name": "ohos.permission.INTERNET","usedScene": {&qu…

网络安全常用易混术语定义与解读(Top 20)

没有网络安全就没有国家安全&#xff0c;网络安全已成为每个人都重视的话题。随着技术的飞速发展&#xff0c;各种网络攻击手段层出不穷&#xff0c;保护个人和企业的信息安全显得尤为重要。然而&#xff0c;在这个复杂的领域中&#xff0c;许多专业术语往往让人感到困惑。为了…

portainer教程-docker可视化管理工具

很多朋友刚接触docker 学习&#xff0c;就想问 docker有图形化界面吗 &#xff0c;答案是肯定的&#xff0c; 这里白眉大叔 给大家推荐 Docker可视化管理平台 -- Portainer 1- 运行Portainer&#xff1a; docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restarta…

【保姆级讲解C语言中的运算符的优先级!】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 🪶C语言中的运算符的优先级 🪶C语言中的运算符的优先级决定了…

二、C#数据类型

本文是网页版《C# 12.0 本质论》第二章解读。欲完整跟踪本系列文章&#xff0c;请关注并订阅我的Essential C# 12.0解读专栏。 前言 数据类型&#xff08;Data Type&#xff09;是一个很恼人的话题。 似乎根本没必要对数据类型进行展开讲解&#xff0c;因为人人都懂。 但是…

16、基于共享内存二叉树的LRU

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 在共享内存的二叉树上尝试了LR…

grafana大坑,es找不到时间戳 | No date field named timestamp found

grafana大坑&#xff0c;es找不到时间戳。最近我这边的es重新装了一遍&#xff0c;结果发现grafana连不上elasticsearch了&#xff08;以下简称es&#xff09;&#xff0c;排查问题查了好久一直以为是es没有装成功或者两边的版本不兼容&#xff0c;最后才发现是数值类型问题 一…

XSLFO 文档:格式化 XML 数据的艺术

XSLFO 文档&#xff1a;格式化 XML 数据的艺术 1. 引言 XSLFO&#xff08;Extensible Stylesheet Language Formatting Objects&#xff09;是一种基于 XML 的语言&#xff0c;用于描述如何将 XML 数据格式化为可视化的文档&#xff0c;如 PDF 或打印的页面。XSLFO 提供了一种…

过滤器、同步异步、跨域问题、json数据格式字符串

1、过滤器 过滤器是将JavaEE中对请求和响应进行拦截的技术&#xff0c;定义一个类实现Filter接口&#xff0c;可以让某些请求地址在到达servlet之前进入到指定的过滤器中从而实现统一管理&#xff0c;例如编码过滤&#xff0c;权限过滤等进行统一过滤。 下面是一个编码过滤的…

Java 基础语法教程

1. 类和对象 Java 是一种面向对象的编程语言&#xff0c;它使用类和对象来组织代码。一个 Java 程序可以认为是一系列对象的集合&#xff0c;而这些对象通过调用彼此的方法来协同工作。 1.1 类 类&#xff08;Class&#xff09;是一个模板&#xff0c;它描述一类对象的行为和…

浅聊 Three.js 屏幕空间反射SSR-SSRShader

浅聊 Three.js 屏幕空间反射SSR(2)-SSRShader 前置基础 渲染管线中的相机和屏幕示意图 -Z (相机朝向的方向)||| -------------- <- 屏幕/投影平面| | || | || | (f) | <- 焦距| | ||…

在 Ubuntu 22.04/20.04 安装 CVAT 和 SAM 指南

1. 安装 Docker 和 Docker Compose sudo apt-get update sudo apt-get --no-install-recommends install -y \apt-transport-https \ca-certificates \curl \gnupg-agent \software-properties-common curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-ke…

跨平台游戏引擎 Axmol-2.1.4 发布

2.1.4 版本是用于错误修复和改进的次要 LTS 版本&#xff0c;感谢 axmol 的所有贡献者 相对于 2.1.3 的重大变化&#xff1a; 添加 JobSystem 支持添加 cmake 选项 AX_WASM_INITIAL_MEMORY添加 Linux WebView 实现改进 curl 下载实现 使用curl_multi_poll代替select使用curl_…

java-如何打破双亲委派机制

在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;双亲委派模型是一种类加载器之间的层次模型&#xff0c;它定义了类加载的规则&#xff0c;即当一个类需要被加载时&#xff0c;JVM默认的行为是首先请求父类加载器加载该类&#xff0c;只有当父类加载器无法加载该类时&a…

【BUG】已解决:error: legacy - install - failure

error: legacy - install - failure 目录 error: legacy - install - failure 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&…

51单片机14(独立按键实验)

一、按键介绍 1、按键是一种电子开关&#xff0c;使用的时候&#xff0c;只要轻轻的按下我们的这个按钮&#xff0c;按钮就可以使这个开关导通。 2、当松开这个手的时候&#xff0c;我们的这个开关&#xff0c;就断开开发板上使用的这个按键&#xff0c;它的内部结构&#xff…

免费分享:2021年度全国城乡划分代码(附下载方法)

《关于统计上划分城乡的规定》指出&#xff1a;“本规定作为统计上划分城乡的依据&#xff0c;不改变现有的行政区划、隶属关系、管理权限和机构编制&#xff0c;以及土地规划、城乡规划等有关规定”。统计用区划代码和城乡划分代码用于统计工作&#xff0c;需要在其他工作中使…

Transforms

深度学习中的Transforms 概述 Transforms在深度学习中起到了关键的作用&#xff0c;主要用于数据预处理、特征提取和数据增强&#xff08;Data Augmentation&#xff09;。通过对数据进行各种变换&#xff0c;能够提升模型的训练效果和泛化能力。 数据增强&#xff08;Data …

回溯题目的套路总结

前言 昨天写完了LeeCode的7&#xff0c;8道回溯算法的题目&#xff0c;写一下总结&#xff0c;这类题目的共同特点就是暴力搜索问题&#xff0c;排列组合或者递归&#xff0c;枚举出所有可能的答案&#xff0c;思路很简单&#xff0c;实现起来的套路也很通用&#xff0c;一…

java题目之抽奖以及优化方式

public class Main9 {public static void main(String[] args) {int[]arr{ 2,588,888,1000,10000};int [] newArrnew int[arr.length];//3.抽奖Random rnew Random();//因为有5个奖项,所以这里循环五次for (int i 0; i <5 ; ) {//获取随机索引int randomIndexr.nextInt(arr…