Android音视频全面介绍与代码实践之CameraX(三)

2024-06-15 10:32

本文主要是介绍Android音视频全面介绍与代码实践之CameraX(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android在应用层提供丰富的音视频多媒体接口,本文主要介绍CameraX,背景是在Camera2基础上,提供Lifecycle生命周期管理,提供更加简洁易用接口,包括摄像头预览、拍照、录像、图片分析,另外支持扩展接口:自动切换弱光模式、焦外成像、HDR拍摄等。

第一篇文章探讨:MediaPlayer、MediaCodec、AudioTrack、MediaMuxer、MediaExtractor。第二篇文章探讨:MediaRecorder、AudioRecord、MediaMetadataRetriever、MediaProjection、AudioManager。

目录

一、权限与依赖

二、配置参数

1、旋转角度

2、矩形裁剪

3、选择摄像头

4、相机分辨率

5、 变焦与曝光

三、摄像头预览

1、使用PreviewView布局

2、请求CameraProvider

3、检查CameraProvider可用性

4、选择相机并绑定生命周期

5、监听相机状态

四、拍照

1、拍照接口

2、拍照模式

3、拍照实例并绑定生命周期

4、拍照保存

五、录像

1、配置录像参数

2、开始录像

六、图像分析

1、创建图像分析器

2、自定义分析器

七、扩展API


一、权限与依赖

使用摄像头需要camera权限和feature:

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

如果要录像录音,需要额外权限:

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

 摄像头核心库与扩展库依赖:

// CameraX core library
def camerax_version = '1.1.0-beta02'
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-view:$camerax_version"
implementation "androidx.camera:camera-video:${camerax_version}"
// CameraX Extensions library
implementation "androidx.camera:camera-extensions:$camerax_version"

二、配置参数

1、旋转角度

相机的旋转角度会设置为与默认的显示屏旋转角度保持一致。也可以通过Preview、ImageCapture、ImageAnalysis设置旋转角度。以ImageCapture拍照为例,监听屏幕方向变化,自适应设置旋转角度:

    val imageCapture = ImageCapture.Builder().build()val orientationEventListener = object : OrientationEventListener(this as Context) {override fun onOrientationChanged(orientation : Int) {val rotation : Int = when (orientation) {in 45..134 -> Surface.ROTATION_270in 135..224 -> Surface.ROTATION_180in 225..314 -> Surface.ROTATION_90else -> Surface.ROTATION_0}imageCapture.targetRotation = rotation}}orientationEventListener.enable()

2、矩形裁剪

默认情况下,显示完整预览画面,按照完整尺寸进行拍照。我们也可以通过ViewPort和UseCaseGroup自定义裁剪矩形区域。裁剪代码示例如下:

val viewPort =  ViewPort.Builder(Rational(width, height), display.rotation).build()
val useCaseGroup = UseCaseGroup.Builder().addUseCase(preview).addUseCase(imageAnalysis).addUseCase(imageCapture).setViewPort(viewPort).build()
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup)

3、选择摄像头

CameraX会自动选择最佳摄像头设备。可以使用 CameraSelector.DEFAULT_FRONT_CAMERA 设置默认为前置摄像头,使用CameraSelector.DEFAULT_BACK_CAMERA 设置默认为后置摄像头。另外,可以通过CameraSelector来动态切换摄像头。

4、相机分辨率

CameraX会默认选择最佳分辨率,并且默认宽高比为4:3。也可以通过如下方法指定分辨率:

setTargetResolution(Size resolution);

5、 变焦与曝光

CameraControl提供变焦、对焦、手电筒、曝光补偿等控制。按照变焦比例进行变焦setZoomRatio(),按照变焦系数进行变焦setLinearZoom()。对焦的方法如下:

CameraControl.startFocusAndMetering();

 当应用需要对自动曝光 (AE) 输出结果以外的曝光值 (EV) 进行微调时,曝光补偿很有用。CameraX 将按以下方式组合曝光补偿值,以确定当前图像条件下所需的曝光:

Exposure = ExposureCompensationIndex * ExposureCompensationStep

设置曝光补偿索引值 的方法如下:

Camera.CameraControl.setExposureCompensationIndex();

完整的CameraX介绍与参数配置,请查看文档:CameraX官方文档 

三、摄像头预览

1、使用PreviewView布局

CameraX配合PreviewView控件进行预览,布局示例如下:

<FrameLayoutandroid:id="@+id/root"><androidx.camera.view.PreviewViewandroid:id="@+id/preview_view" />
</FrameLayout>

2、请求CameraProvider

在onCreate生命周期时,进行请求:

cameraProviderFuture = ProcessCameraProvider.getInstance(this)

3、检查CameraProvider可用性

得到CameraProvider后,检查其是否可用:

cameraProviderFuture.addListener(Runnable {val cameraProvider = cameraProviderFuture.get()bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))

4、选择相机并绑定生命周期

 以选择后置摄像头为例,示例代码如下:

fun bindPreview(cameraProvider : ProcessCameraProvider) {// 1、创建Previewvar preview : Preview = Preview.Builder().build()// 2、选择后置摄像头var cameraSelector : CameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()// 3、preview连接到previewViewpreview.setSurfaceProvider(previewView.getSurfaceProvider())// 4、绑定生命周期var camera = cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
}

5、监听相机状态

相机状态包括:准备打开、打开中、已打开、关闭中、已关闭。而错误状态包括:流配置出错、相机在使用中、已达到最大数量、相机关闭等等。示例代码如下:

private fun observeCameraState(cameraInfo: CameraInfo) {cameraInfo.cameraState.observe(viewLifecycleOwner) { cameraState ->run {when (cameraState.type) {CameraState.Type.PENDING_OPEN -> {Toast.makeText(context, "CameraState: Pending Open", Toast.LENGTH_SHORT).show()}CameraState.Type.OPENING -> {Toast.makeText(context, "CameraState: Opening", Toast.LENGTH_SHORT).show()}CameraState.Type.OPEN -> {Toast.makeText(context, "CameraState: Open", Toast.LENGTH_SHORT).show()}CameraState.Type.CLOSING -> {Toast.makeText(context, "CameraState: Closing", Toast.LENGTH_SHORT).show()}CameraState.Type.CLOSED -> {Toast.makeText(context, "CameraState: Closed", Toast.LENGTH_SHORT).show()}}}cameraState.error?.let { error ->when (error.code) {CameraState.ERROR_STREAM_CONFIG -> {Log.e(TAG, "Stream config error")}CameraState.ERROR_CAMERA_IN_USE -> {Log.e(TAG,  "Camera is in using")}CameraState.ERROR_MAX_CAMERAS_IN_USE -> {Log.e(TAG, "Max cameras in use")}CameraState.ERROR_CAMERA_DISABLED -> {Log.e(TAG, "Camera disabled")}}}}
}

四、拍照

1、拍照接口

CameraX的拍照提供自动白平衡、自动曝光和自动对焦 (3A) 功能。使用takePicture进行拍照:

  • takePicture(Executor, OnImageCapturedCallback):为拍摄的图片提供内存缓冲区;
  • takePicture(OutputFileOptions, Executor, OnImageSavedCallback):将拍摄的图片保存到指定的文件位置;

2、拍照模式

拍照时使用闪光灯选项和连续自动对焦进行拍摄。如需缩短照片拍摄的延迟时间,我们可以把 ImageCapture.CaptureMode 设置为 CAPTURE_MODE_MINIMIZE_LATENCY。如需优化照片质量,则设置为 CAPTURE_MODE_MAXIMIZE_QUALITY。

3、拍照实例并绑定生命周期

创建ImageCapture对象实例,并且绑定到生命周期:

val imageCapture = ImageCapture.Builder().setTargetRotation(view.display.rotation).setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY).build()cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageCapture,imageAnalysis, preview)

4、拍照保存

以拍照保存为例,相关代码如下:

fun doTakePicture(photoFile: File) {imageCapture?.let { imageCapture ->val metadata = Metadata().apply {// 前置摄像头需要水平镜像isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT}// 指定保存图片路径,并设置metadataval outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).setMetadata(metadata).build()// 开始拍照,监听拍照结果回调imageCapture.takePicture(outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {override fun onError(exc: ImageCaptureException) {Log.e(TAG, "Photo capture error: ${exc.message}")}override fun onImageSaved(output: ImageCapture.OutputFileResults) {val savedUri = output.savedUri ?: Uri.fromFile(photoFile)// 发送广播通知更新相册if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {requireActivity().sendBroadcast(Intent(android.hardware.Camera.ACTION_NEW_PICTURE, savedUri))}// 扫描媒体库val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(savedUri.toFile().extension)MediaScannerConnection.scanFile(context,arrayOf(savedUri.toFile().absolutePath),arrayOf(mimeType)) { _, uri ->Log.d(TAG, "Photo scanned into media store: $uri")}}})}
}

五、录像

1、配置录像参数

CameraX提供VideoCapture进行录像,配置步骤:选择摄像头、选择分辨率、连接PreviewView、创建videoCapture对象、绑定生命周期。示例代码如下:

    private suspend fun bindCaptureUsecase() {val cameraProvider = ProcessCameraProvider.getInstance(requireContext()).await()// 选择前置/后置摄像头val cameraSelector = getCameraSelector(cameraIndex)// 选择分辨率val quality = cameraCapabilities[cameraIndex].qualities[qualityIndex]val qualitySelector = QualitySelector.from(quality)// 连接preview到previewViewval preview = Preview.Builder().setTargetAspectRatio(quality.getAspectRatio(quality)).build()preview.setSurfaceProvider(captureViewBinding.previewView.surfaceProvider)// 创建videoCapture对象val recorder = Recorder.Builder().setQualitySelector(qualitySelector).build()videoCapture = VideoCapture.withOutput(recorder)try {// 绑定生命周期cameraProvider.unbindAll()cameraProvider.bindToLifecycle(viewLifecycleOwner, cameraSelector, videoCapture, preview)} catch (e: Exception) {Log.e(TAG, "VideoCapture binding failed:$e")}}

2、开始录像

先调用VideoCapture的prepareRecording()准备就绪,然后调用start()开始。示例代码如下:

    private fun startRecording() {// 设置存储路径与名称val name = "hello.mp4"val contentValues = ContentValues().apply {put(MediaStore.Video.Media.DISPLAY_NAME, name)}val mediaStoreOutput = MediaStoreOutputOptions.Builder(requireActivity().contentResolver,MediaStore.Video.Media.EXTERNAL_CONTENT_URI).setContentValues(contentValues).build()// 准备与开始录像currentRecording = videoCapture.output.prepareRecording(requireActivity(), mediaStoreOutput).apply { if (audioEnabled) withAudioEnabled() }.start(mainThreadExecutor, captureListener)}

六、图像分析

1、创建图像分析器

使用ImageAnalysis创建图像分析器,设置图像宽高比、旋转角度,然后设置自定义分析器,最终绑定生命周期,示例代码如下:

// 构建图像分析器
imageAnalyzer = ImageAnalysis.Builder().setTargetAspectRatio(screenAspectRatio).setTargetRotation(rotation).build()
// 设置亮度分析器
imageAnalyzer?.setAnalyzer(cameraExecutor, LuminanceAnalyzer { luma ->Log.d(TAG, "Average luminance: $luma")})
// 绑定生命周期
camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalyzer)

2、自定义分析器

自定义的图像亮度分析器,继承ImageAnalysis.Analyzer,示例代码如下:

 

    private class LuminosityAnalyzer(listener: LumaListener? = null) : ImageAnalysis.Analyzer {private val listeners = ArrayList<LumaListener>().apply { listener?.let { add(it) } }private fun ByteBuffer.toByteArray(): ByteArray {rewind()val data = ByteArray(remaining())get(data)return data}override fun analyze(image: ImageProxy) {if (listeners.isEmpty()) {image.close()return}// 取出luminance plane,即Y分量val buffer = image.planes[0].bufferval data = buffer.toByteArray()// 转成像素数组,取值范围0-255val pixels = data.map { it.toInt() and 0xFF }// 计算平均亮度val luma = pixels.average()// 结果回调listeners.forEach { it(luma) }// 关闭imageimage.close()}}

七、扩展API

CameraX提供Extensions API接口,用于实现如下特效:

  • 自动切换:根据周围场景自动调整最终图片。例如,扩展库会执行弱光检测,切换到弱光模式或 HDR 模式以拍摄照片;
  • 焦外成像:焦外成像模式会使前景人物看起来更加清晰,并对照片背景进行模糊处理;
  • 脸部修复:拍摄静态图片时修复脸部肤色;
  • HDR:HDR 模式会在黑暗环境凸显亮度,提升画质;
  • 夜间模式:在光线较暗的情况下(通常是在夜间)拍摄最佳的静态图片;

扩展库的框架图如下:

 

初始化扩展库过程如下:

    fun initExtension() {// 创建扩展管理器val extensionsManager = ExtensionsManager.getInstanceAsync(context, cameraProvider).await()// 选择摄像头val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA// 检测扩展库是否可用if (extensionsManager.isExtensionAvailable(cameraSelector, ExtensionMode.BOKEH)) {cameraProvider.unbindAll()val bokehCameraSelector = extensionsManager.getExtensionEnabledCameraSelector(cameraSelector, ExtensionMode.BOKEH)// 创建ImageCapture和Preview实例val imageCapture = ImageCapture.Builder().build()val preview = Preview.Builder().build()// 绑定生命周期cameraProvider.bindToLifecycle(lifecycleOwner, bokehCameraSelector, imageCapture, preview)}}

至此,Android多媒体CameraX的相机预览、拍照、录像、图像分析、扩展库介绍完毕。

这篇关于Android音视频全面介绍与代码实践之CameraX(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1063201

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识