捕获系统通常会录制视频和音频流,对其进行压缩,将两个流复用,然后将结果流写入磁盘。

在 CameraX 中,视频捕获的解决方案是 VideoCapture
用例

VideoCapture
用例的概念图。如图 2 所示,CameraX 视频捕获包含几个高层架构组件
- 用于视频源的
SurfaceProvider
。 - 用于音频源的
AudioSource
。 - 两个编码器,用于编码和压缩视频/音频。
- 一个媒体复用器,用于复用两个流。
- 一个文件保存器,用于写入结果。
VideoCapture API 抽象了复杂的捕获引擎,并为应用程序提供了更简单直接的 API。
VideoCapture API 概览
VideoCapture
是 CameraX 用例,可以独立良好工作,也可以与其他用例结合使用。具体的支持组合取决于相机硬件功能,但 Preview
和 VideoCapture
是所有设备上都有效的用例组合。
VideoCapture API 由以下与应用程序通信的对象组成
VideoCapture
是顶级用例类。VideoCapture
通过CameraSelector
和其他 CameraX 用例绑定到LifecycleOwner
。有关这些概念和用法的更多信息,请参阅CameraX 架构。Recorder
是 VideoOutput 的一个实现,与VideoCapture
紧密耦合。Recorder
用于执行视频和音频捕获。应用程序从Recorder
创建录制内容。PendingRecording
配置录制,提供启用音频和设置事件监听器等选项。您必须使用Recorder
创建PendingRecording
。PendingRecording
不会录制任何内容。Recording
执行实际的录制。您必须使用PendingRecording
创建Recording
。
图 3 显示了这些对象之间的关系

图例
- 使用
QualitySelector
创建Recorder
。 - 使用其中一个
OutputOptions
配置Recorder
。 - 如果需要,使用
withAudioEnabled()
启用音频。 - 调用
start()
并传入VideoRecordEvent
监听器以开始录制。 - 在
Recording
上使用pause()
/resume()
/stop()
来控制录制。 - 在您的事件监听器中响应
VideoRecordEvents
。
详细的 API 列表位于源代码中的 current.txt 中。
使用 VideoCapture API
要将 CameraX VideoCapture
用例集成到您的应用中,请执行以下操作
- 绑定
VideoCapture
。 - 准备和配置录制。
- 启动并控制运行时录制。
以下各节概述了您可以在每个步骤中执行的操作,以获得端到端的录制会话。
绑定 VideoCapture
要绑定 VideoCapure
用例,请执行以下操作
- 创建
Recorder
对象。 - 创建
VideoCapture
对象。 - 绑定到
Lifecycle
。
CameraX VideoCapture API 遵循构建器设计模式。应用程序使用 Recorder.Builder
创建 Recorder
。您还可以通过 QualitySelector
对象配置 Recorder
的视频分辨率。
CameraX Recorder
支持以下预定义的视频分辨率 Qualities
Quality.UHD
用于 4K 超高清视频大小 (2160p)Quality.FHD
用于全高清视频大小 (1080p)Quality.HD
用于高清视频大小 (720p)Quality.SD
用于标清视频大小 (480p)
请注意,CameraX 也可以在应用程序授权时选择其他分辨率。
每个选择的确切视频大小取决于相机和编码器的功能。有关更多信息,请参阅 CamcorderProfile
的文档。
应用程序可以通过创建 QualitySelector
来配置分辨率。您可以使用以下方法之一创建 QualitySelector
通过使用
fromOrderedList()
提供一些首选分辨率,并包含一个备用策略,以防不支持任何首选分辨率。CameraX 可以根据所选相机的功能决定最佳备用匹配,有关更多详细信息,请参阅
QualitySelector
的FallbackStrategy specification
。例如,以下代码请求录制支持的最高分辨率,如果不支持任何请求的分辨率,则授权 CameraX 选择一个最接近 Quality.SD 分辨率的。val qualitySelector = QualitySelector.fromOrderedList( listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD), FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))
首先查询相机功能,然后使用
QualitySelector::from()
从支持的分辨率中选择。val cameraInfo = cameraProvider.availableCameraInfos.filter { Camera2CameraInfo .from(it) .getCameraCharacteristic(CameraCharacteristics.LENS\_FACING) == CameraMetadata.LENS_FACING_BACK } val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo[0]) val filteredQualities = arrayListOf (Quality.UHD, Quality.FHD, Quality.HD, Quality.SD) .filter { supportedQualities.contains(it) } // Use a simple ListView with the id of simple_quality_list_view viewBinding.simpleQualityListView.apply { adapter = ArrayAdapter(context, android.R.layout.simple_list_item_1, filteredQualities.map { it.qualityToString() }) // Set up the user interaction to manually show or hide the system UI. setOnItemClickListener { _, _, position, _ -> // Inside View.OnClickListener, // convert Quality.* constant to QualitySelector val qualitySelector = QualitySelector.from(filteredQualities[position]) // Create a new Recorder/VideoCapture for the new quality // and bind to lifecycle val recorder = Recorder.Builder() .setQualitySelector(qualitySelector).build() // ... } } // A helper function to translate Quality to a string fun Quality.qualityToString() : String { return when (this) { Quality.UHD -> "UHD" Quality.FHD -> "FHD" Quality.HD -> "HD" Quality.SD -> "SD" else -> throw IllegalArgumentException() } }
请注意,从
QualitySelector.getSupportedQualities()
返回的功能保证适用于VideoCapture
用例或VideoCapture
和Preview
用例的组合。当与ImageCapture
或ImageAnalysis
用例一起绑定时,当所需组合在请求的相机上不受支持时,CameraX 仍可能无法绑定。
一旦您有了 QualitySelector
,应用程序就可以创建 VideoCapture
对象并执行绑定。请注意,此绑定与其他用例相同。
val recorder = Recorder.Builder()
.setExecutor(cameraExecutor).setQualitySelector(qualitySelector)
.build()
val videoCapture = VideoCapture.withOutput(recorder)
try {
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, CameraSelector.DEFAULT_BACK_CAMERA, preview, videoCapture)
} catch(exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
请注意,bindToLifecycle()
返回一个 Camera
对象。有关控制相机输出(例如变焦和曝光)的更多信息,请参阅本指南。
Recorder
为系统选择最合适的格式。最常见的视频编解码器是 H.264 AVC,容器格式为 MPEG-4。
配置和创建录制
从 Recorder
中,应用程序可以创建录制对象来执行视频和音频捕获。应用程序通过执行以下操作创建录制内容
- 使用
prepareRecording()
配置OutputOptions
。 - (可选)启用音频录制。
- 使用
start()
注册VideoRecordEvent
监听器,并开始视频捕获。
当您调用 start()
函数时,Recorder
会返回一个 Recording
对象。您的应用程序可以使用此 Recording
对象来完成捕获或执行其他操作,例如暂停或恢复。
一个 Recorder
一次只支持一个 Recording
对象。您可以在对上一个 Recording
对象调用 Recording.stop()
或 Recording.close()
后开始新的录制。
让我们更详细地了解这些步骤。首先,应用程序使用 Recorder.prepareRecording()
为 Recorder 配置 OutputOptions
。Recorder
支持以下类型的 OutputOptions
FileDescriptorOutputOptions
用于捕获到FileDescriptor
。FileOutputOptions
用于捕获到File
。MediaStoreOutputOptions
用于捕获到MediaStore
。
所有 OutputOptions
类型都允许您使用 setFileSizeLimit()
设置最大文件大小。其他选项特定于单个输出类型,例如 FileDescriptorOutputOptions
的 ParcelFileDescriptor
。
prepareRecording()
返回一个 PendingRecording
对象,这是一个中间对象,用于创建相应的 Recording
对象。PendingRecording
是一个瞬态类,在大多数情况下应该是不可见的,并且很少被应用程序缓存。
应用程序可以进一步配置录制,例如
- 使用
withAudioEnabled()
启用音频。 - 使用
start(Executor, Consumer<VideoRecordEvent>)
注册一个监听器以接收视频录制事件。 - 允许录制在其附加的 VideoCapture 重新绑定到另一个相机时连续录制,使用
PendingRecording.asPersistentRecording()
。
要开始录制,请调用 PendingRecording.start()
。CameraX 将 PendingRecording
转换为 Recording
,将录制请求排队,并将新创建的 Recording
对象返回给应用程序。一旦录制在相应的相机设备上开始,CameraX 会发送一个 VideoRecordEvent.EVENT_TYPE_START
事件。
以下示例显示了如何将视频和音频录制到 MediaStore
文件中
// Create MediaStoreOutputOptions for our recorder
val name = "CameraX-recording-" +
SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis()) + ".mp4"
val contentValues = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name)
}
val mediaStoreOutput = MediaStoreOutputOptions.Builder(this.contentResolver,
MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
.setContentValues(contentValues)
.build()
// 2. Configure Recorder and Start recording to the mediaStoreOutput.
val recording = videoCapture.output
.prepareRecording(context, mediaStoreOutput)
.withAudioEnabled()
.start(ContextCompat.getMainExecutor(this), captureListener)
虽然相机预览默认在前置摄像头上镜像,但 VideoCapture 录制的视频默认不镜像。使用 CameraX 1.3,现在可以镜像视频录制,以便前置摄像头预览和录制的视频匹配。
有三种 MirrorMode 选项:MIRROR_MODE_OFF、MIRROR_MODE_ON 和 MIRROR_MODE_ON_FRONT_ONLY。为了与相机预览对齐,Google 建议使用 MIROR_MODE_ON_FRONT_ONLY,这意味着后置摄像头不启用镜像,但前置摄像头启用镜像。有关 MirrorMode 的更多信息,请参阅 MirrorMode constants
。
此代码片段演示了如何使用 MIRROR_MODE_ON_FRONT_ONLY
调用 VideoCapture.Builder.setMirrorMode()
。有关更多信息,请参阅 setMirrorMode()
。
Kotlin
val recorder = Recorder.Builder().build() val videoCapture = VideoCapture.Builder(recorder) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build() useCases.add(videoCapture);
Java
Recorder.Builder builder = new Recorder.Builder(); if (mVideoQuality != QUALITY_AUTO) { builder.setQualitySelector( QualitySelector.from(mVideoQuality)); } VideoCapture<Recorder> videoCapture = new VideoCapture.Builder<>(builder.build()) .setMirrorMode(MIRROR_MODE_ON_FRONT_ONLY) .build(); useCases.add(videoCapture);
控制活动录制
您可以使用以下方法暂停、恢复和停止正在进行的 Recording
请注意,您可以调用 stop()
来终止 Recording
,无论录制是处于暂停状态还是活动录制状态。
如果您使用 PendingRecording.start()
注册了 EventListener
,则 Recording
会使用 VideoRecordEvent
进行通信。
VideoRecordEvent.EVENT_TYPE_STATUS
用于录制统计信息,例如当前文件大小和录制时长。VideoRecordEvent.EVENT_TYPE_FINALIZE
用于录制结果,并包含最终文件的 URI 以及任何相关错误等信息。
一旦您的应用收到表示录制会话成功的 EVENT_TYPE_FINALIZE
,您就可以从 OutputOptions
中指定的位置访问捕获的视频。
其他资源
要了解有关 CameraX 的更多信息,请参阅以下其他资源