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.view
    implementation "androidx.camera:camera-core:1.3.4"
// CameraX Camera2 extensions[可选]拓展库可实现人像、HDR、夜间和美颜、滤镜但依赖于OEM
    implementation "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.PreviewView
        android: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"
        />
    <Button
        android: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;

    @Override
    protected 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() {
            @Override
            public void onClick(View view) {
                isCapturePreview = !isCapturePreview;
                if(isCapturePreview){
                    mButton.setText(R.string.startCapture);
                    startCamera();
                }else{
                    mButton.setText(R.string.stopCapture);
                    stopCamera();
                }
            }
        });

        // 初始化 ImageAnalysis
        imageAnalysis = new ImageAnalysis.Builder()
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build();
        imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
            @Override
            public void analyze(@NonNull ImageProxy imageProxy) {
                Log.d("XXXX","-----------------get Data");
                // 处理图像数据
            }
        });
    }

    private void startCamera() {
        // 请求 CameraProvider
        cameraProviderFuture = 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();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (imageAnalysis != null) {
            imageAnalysis.clearAnalyzer(); // 清除分析器
        }
        if (executor != null) {
            executor.shutdown(); // 关闭线程池
        }
    }
}

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

2.5 CameraX预览demo实现效果

实际运行效果展示如下:

ef426a66ce804f1e9a03f3b07367dbc5.png

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于微信小程序的高校排课系统 /基于微信小程序的排课管理系统/课程管理系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&a…

PE文件(十二)导入表

导入表 导入表的引入 当一个PE文件&#xff08;如.dll/.exe等&#xff09;需要使用别的模块的函数&#xff0c;也叫做依赖某模块&#xff0c;就需要一个清单来记录使用的模块&#xff08;一般为.dll文件&#xff0c;为方便理解&#xff0c;以后我们将模块都认为是.dll文件&am…

electron安装及快速创建

electron安装及快速创建 electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 详细内容见官网&#xff1a;https://www.electronjs.org/zh/docs/latest/。 今天来记录下练习中的安装过程和hello world的创建。 创建项目文件夹&#xff0c;并执行npm 初始化命…

将iPad 作为Windows电脑副屏的几种方法(二)

将iPad 作为Windows电脑副屏的几种方法&#xff08;二&#xff09; 1. 前言2. EV 扩展屏2.1 概述2.2 下载、安装、连接教程2.3 遇到的问题和解决方法2.3.1 平板连接不上电脑 3. Twomon SE3.1 概述3.2 下载安装教程 4. 多屏中心&#xff08;GlideX&#xff09;4.1 概述4.2 下载安…

东莞网站建设前期需要做好哪些工作

在进行东莞网站建设前&#xff0c;需要做好一系列的前期工作。这些工作的实施将为网站建设奠定坚实的基础&#xff0c;确保项目能够按计划顺利进行&#xff0c;并最终达到预期的目标。 首先&#xff0c;需要明确网站的定位和目标。东莞是一个经济发达的城市&#xff0c;因此&am…

Oracle系统表空间的加解密

实验环境 数据库选择的是orclpdb1&#xff0c;当前系统表空间未加密&#xff1a; SQL> show con_nameCON_NAME ------------------------------ ORCLPDB1SQL> select TABLESPACE_NAME, STATUS, ENCRYPTED from dba_tablespaces;TABLESPACE_NAME STATUS …

docker搭建python3的私有源--devpi

一、部署 # docker run -d --name devpi-lib -p 7104:7104 --env DEVPISERVER_HOST0.0.0.0 --env DEVPISERVER_PORT7104 --env DEVPISERVER_ROOT_PASSWORDpassword --env DEVPISERVER_USERlowinli --env DEVPISERVER_PASSWORDpassword --env DEVPISERVER_MIRROR_INDEXpypi --…

SAP PP学习笔记31 - 计划运行的步骤2 - Scheduling(日程计算),BOM Explosion(BOM展开)

上一章讲了计划运行的5大步骤中的前两步&#xff0c;计算净需求和计算批量大小。 SAP PP学习笔记30 - 计划运行的步骤1 - Net requirements calculation 计算净需求(主要讲了安全库存要素)&#xff0c;Lot-size calculation 计算批量大小-CSDN博客 本章继续讲计划运行的后面几…

【快速逆向二/无过程/有源码】掌上高考—2024高考志愿填报服务平台

逆向日期&#xff1a;2024.07.21 使用工具&#xff1a;Node.js 加密工具&#xff1a;Crypto-js标准库 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算法&…

spring-boot3.x整合Swagger 3 (OpenAPI 3) +knife4j

1.简介 OpenAPI阶段的Swagger也被称为Swagger 3.0。在Swagger 2.0后&#xff0c;Swagger规范正式更名为OpenAPI规范&#xff0c;并且根据OpenAPI规范的版本号进行了更新。因此&#xff0c;Swagger 3.0对应的就是OpenAPI 3.0版本&#xff0c;它是Swagger在OpenAPI阶段推出的一个…

【Linux】玩转操作系统,深入刨析进程状态与调度机制

目录 1. 进程排队2. 进程状态的表述2.1. 进程状态2.2 运行状态2.3. 阻塞状态2.4. 挂起状态 3. Linux下具体的进程状态3.1. 运行状态R3.2. 可中断睡眠状态S3.3. 不可中断睡眠状态D3.4. 停止状态T3.5. 死亡状态X3.6. 僵尸状态Z 4. 孤儿进程5. 优先级6. Linux的调度与切换6.1. 四个…

第二证券:台风的后遗症竟然是台股!

今日早盘&#xff0c;中国台湾的台湾加权指数开盘大跌逾4%&#xff0c;台积电跌超6%。此前&#xff0c;因为飓风的原因&#xff0c;台湾股市暂停生意两天。暂停生意前&#xff0c;台湾加权指数收报22871点&#xff0c;上升614点&#xff0c;涨幅高达2.76%。 剖析人士认为&…

域名解析到ipv6,并用CF隐藏端口

要求&#xff1a;域名解析到 IPv6 地址并隐藏端口 ‍ 效果&#xff1a;用域名 https://myhalo.soulio.top​ 访问http://[2409:8a62:867:4f12:56c7:5508:f7x6:8]:8080​。唯一缺点是延迟有点高。 ​​ ‍ 难度&#xff1a;需要有一定域名解析、cloudflare使用基础 ‍ 实…

[数据集][目标检测]躺坐站识别检测数据集VOC+YOLO格式9488张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;9488 标注数量(xml文件个数)&#xff1a;9488 标注数量(txt文件个数)&#xff1a;9488 标注…

【C/C++】内存管理

内存管理 一.C/C内存分布二.C内存管理方式1.new、delete操作内置类型2.new、delete操作自定义类型3.32位、64位机器的区别 三.operator new与operator delete函数四.new和delete的实现原理1.内置类型2.自定义类型1.new的原理2.delete的原理3.new T[N]的原理4.delete[]的原理 五…

5G赋能新能源,工业5G路由器实现充电桩远程高效管理

随着5G技术的广泛应用&#xff0c;新能源充电桩的5G应用正逐步构建起全新的生态系统。在数字化转型的浪潮中&#xff0c;新能源充电桩行业正迎来数字化改革。工业5G路由器的引入&#xff0c;为充电桩的远程管理提供了强有力的技术支持&#xff0c;新能源充电桩5G路由器网络部署…

MySQL窗口函数详解

MySQL窗口函数详解 MySQL从8.0版本开始引入了窗口函数&#xff0c;这是一个强大的特性&#xff0c;可以大大简化复杂的数据分析任务。本文将详细介绍MySQL窗口函数的概念、语法和常见用法&#xff0c;并结合实际应用场景进行说明。 什么是窗口函数? 窗口函数是一种能够对结…

docker搭建ES 8.14 集群

参考&#xff1a;【docker搭建es8集群kibana】_docker 安装生产级 es 8.14 集群-CSDN博客 1、之前已搭建一台单机版的dockerES集群 参见 Elasticsearch docker 安装_docker 安装es8.14.3-CSDN博客 2、现在需要重新搭建为docker ES集群 准备新搭建3个点 一、准备工作 提前开…

【中项】系统集成项目管理工程师-第4章 信息系统架构-4.3应用架构

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

计蒜客T3473(丑数) 优先队列,质因数,小题大做一下

文章目录 丑数思考过程代码 丑数 思考过程 其实现在这一题&#xff0c;我还没把代码敲完。但想赶紧把自己的思考过程给记录下来&#xff0c;不然一会儿&#xff0c;一些细节就捕捉不到了。因为才看了一个“广告”&#xff0c;关于抓住瞬间的灵感&#xff0c;虽然我这纯属是小儿…