查看原文
其他

CameraX 1.3 Beta 版发布 | 为 Android 应用带来更强大的相机功能

Android Android 开发者 2023-11-14


作者 / Donovan McMurray,Camera Developer Relations Engineer


CameraX 是 Android Jetpack 的相机库,可帮助您为不同的 Android 版本和设备打造一致的出色体验,随着 CameraX 1.3 版本的推出,这个库的实用性也更上一层楼。CameraX 已用于越来越多的 Android 应用中,拥有非常广泛的应用场景,包括简单高效的相机交互、高级图像处理等等。


  • CameraX

    https://developer.android.google.cn/training/camerax

  • Android Jetpack

    https://developer.android.google.cn/jetpack


CameraX 1.3 提供更多高级功能。借助双并发摄像头功能,应用可以同时操控两个摄像头。此外,CameraX 1.3 提供一些新的 HDR 视频功能,让用户可以轻松拍出满意的作品。现在,您还可添加图形库转换效果 (例如使用 OpenGL 或 Vulkan) 到 Preview、ImageCapture 和 VideoCapture 用例中,以便采用滤镜和特效。此外,还有许多视频方面的功能改进等您发掘。

  • OpenGL
    https://www.opengl.org/

  • Vulkan
    https://www.vulkan.org/


CameraX 1.3 Beta 版已正式推出,让我们即刻了解详情吧!


双并发摄像头



CameraX 让复杂的相机功能轻松易用,新的双并发摄像头功能也不例外。CameraX 会处理低层级细节工作,例如确保以正确的顺序打开和关闭并发摄像头视频串流。在 CameraX 中,绑定双并发摄像头与绑定单个摄像头并无太大差别。


首先,使用 getAvailableConcurrentCameraInfos() 确定哪些相机支持并发连接。常见情形是选择前置摄像头和后置摄像头。


  • getAvailableConcurrentCameraInfos()

    https://developer.android.google.cn/reference/androidx/camera/lifecycle/ProcessCameraProvider#getAvailableConcurrentCameraInfos%28%29


var primaryCameraSelector: CameraSelector? = nullvar secondaryCameraSelector: CameraSelector? = null
for (cameraInfos in cameraProvider.availableConcurrentCameraInfos) { primaryCameraSelector = cameraInfos.first { it.lensFacing == CameraSelector.LENS_FACING_FRONT }.cameraSelector secondaryCameraSelector = cameraInfos.first { it.lensFacing == CameraSelector.LENS_FACING_BACK }.cameraSelector
if (primaryCameraSelector == null || secondaryCameraSelector == null) { // If either a primary or secondary selector wasn't found, reset both // to move on to the next list of CameraInfos. primaryCameraSelector = null secondaryCameraSelector = null } else { // If both primary and secondary camera selectors were found, we can // conclude the search. break }}
if (primaryCameraSelector == null || secondaryCameraSelector == null) { // Front and back concurrent camera not available. Handle accordingly.}
然后,为每个摄像头创建一个 SingleCameraConfig,依次传入各摄像头选择器、UseCaseGroup 和 LifecycleOwner。然后,对您的 CameraProvider 调用 bindToLifecycle(),并将两项 SingleCameraConfig 加入列表中。


  • SingleCameraConfig

    https://developer.android.google.cn/reference/androidx/camera/core/ConcurrentCamera.SingleCameraConfig

  • UseCaseGroup

    https://developer.android.google.cn/reference/androidx/camera/core/UseCaseGroup

  • LifecycleOwner

    https://developer.android.google.cn/reference/androidx/lifecycle/LifecycleOwner

  • bindToLifecycle()
    https://developer.android.google.cn/reference/androidx/camera/lifecycle/ProcessCameraProvider#bindToLifecycle%28java.util.List%3Candroidx.camera.core.ConcurrentCamera.SingleCameraConfig%3E%29


val primary = ConcurrentCamera.SingleCameraConfig( primaryCameraSelector, useCaseGroup, lifecycleOwner)
val secondary = ConcurrentCamera.SingleCameraConfig( secondaryCameraSelector, useCaseGroup, lifecycleOwner)
val concurrentCamera = cameraProvider.bindToLifecycle( listOf(primary, secondary))
为了确保兼容,双并发摄像头功能支持每个摄像头绑定最多 2 个用例,最高分辨率为 720p 或 1440p,具体取决于设备。



HDR 视频



CameraX 1.3 还新增了对 10 位视频流及 HDR 配置文件的支持,以便用户能够拍出细节、色彩、对比效果更胜以往的视频。您可以使用 VideoCapture.Builder.setDynamicRange() 方法进行多项配置。下面是一些预先配置的值: 


  • HLG_10_BIT - 采用 HLG 编码的 10 位高动态范围。这是建议使用的 HDR 编码,因为所有支持 HDR 拍摄功能的设备都会支持 HLG10。您可参阅检查 HDR 支持情况指南以了解详情。

  • HDR10_10_BIT - 采用 HDR10 编码的 10 位高动态范围。

  • HDR10_PLUS_10_BIT - 采用 HDR10+ 编码的 10 位高动态范围。

  • DOLBY_VISION_10_BIT - 采用杜比视界 (Dolby Vision) 编码的 10 位高动态范围。

  • DOLBY_VISION_8_BIT - 采用杜比视界 (Dolby Vision) 编码的 8 位高动态范围。


  • VideoCapture.Builder.setDynamicRange()
    https://developer.android.google.cn/reference/androidx/camera/video/VideoCapture.Builder#setDynamicRange%28androidx.camera.core.DynamicRange%29

  • 检查 HDR 支持情况
    https://developer.android.google.cn/training/camera2/hdr-video-capture#check_for_hdr_support


首先,循环检查可获取的 CameraInfo,找出首个支持 HDR 的项。您可在此处添加其他摄像头选择标准。


  • CameraInfo
    https://developer.android.google.cn/reference/androidx/camera/core/CameraInfo


var supportedHdrEncoding: DynamicRange? = nullval hdrCameraInfo = cameraProvider.availableCameraInfos .first { cameraInfo -> val videoCapabilities = Recorder.getVideoCapabilities(cameraInfo) val supportedDynamicRanges = videoCapabilities.getSupportedDynamicRanges() supportedHdrEncoding = supportedDynamicRanges.firstOrNull { it != DynamicRange.SDR // Ensure an HDR encoding is found } return@first supportedDynamicRanges != null }
var cameraSelector = hdrCameraInfo?.cameraSelector ?:     CameraSelector.DEFAULT_BACK_CAMERA

然后,设置 Recorder 和 VideoCapture 用例。如果您之前找到了 supportedHdrEncoding,还可调用 setDynamicRange() 为您的相机应用开启 HDR。


  • Recorder
    https://developer.android.google.cn/reference/androidx/camera/video/Recorder

  • VideoCapture
    https://developer.android.google.cn/reference/androidx/camera/video/VideoCapture


// Create a Recorder with Quality.HIGHEST, which will select the highest// resolution compatible with the chosen DynamicRange.val recorder = Recorder.Builder() .setQualitySelector(QualitySelector.from(Quality.HIGHEST)) .build()val videoCaptureBuilder = VideoCapture.Builder(recorder)if (supportedHdrEncoding != null) { videoCaptureBuilder.setDynamicRange(supportedHdrEncoding!!)}val videoCapture = videoCaptureBuilder.build()



特效



CameraX 不仅让很多相机任务变得轻松,还提供了一些钩子 (hooks) 来实现高级或自定义功能。借助新的特效方法,您可将自定义图形库转换效果应用到 Preview、ImageCapture 和 VideoCapture 的帧中。

您可定义一个 CameraEffect 以将代码注入 CameraX 流水线并应用视觉特效,例如一项自定义的人像特效。当通过构造函数创建您自己的 CameraEffect 时,您必须指定目标用例 (PREVIEW、VIDEO_CAPTURE 或 IMAGE_CAPTURE)。您还必须指定一项 SurfaceProcessor,为底层 Surface 实现 GPU 特效。建议使用 OpenGL 或 Vulkan 等图形 API 来访问 Surface。此进程会阻塞与 ImageCapture 关联的执行器 (Executor)。系统会默认使用一个内部 I/O 线程,或者您可使用 ImageCapture.Builder.setIoExecutor() 设置一个线程。注意: 性能取决于您的实现代码。对于 30fps 的输入,每帧的处理时间应在 30 毫秒以内,以避免丢帧。

  • CameraEffect
    https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect

  • 通过构造函数创建您自己的 CameraEffect
    https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#CameraEffect%28int,java.util.concurrent.Executor,androidx.camera.core.SurfaceProcessor,androidx.core.util.Consumer%3Cjava.lang.Throwable%3E%29

  • PREVIEW
    https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#PREVIEW%28%29

  • VIDEO_CAPTURE
    https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#VIDEO_CAPTURE%28%29

  • IMAGE_CAPTURE
    https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#IMAGE_CAPTURE%28%29

  • SurfaceProcessor
    https://developer.android.google.cn/reference/androidx/camera/core/SurfaceProcessor

  • Surface
    https://developer.android.google.cn/reference/android/view/Surface.html

  • ImageCapture.Builder.setIoExecutor()
    https://developer.android.google.cn/reference/androidx/camera/core/ImageCapture.Builder#setIoExecutor%28java.util.concurrent.Executor%29


您可使用一个备选 CameraEffect 构造函数来处理静态图像,因为在处理单幅图像时,可以接受更高的延迟。如果使用此构造函数,您需传入一项 ImageProcessor,执行相应进程方法以返回图像,详情您可以参阅 ImageProcessor.Request.getInputImage() 方法的说明。


  • 备选 CameraEffect 构造函数
    https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#CameraEffect%28int,java.util.concurrent.Executor,androidx.camera.core.ImageProcessor,androidx.core.util.Consumer%3Cjava.lang.Throwable%3E%29

  • ImageProcessor
    https://developer.android.google.cn/reference/androidx/camera/core/ImageProcessor

  • ImageProcessor.Request.getInputImage()
    https://developer.android.google.cn/reference/androidx/camera/core/ImageProcessor.Request#getInputImage%28%29


在定义一个或多个 CameraEffect 后,您可将其添加到 CameraX 设置中。如果使用 CameraProvider,您应针对每个 CameraEffect 调用 UseCaseGroup.Builder.addEffect(),然后构建 UseCaseGroup 并将其传入 bindToLifecycle()。如果您使用 CameraController,您应将所有 CameraEffect 都传入 setEffects()。


  • CameraProvider
    https://developer.android.google.cn/reference/androidx/camera/core/CameraProvider

  • UseCaseGroup.Builder.addEffect()
    https://developer.android.google.cn/reference/androidx/camera/core/UseCaseGroup.Builder#addEffect%28androidx.camera.core.CameraEffect%29

  • bindToLifecycle()
    https://developer.android.google.cn/reference/androidx/camera/lifecycle/ProcessCameraProvider#bindToLifecycle%28androidx.lifecycle.LifecycleOwner,androidx.camera.core.CameraSelector,androidx.camera.core.UseCaseGroup%29

  • CameraController
    https://developer.android.google.cn/reference/androidx/camera/view/CameraController

  • setEffects()
    https://developer.android.google.cn/reference/androidx/camera/view/CameraController#setEffects%28java.util.Set%3Candroidx.camera.core.CameraEffect%3E%29



其他视频方面的功能



CameraX 1.3 还新增了许多备受期盼的其他视频功能,我们很高兴为其提供支持。


借助 VideoCapture.Builder.setMirrorMode(),您可控制何时让录像画面在水平方向镜像翻转。您可设置 MIRROR_MODE_OFF (默认)、MIRROR_MODE_ON 和 MIRROR_MODE_ON_FRONT_ONLY (适用于匹配预览的镜像状态,该预览在前置摄像头上进行镜像)。注意: 对于仅使用前置摄像头的应用,MIRROR_MODE_ONMIRROR_MODE_ON_FRONT_ONLY 是等效的。


  • VideoCapture.Builder.setMirrorMode()
    https://developer.android.google.cn/reference/androidx/camera/video/VideoCapture.Builder#setMirrorMode%28int%29

  • MIRROR_MODE_OFF
    https://developer.android.google.cn/reference/androidx/camera/core/MirrorMode#MIRROR_MODE_OFF%28%29

  • MIRROR_MODE_ON
    https://developer.android.google.cn/reference/androidx/camera/core/MirrorMode#MIRROR_MODE_ON%28%29

  • MIRROR_MODE_ON_FRONT_ONLY
    https://developer.android.google.cn/reference/androidx/camera/core/MirrorMode#MIRROR_MODE_ON_FRONT_ONLY%28%29


PendingRecording.asPersistentRecording() 方法可防止视频因生命周期事件而停止,或因录像所用 Recorder 附加的 VideoCapture 用例被显式解除绑定而停止。如果您想绑定到另一个摄像头并使用该摄像头继续录像,便可使用这种方法。当启用这一选项时,您必须显式调用 Recording.stop() 或 Recording.close() 来结束录像。


  • PendingRecording.asPersistentRecording()
    https://developer.android.google.cn/reference/androidx/camera/video/PendingRecording#asPersistentRecording%28%29

  • VideoCapture
    https://developer.android.google.cn/reference/androidx/camera/video/VideoCapture

  • Recording.stop()
    https://developer.android.google.cn/reference/androidx/camera/video/Recording#stop%28%29

  • Recording.close()
    https://developer.android.google.cn/reference/androidx/camera/video/Recording#close%28%29


如果已通过 PendingRecording.withAudioEnabled() 将视频设为同时录制音频,可在录制过程中调用 Recording.mute()。您可以传入一个布尔值来指定将音频静音还是取消静音,这样 CameraX 便会在设为静音的部分中插入无声片段,以确保音频与视频保持一致。


  • PendingRecording.withAudioEnabled()
    https://developer.android.google.cn/reference/androidx/camera/video/PendingRecording#withAudioEnabled%28%29

  • Recording.mute()
    https://developer.android.google.cn/reference/androidx/camera/video/Recording#mute%28boolean%29


AudioStats 新增了 getAudioAmplitude() 方法,用于向用户显示一个指示标识,以表明正在录制音频。在视频录制过程中,每个 VideoRecordEvent 都可用于访问 RecordingStats,而 RecordingStats 中包含 AudioStats 对象。


  • AudioStats
    https://developer.android.google.cn/reference/androidx/camera/video/AudioStats

  • VideoRecordEvent
    https://developer.android.google.cn/reference/androidx/camera/video/VideoRecordEvent

  • RecordingStats
    https://developer.android.google.cn/reference/androidx/camera/video/RecordingStats



后续步骤



您可以阅读 CameraX 1.3 的完整版本说明,详细了解本文所述的各项功能和其他信息!如果您已准备好体验 CameraX 1.3,可以将您项目的 CameraX 依赖项更新为 1.3.0-beta02 (或您阅读本文时的最新版本)。


  • CameraX 1.3 的完整版本说明
    https://developer.android.google.cn/jetpack/androidx/releases/camera#version_13_2


如果想针对上述某项功能或 CameraX 的总体情况与我们分享反馈,您可以创建一个 CameraX issue。您也可以在 CameraX 讨论组中与我们沟通交流。欢迎您持续关注 "Android 开发者" 微信公众号,及时了解更多开发技术和产品更新等资讯动态。


  • CameraX issue
    https://issuetracker.google.com/issues?q=status:open%20componentid:618491&s=created_time:desc

  • CameraX 讨论组
    https://groups.google.com/a/android.com/g/camerax-developers




推荐阅读

如页面未加载,请刷新重试

 点击屏末 | 阅读原文 | 即刻使用 CameraX 轻松地开发相机应用




继续滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存