CameraX 1.3 Beta 版发布 | 为 Android 应用带来更强大的相机功能
作者 / Donovan McMurray,Camera Developer Relations Engineer
CameraX
https://developer.android.google.cn/training/camerax
Android Jetpack
https://developer.android.google.cn/jetpack
OpenGL
https://www.opengl.org/Vulkan
https://www.vulkan.org/
双并发摄像头
CameraX 让复杂的相机功能轻松易用,新的双并发摄像头功能也不例外。CameraX 会处理低层级细节工作,例如确保以正确的顺序打开和关闭并发摄像头视频串流。在 CameraX 中,绑定双并发摄像头与绑定单个摄像头并无太大差别。
首先,使用 getAvailableConcurrentCameraInfos() 确定哪些相机支持并发连接。常见情形是选择前置摄像头和后置摄像头。
getAvailableConcurrentCameraInfos()
https://developer.android.google.cn/reference/androidx/camera/lifecycle/ProcessCameraProvider#getAvailableConcurrentCameraInfos%28%29
var primaryCameraSelector: CameraSelector? = null
var 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
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)
)
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? = null
val 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/RecorderVideoCapture
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()
特效
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%29PREVIEW
https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#PREVIEW%28%29VIDEO_CAPTURE
https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#VIDEO_CAPTURE%28%29IMAGE_CAPTURE
https://developer.android.google.cn/reference/androidx/camera/core/CameraEffect#IMAGE_CAPTURE%28%29SurfaceProcessor
https://developer.android.google.cn/reference/androidx/camera/core/SurfaceProcessorSurface
https://developer.android.google.cn/reference/android/view/Surface.htmlImageCapture.Builder.setIoExecutor()
https://developer.android.google.cn/reference/androidx/camera/core/ImageCapture.Builder#setIoExecutor%28java.util.concurrent.Executor%29
备选 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%29ImageProcessor
https://developer.android.google.cn/reference/androidx/camera/core/ImageProcessorImageProcessor.Request.getInputImage()
https://developer.android.google.cn/reference/androidx/camera/core/ImageProcessor.Request#getInputImage%28%29
CameraProvider
https://developer.android.google.cn/reference/androidx/camera/core/CameraProviderUseCaseGroup.Builder.addEffect()
https://developer.android.google.cn/reference/androidx/camera/core/UseCaseGroup.Builder#addEffect%28androidx.camera.core.CameraEffect%29bindToLifecycle()
https://developer.android.google.cn/reference/androidx/camera/lifecycle/ProcessCameraProvider#bindToLifecycle%28androidx.lifecycle.LifecycleOwner,androidx.camera.core.CameraSelector,androidx.camera.core.UseCaseGroup%29CameraController
https://developer.android.google.cn/reference/androidx/camera/view/CameraControllersetEffects()
https://developer.android.google.cn/reference/androidx/camera/view/CameraController#setEffects%28java.util.Set%3Candroidx.camera.core.CameraEffect%3E%29
其他视频方面的功能
VideoCapture.Builder.setMirrorMode()
https://developer.android.google.cn/reference/androidx/camera/video/VideoCapture.Builder#setMirrorMode%28int%29MIRROR_MODE_OFF
https://developer.android.google.cn/reference/androidx/camera/core/MirrorMode#MIRROR_MODE_OFF%28%29MIRROR_MODE_ON
https://developer.android.google.cn/reference/androidx/camera/core/MirrorMode#MIRROR_MODE_ON%28%29MIRROR_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%29VideoCapture
https://developer.android.google.cn/reference/androidx/camera/video/VideoCaptureRecording.stop()
https://developer.android.google.cn/reference/androidx/camera/video/Recording#stop%28%29Recording.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%29Recording.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/AudioStatsVideoRecordEvent
https://developer.android.google.cn/reference/androidx/camera/video/VideoRecordEventRecordingStats
https://developer.android.google.cn/reference/androidx/camera/video/RecordingStats
后续步骤
CameraX 1.3 的完整版本说明
https://developer.android.google.cn/jetpack/androidx/releases/camera#version_13_2
CameraX issue
https://issuetracker.google.com/issues?q=status:open%20componentid:618491&s=created_time:descCameraX 讨论组
https://groups.google.com/a/android.com/g/camerax-developers
推荐阅读