试手一下CameraX(APP)

书接上回。

首先还是看谷歌的官方文档:

https://developer.android.com/media/camera/camerax?hl=zh-cn

https://developer.android.com/codelabs/camerax-getting-started?hl=zh-cn#1

注:这里大部分内容也来自谷歌文档。

官方文档用的是Kotlin,和Java也大差不差。看看流程就好。

API 级别设置为 21。

我觉得其实从App这个层面,用camera1,camera2还是camerax其实都并不重要,很多重大的改变对app层应该都是不可见的。为什么还要折腾上层呢?这个就要问谷歌的设计师了。。。

1 环境配置

在Gardle中增加依赖,我理解就是增加底层库,这几个应该就是camerax所使用的Framework的so,下面应该是AIDL调用的HAL。这个部分和底层驱动关系就很大了,后面还会单独写一篇。

dependencies {def camerax_version = "1.1.0-beta01"implementation "androidx.camera:camera-core:${camerax_version}"implementation "androidx.camera:camera-camera2:${camerax_version}"implementation "androidx.camera:camera-lifecycle:${camerax_version}"implementation "androidx.camera:camera-video:${camerax_version}"implementation "androidx.camera:camera-view:${camerax_version}"implementation "androidx.camera:camera-extensions:${camerax_version}"
}

同时要增加Java8和viewBinding的支持。

    compileOptions {sourceCompatibility JavaVersion.VERSION_1_8targetCompatibility JavaVersion.VERSION_1_8}buildFeatures {viewBinding true}

在Layout的activity_main.xml中使用PreviewView。这个应该是camerax的控件。

   <androidx.camera.view.PreviewViewandroid:id="@+id/viewFinder"android:layout_width="match_parent"android:layout_height="match_parent" />

增加两个按键,分别是takephoto和capturevideo,并增加按键事件。

       // Set up the listeners for take photo and video capture buttonsviewBinding.imageCaptureButton.setOnClickListener { takePhoto() }viewBinding.videoCaptureButton.setOnClickListener { captureVideo() }

在AndroidManifest.xml中增加权限。

<uses-feature android:name="android.hardware.camera.any" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="28" />

 在运行时会让你授权。

刚开始运行时,要检查权限。

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults:IntArray) {if (requestCode == REQUEST_CODE_PERMISSIONS) {if (allPermissionsGranted()) {startCamera()} else {Toast.makeText(this,"Permissions not granted by the user.",Toast.LENGTH_SHORT).show()finish()}}
}

2 CameraX调用代码

 主要用到的的几个包:

import androidx.camera.core.ImageCapture
import androidx.camera.video.Recorder
import androidx.camera.video.Recording
import androidx.camera.video.VideoCapture
2.1 提供图像预览:

大体的流程就是首先取得surface,然后使用cameraProvider.bindToLifecycle,将surface作为参数传进去。

private fun startCamera() {val cameraProviderFuture = ProcessCameraProvider.getInstance(this)cameraProviderFuture.addListener({// Used to bind the lifecycle of cameras to the lifecycle ownerval cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()// Previewval preview = Preview.Builder().build().also {it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)}// Select back camera as a defaultval cameraSelector = CameraSelector.DEFAULT_BACK_CAMERAtry {// Unbind use cases before rebindingcameraProvider.unbindAll()// Bind use cases to cameracameraProvider.bindToLifecycle(this, cameraSelector, preview)} catch(exc: Exception) {Log.e(TAG, "Use case binding failed", exc)}}, ContextCompat.getMainExecutor(this))
}
2.2 拍照:

可以看到,基本上就是围绕着imageCapture.takePicture这个方法。name,contentValues,outputOptions都是作为参数传进去。

private fun takePhoto() {// Get a stable reference of the modifiable image capture use caseval imageCapture = imageCapture ?: return// Create time stamped name and MediaStore entry.val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis())val contentValues = ContentValues().apply {put(MediaStore.MediaColumns.DISPLAY_NAME, name)put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")}}// Create output options object which contains file + metadataval outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver,MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues).build()// Set up image capture listener, which is triggered after photo has// been takenimageCapture.takePicture(outputOptions,ContextCompat.getMainExecutor(this),object : ImageCapture.OnImageSavedCallback {override fun onError(exc: ImageCaptureException) {Log.e(TAG, "Photo capture failed: ${exc.message}", exc)}override funonImageSaved(output: ImageCapture.OutputFileResults){val msg = "Photo capture succeeded: ${output.savedUri}"Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()Log.d(TAG, msg)}})
}
2.3 拍视频:

基本就是围绕着videoCapture.output。name,contentValues,mediaStoreOutputOptions都是作为参数使用。在output中,好像是使用了lambda函数,弄了一些内置行为。

// Implements VideoCapture use case, including start and stop capturing.
private fun captureVideo() {val videoCapture = this.videoCapture ?: returnviewBinding.videoCaptureButton.isEnabled = falseval curRecording = recordingif (curRecording != null) {// Stop the current recording session.curRecording.stop()recording = nullreturn}// create and start a new recording sessionval name = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis())val contentValues = ContentValues().apply {put(MediaStore.MediaColumns.DISPLAY_NAME, name)put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/CameraX-Video")}}val mediaStoreOutputOptions = MediaStoreOutputOptions.Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI).setContentValues(contentValues).build()recording = videoCapture.output.prepareRecording(this, mediaStoreOutputOptions).apply {if (PermissionChecker.checkSelfPermission(this@MainActivity,Manifest.permission.RECORD_AUDIO) ==PermissionChecker.PERMISSION_GRANTED){withAudioEnabled()}}.start(ContextCompat.getMainExecutor(this)) { recordEvent ->when(recordEvent) {is VideoRecordEvent.Start -> {viewBinding.videoCaptureButton.apply {text = getString(R.string.stop_capture)isEnabled = true}}is VideoRecordEvent.Finalize -> {if (!recordEvent.hasError()) {val msg = "Video capture succeeded: " +"${recordEvent.outputResults.outputUri}"Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()Log.d(TAG, msg)} else {recording?.close()recording = nullLog.e(TAG, "Video capture ends with error: " +"${recordEvent.error}")}viewBinding.videoCaptureButton.apply {text = getString(R.string.start_capture)isEnabled = true}}}}
}

好了,就到这了。先概要看看就行了。

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

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

相关文章

常用的字符字符串的读取方法(C / C++)

一、字符 1、读取单个字符&#xff1a;直接读取 //输入a //读取 char x; scanf("%c",&x); 2、读取带空格的字符 h h h 按格式书写格式化字符串即可 char a,b,c; scanf("%c %c %c",&a,&b,&c); 3、 处理字符间的换行符 假设要读取以…

Day14:信息打点-主机架构蜜罐识别WAF识别端口扫描协议识别服务安全

目录 Web服务器&应用服务器差异性 WAF防火墙&安全防护&识别技术 蜜罐平台&安全防护&识别技术 思维导图 章节知识点 Web&#xff1a;语言/CMS/中间件/数据库/系统/WAF等 系统&#xff1a;操作系统/端口服务/网络环境/防火墙等 应用&#xff1a;APP对象/…

小程序图形:echarts-weixin 入门使用

去官网下载整个项目&#xff1a; https://github.com/ecomfe/echarts-for-weixin 拷贝ec-canvs文件夹到小程序里面 index.js里面的写法 import * as echarts from "../../components/ec-canvas/echarts" const app getApp(); function initChart(canvas, width, h…

Vscode 使用SSH远程连接树莓派的教程(解决卡在Downloading with wget)

配置Vscode Remote SSH 安装OpenSSH 打开Windows开始页面&#xff0c;直接进行搜索PowerShell&#xff0c;打开第一个Windows PowerShell&#xff0c;点击以管理员身份运行 输入指令 Get-WindowsCapability -Online | ? Name -like OpenSSH* 我是已经安装好了&#xff0c;…

学会玩游戏,智能究竟从何而来?

最近在读梅拉妮米歇尔《AI 3.0》第三部分第九章&#xff0c;谈到学会玩游戏&#xff0c;智能究竟从何而来&#xff1f; 作者: [美] 梅拉妮米歇尔 出版社: 四川科学技术出版社湛庐 原作名: Artificial Intelligence: A Guide for Thinking Humans 译者: 王飞跃 / 李玉珂 / 王晓…

基于springboot实现计算机类考研交流平台系统项目【项目源码+论文说明】

基于springboot实现计算机类考研交流平台系统演示 摘要 高校的大学生考研是继高校的高等教育更上一层的表现形式&#xff0c;教育的发展是我们社会的根本&#xff0c;那么信息技术的发展又是改变我们生活的重要因素&#xff0c;生活当中各种各样的场景都存在着信息技术的发展。…

程序员超强大脑——更好地解决编程问题(二)

概念机器 概念机器是计算机的抽象表征&#xff0c;可以借此分析计算机执行的操作。 程序员不仅经常借助概念机器推理计算机的运行方式&#xff0c;而且往往用它来分析代码。例如&#xff0c;虽然并不存在能够出存储数值的实体&#xff0c;但程序员还是会将变量描述为“保存”…

Debezium发布历史163

原文地址&#xff1a; https://debezium.io/blog/2023/09/23/flink-spark-online-learning/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. Online machine learning with the data streams from the database …

SpringBlade CVE-2022-27360 export-user SQL 注入漏洞分析

漏洞描述 SpringBlade是一个基于Spring Cloud和Spring Boot的开发框架&#xff0c;旨在简化和加速微服务架构的开发过程。它提供了一系列开箱即用的功能和组件&#xff0c;帮助开发人员快速构建高效可靠的微服务应用。该产品/api/blade-user/export-user接口存在SQL注入。 漏…

Java - List集合与Array数组的相互转换

一、List 转 Array 使用集合转数组的方法&#xff0c;必须使用集合的 toArray(T[] array)&#xff0c;传入的是类型完全一样的数组&#xff0c;大小就是 list.size() public static void main(String[] args) throws Exception {List<String> list new ArrayList<S…

无处不在的智慧:探索嵌入式系统的奇妙

无处不在的智慧&#xff1a;探索嵌入式系统的奇妙 嵌入式系统作为当今科技领域中无处不在的一种技术&#xff0c;其奇妙之处正在逐步被揭示和探索。从智能家居到智能穿戴设备&#xff0c;从工业自动化到医疗健康&#xff0c;嵌入式系统已经深入到我们生活和工作的方方面面&…

分布式ID生成策略-雪花算法Snowflake

分布式ID生成策略-雪花算法Snowflake 一、其他分布式ID策略1.UUID2.数据库自增与优化2.1 优化1 - 共用id自增表2.2 优化2 - 分段获取id 3.Reids的incr和incrby 二、雪花算法Snowflake1.雪花算法的定义2.基础雪花算法源码解读3.并发1000测试4.如何设置机房和机器id4.雪花算法时钟…

【misc | CTF】BUUCTF 二维码

天命&#xff1a;这题使用到脚本暴力破解压缩包文件里面的密码&#xff0c;还是比较有意思的 一开始是一个二维码&#xff0c;扫码进去有一个假flag 扔进图片隐写工具&#xff0c;啥也没有&#xff0c;都是同一个二维码 使用工具&#xff1a;foremost&#xff0c;直接分离图片&…

【详识JAVA语言】抽象类和接口

抽象类 抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果 一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类。 比如&#xff1a;…

水印相机小程序源码

水印相机前端源码&#xff0c;本程序无需后端&#xff0c;前端直接导入即可&#xff0c;没有添加流量主功能&#xff0c;大家开通后自行添加 源码搜索&#xff1a;源码软件库 注意小程序后台的隐私权限设置&#xff0c;前端需要授权才可使用 真实时间地址拍照记录&#xff0c…

Endnote x9 最快方法批量导入.enw格式文件

按照网上看到的一个方法直接选中所有enw批量拖拽到 All references 附件不行啊&#xff0c; 以为只能写bat脚本方式了 经过一番尝试&#xff0c;惊人的发现拖到下面这个符号的地方就行了&#xff01;&#xff01;&#xff01; 如果不成功的话&#xff0c;可能&#xff1a; 我…

使用typescript实现引入vue3生命周期函数的基础知识整理

在Vue 3中&#xff0c;生命周期函数被更改为组合式API&#xff0c;并且不再使用官方命名的生命周期钩子函数。不过&#xff0c;我们仍然可以模拟类似的功能&#xff0c;使用onBeforeMount、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount、onUnmounted等组合式API。 …

浅谈vue的自定义指令

Vue 的自定义指令是一种强大的工具&#xff0c;允许你为 DOM 元素添加自定义行为。自定义指令可以通过 Vue 的 Vue.directive() 全局 API 或组件内的 directives 选项来定义。 下面是如何使用 Vue 的自定义指令的基本步骤&#xff1a; 全局注册自定义指令 Vue.directive(foc…

js 手写深拷贝方法

文章目录 一、深拷贝实现代码二、代码讲解2.1 obj.constructor(obj)2.2 防止循环引用手写一个深拷贝是我们常见的面试题,在实现过程中我们需要考虑的类型很多,包括对象、数组、函数、日期等。以下就是深拷贝实现逻辑 一、深拷贝实现代码 const originalObject = {string: H…

蓝桥杯复习之差分

题目&#xff1a;空调 题目链接&#xff1a;https://www.acwing.com/problem/content/description/4265/ 思路&#xff1a; 对希望温度与实际温度做差&#xff0c;再对这个做差数组做差分。我们的每次操作等价于在差分数组中选一个数加一或者选两个数一个加一&#xff0c…