Camera、Camera2、CameraX?3者之间啥关系?
CameraX、CamX分不清?
今天我们就一起来学习、了解下这些内容,为大家解开迷惑。
这篇文章分下面几点展开:
1) CameraX初认识?
2) Google为啥要推出CameraX?
3) CameraX基本框架介绍;
4) CameraX的基本使用示例;
5) CameraX、Camx要分清;
一、CameraX初认识?
1) CameraX 是一个 Jetpack 库,最低版本是兼容到Android5.0。好学的同学们,肯定又会问,那Jetpack库又是啥呢?
好了,那我们先来扯下Android Jetpack又是个啥。
在 Jetpack 的官方文档中是这样对它定义的:
Jetpack 是一套组件库,可帮助开发人员遵循最佳实践,减少样板代码并编写可在 Android 版本和设备上一致工作的代码,以便开发人员可以专注于他们关心的代码。
上面其实就是2个核心点,第一:Jetpack是一套组件库,注意,是一套,一套那就表示包含很多不同的组件。第二:使用Jetpack,方便我们在不同的android设备和不同的android版本上的适配,简单说,就是适配性强。
下面列表,就是热门和常用的Jetpack库,我们可以看到Camera也在其中,这个Camera*就是我们今天要重点介绍的CameraX。
上面介绍了这么多,大家应该对cameraX应该有个最基础的了解了。CameraX是一个 Jetpack 库。
这个CameraX库呢,然后呢,这个库是针对相机领域的。
二、 Google为啥要推出CameraX?
关于这点,从前面Android Jetpack库的介绍里面,其实我们也基本可以知道原因了。这个库是为了方便我们在各个Android版本和Android设备直接的适配和兼容。
官方的介绍是这样的:
CameraX 是 Jetpack 的新增库。利用该库,可以更轻松地向应用添加相机功能。该库提供了很多兼容性修复程序和解决方法,有助于在众多设备上打造一致的开发者体验。
主要优势表现为以下几点:
1)广泛的设备兼容性
CameraX 支持搭载 Android 5.0(API 级别 21)或更高版本的设备,覆盖现有 Android 设备的 98% 以上。
2)易用性
CameraX 着重于用例,使您可以专注于需要完成的任务,而无需花时间处理不同设备之间的细微差别。CameraX 支持大多数常见的相机用例:
- 预览:在屏幕上查看图片。
- 图片分析:无缝访问缓冲区中的图片以便在算法中使用,例如将其传递到机器学习套件。
- 图片拍摄:保存图片。
- 视频拍摄:保存视频和音频。
3)确保各设备间的一致性
要维持一致的相机行为并非易事。您必须考虑宽高比、屏幕方向、旋转角度、预览大小和图像大小。有了 CameraX,这些基本行为都不用您再费心。
我们设立了一个自动化 CameraX 测试实验室,用于测试搭载了 Android 5.0 及更高版本的一系列设备和这些操作系统版本中的各种相机行为。我们将持续运行这些测试,以找出各种各样的问题并进行修复。
4)新体验
CameraX 有一个可选的 Extensions API,您只需两行代码,便可借助该 API 实现与设备的原生相机应用相同的特性和功能。
扩展程序包含焦外成像(人像)、高动态范围 (HDR)、夜间模式和脸部照片修复功能,所有这些都需要设备支持。
三、 CameraX基本框架介绍
从下图我们可以看到,CameraX是基于Camera2的API进行的封装。
Camera API1,Google已经声明在Android5.0之后的设备上废弃了。所以,CameraX所能支持的功能,也就是Camera2所支持的功能。
目前CameraX为我们提供下下面几个最主要的功能,分别是预览、图片分析、图片拍摄、视频拍摄等。这些都是相机开发里面常用的功能。
四、 CameraX的基本使用示例
1)实现预览
在向应用添加预览时,请使用 PreviewView
,这是一种可以剪裁、缩放和旋转以确保正确显示的 View
。
当相机处于活动状态时,图片预览会流式传输到 PreviewView
中的 Surface。
使用 PreviewView
如需使用 PreviewView
实现 CameraX 预览,请按以下步骤操作(稍后将对这些步骤进行说明):
- (可选)配置
CameraXConfig.Provider
。 - 将
PreviewView
添加到布局。 - 请求
ProcessCameraProvider
。 - 在创建
View
时,请检查ProcessCameraProvider
。 - 选择相机并绑定生命周期和用例。
使用 PreviewView
存在一些限制。使用 PreviewView
时,您无法执行以下任何操作:
- 创建
SurfaceTexture
,以在TextureView
和Preview.SurfaceProvider
上进行设置。 - 从
TextureView
检索SurfaceTexture
,并在Preview.SurfaceProvider
上对其进行设置。 - 从
SurfaceView
获取Surface
,并在Preview.SurfaceProvider
上对其进行设置。
如果出现上述任何一种情况,Preview
就会停止将帧流式传输到 PreviewView
。
将 PreviewView 添加到布局
以下示例显示了布局中的 PreviewView
:
<FrameLayout
android:id="@ id/container">
<androidx.camera.view.PreviewView
android:id="@ id/previewView" />
</FrameLayout>
请求 CameraProvider
以下代码展示了如何请求 CameraProvider
:
import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture
public class MainActivity extends AppCompatActivity {
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
}
}
检查 CameraProvider 可用性
请求 CameraProvider
后,请验证它能否在视图创建后成功初始化。以下代码展示了如何执行此操作:
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future.
// This should never be reached.
}
}, ContextCompat.getMainExecutor(this));
如需查看此示例中使用的 bindPreview
函数的示例,请参阅下一部分中提供的代码。
选择相机并绑定生命周期和用例
创建并确认 CameraProvider
后,请执行以下操作:
- 创建
Preview
。 - 指定所需的相机
LensFacing
选项。 - 将所选相机和任意用例绑定到生命周期。
- 将
Preview
连接到PreviewView
。
以下代码展示了一个示例:
代码语言:javascript复制void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
Preview preview = new Preview.Builder()
.build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
}
请注意,bindToLifecycle()
会返回一个 Camera
对象。如需详细了解如何控制相机输出(如变焦和曝光),请参阅此指南。
现在,您已完成实现相机预览的操作。请构建您的应用,然后确认预览是否出现在您的应用中并能按预期工作。
2) 图像分析
图像分析用例为您的应用提供可供 CPU 访问的图像,您可以对这些图像执行图像处理、计算机视觉或机器学习推断。应用会实现对每个帧运行的 analyze()
方法。
如需在您的应用中使用图像分析,请按以下步骤操作:
- 构建
ImageAnalysis
用例。 - 创建
ImageAnalysis.Analyzer
。 - 将分析器设为
ImageAnalysis
。 - 将生命周期所有者、相机选择器和
ImageAnalysis
用例绑定到生命周期。
绑定后,CameraX 会立即将图像发送到已注册的分析器。完成分析后,调用 ImageAnalysis.clearAnalyzer()
或解除绑定 ImageAnalysis
用例以停止分析。
构建 ImageAnalysis 用例
ImageAnalysis
可将分析器(图像使用方)连接到 CameraX(图像生成方)。应用可以使用 ImageAnalysis.Builder
来构建 ImageAnalysis
对象。借助 ImageAnalysis.Builder
,应用可以进行以下配置:
- 图像输出参数:
- 格式:CameraX 可通过
setOutputImageFormat(int)
支持YUV_420_888
和RGBA_8888
。默认格式为YUV_420_888
。 - Resolution 和 AspectRatio:您可以设置其中一个参数,但请注意,您不能同时设置这两个值。
- 旋转角度。
- 目标名称:使用该参数进行调试。* 图像流控制:
- 后台执行器
- 图像队列深度(分析器和 CamaraX 之间)
- 背压策略
应用可以设置分辨率或宽高比,但不能同时设置这两个值。确切的输出分辨率取决于应用请求的大小(或宽高比)和硬件功能,并可能与请求的大小或宽高比不同。如需了解分辨率匹配算法,请参阅有关 setTargetResolution()
的文档
应用可以将输出图像像素配置为采用 YUV(默认)或 RGBA 颜色空间。设置 RGBA 输出格式时,CameraX 会在内部将图像从 YUV 颜色空间转换为 RGBA 颜色空间,并将图像位打包到 ImageProxy 第一个平面(其他两个平面未使用)的 ByteBuffer
中,序列如下:
ImageProxy.getPlanes()[0].buffer[0]: alpha
ImageProxy.getPlanes()[0].buffer[1]: red
ImageProxy.getPlanes()[0].buffer[2]: green
ImageProxy.getPlanes()[0].buffer[3]: blue
...
在执行设备无法满足帧速率要求的复杂图像分析时,您可以使用本主题的操作模式部分所述的策略将 CameraX 配置为丢帧。
创建分析器
应用可以通过实现 ImageAnalysis.Analyzer
接口并替换 analyze(ImageProxy image)
来创建分析器。在每个分析器中,应用都会收到一个 ImageProxy
,它是 Media.Image 的封装容器。可以使用 ImageProxy.getFormat()
来查询图像格式。该格式使用应用通过 ImageAnalysis.Builder
提供的以下值之一表示:
- 如果应用请求了
OUTPUT_IMAGE_FORMAT_RGBA_8888
,则为ImageFormat.RGBA_8888
。 - 如果应用请求了
OUTPUT_IMAGE_FORMAT_YUV_420_888
,则为ImageFormat.YUV_420_888
。
如需了解颜色空间配置以及可检索像素字节的位置,请参阅构建 ImageAnalysis 用例。
在分析器中,应用应执行以下操作:
- 尽快分析给定的帧,最好在给定的帧速率时间限制内进行分析(例如,如果帧速率为 30 fps,则用时应低于 32 毫秒)。如果应用无法足够快地分析帧,请考虑采用一种受支持的丢帧机制。
- 通过调用
ImageProxy.close()
将ImageProxy
发布到 CameraX。请注意,您不应调用已封装 Media.Image 的 close 函数 (Media.Image.close()
)。
应用可以直接使用 ImageProxy 中的已封装 Media.Image
。请不要对已封装的图像调用 Media.Image.close()
,因为这会破坏 CameraX 中的图像分享机制;请改为使用 ImageProxy.close()
将底层 Media.Image
发布到 CameraX。
针对 ImageAnalysis 配置分析器
创建分析器后,使用 ImageAnalysis.setAnalyzer()
注册该分析器以开始分析。完成分析后,使用 ImageAnalysis.clearAnalyer()
移除已注册的分析器。
您只能配置一个活跃分析器用于分析图像。调用 ImageAnalysis.setAnalyzer()
会替换已注册的分析器(如果已存在该分析器)。应用可以在绑定用例之前或之后随时设置新的分析器。
将 ImageAnalysis 绑定到生命周期
注意:该步骤适用于所有 CameraX 用例。如需详细了解绑定和生命周期自定义,请参阅 CameraX API 模型。
强烈建议您使用 ProcessCameraProvider.bindToLifecycle()
函数将 ImageAnalysis
绑定到现有的 AndroidX 生命周期。请注意,bindToLifecycle()
函数会返回选定的 Camera
设备,该函数可用于微调曝光等高级设置。如需详细了解如何控制相机输出,请参阅此指南。
以下示例结合了上述步骤中的所有操作,将 CameraX ImageAnalysis
和 Preview
用例绑定到了 lifeCycle
所有者:
ImageAnalysis imageAnalysis =
new ImageAnalysis.Builder()
// enable the following line if RGBA output is needed.
//.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
.setTargetResolution(new Size(1280, 720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
@Override
public void analyze(@NonNull ImageProxy imageProxy) {
int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
// insert your code here.
...
// after done, release the ImageProxy object
imageProxy.close();
}
});
cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);
3)图片拍摄
图片拍摄用例旨在拍摄高分辨率的优质照片,不仅提供简单的相机手动控制功能,还提供自动白平衡、自动曝光和自动对焦 (3A) 功能。调用方负责决定如何使用拍摄的照片,具体包括以下选项:
takePicture(Executor, OnImageCapturedCallback)
:此方法为拍摄的图片提供内存缓冲区。takePicture(OutputFileOptions, Executor, OnImageSavedCallback)
:此方法将拍摄的图片保存到提供的文件位置。
运行 ImageCapture
的可自定义执行程序有两种类型:回调执行程序和 IO 执行程序。
- 回调执行程序是
takePicture
方法的参数。它用于执行用户提供的OnImageCapturedCallback()
。 - 如果调用方选择将图片保存到文件位置,您可以指定执行程序以执行 IO。如需设置 IO 执行程序,请调用
ImageCapture.Builder.setIoExecutor(Executor)
。如果执行程序不存在,则默认 CameraX 为任务的内部 IO 执行程序。
实现
提供了拍照所需的基本控制功能。照片是使用闪光灯选项和连续自动对焦拍摄的。
如需缩短照片拍摄的延迟时间,请将 ImageCapture.CaptureMode
设置为 CAPTURE_MODE_MINIMIZE_LATENCY
。如需优化照片质量,请将其设置为 CAPTURE_MODE_MAXIMIZE_QUALITY
。
以下代码示例展示了如何配置应用以拍摄照片:
代码语言:javascript复制ImageCapture imageCapture =
new ImageCapture.Builder()
.setTargetRotation(view.getDisplay().getRotation())
.build();
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageCapture, imageAnalysis, preview);
请注意,bindToLifecycle()
会返回一个 Camera
对象。如需详细了解如何控制相机输出(如变焦和曝光),请参阅此指南。
配置好相机后,以下代码会根据用户操作拍照:
代码语言:javascript复制public void onClick() {
ImageCapture.OutputFileOptions outputFileOptions =
new ImageCapture.OutputFileOptions.Builder(new File(...)).build();
imageCapture.takePicture(outputFileOptions, cameraExecutor,
new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(ImageCapture.OutputFileResults outputFileResults) {
// insert your code here.
}
@Override
public void onError(ImageCaptureException error) {
// insert your code here.
}
}
);
}
图片拍摄方法完全支持 JPEG
格式。如需查看有关如何将 Media.Image
对象从 YUV_420_888
格式转换为 RGB Bitmap
对象的示例代码,请参阅 YuvToRgbConverter.kt
。
4)CameraX 视频捕获架构
捕获系统通常会录制视频流和音频流,对其进行压缩,对这两个流进行多路复用,然后将生成的流写入磁盘。
图 1. 视频和音频捕获系统概念图。
在 CameraX 中,用于视频捕获的解决方案是 VideoCapture
用例:
图 2. 展示 CameraX 如何处理 VideoCapture
用例的概念图。
如图 2 所示,CameraX 视频捕获包括几个高级架构组件:
SurfaceProvider
,表示视频来源。AudioSource
,表示音频来源。- 用于对视频/音频进行编码和压缩的两个编码器。
- 用于对两个流进行多路复用的媒体复用器。
- 用于写出结果的文件保存器。
VideoCapture API 会对复杂的捕获引擎进行抽象化处理,为应用提供更加简单且直观的 API。
VideoCapture API 概述
VideoCapture
是一种 CameraX 用例,既可以单独使用,也可以与其他用例搭配使用。受支持的具体组合取决于相机硬件功能,不过 Preview
和 VideoCapture
这一用例组合适用于所有设备。
注意:VideoCapture
是在 CameraX 软件包内的 camera-video
库中实现的,在 1.1.0-alpha10
及更高版本中可用。
VideoCapture API 包含可与应用通信的以下对象:
VideoCapture
是顶级用例类。VideoCapture
通过CameraSelector
和其他 CameraX 用例绑定到LifecycleOwner
。如需详细了解这些概念和用法,请参阅 CameraX 架构。Recorder
是与VideoCapture
紧密耦合的 VideoOutput 实现。Recorder
用于执行视频和音频捕获操作。应用通过Recorder
创建录制对象。PendingRecording
会配置录制对象,同时提供启用音频和设置事件监听器等选项。您必须使用Recorder
来创建PendingRecording
。PendingRecording
不会录制任何内容。Recording
会执行实际录制操作。您必须使用PendingRecording
来创建Recording
。
图 3 展示了这些对象之间的关系:
图 3. 展示 VideoCapture 用例中发生的交互的示意图。
图例:
- 使用
QualitySelector
创建Recorder
。 - 使用其中一个
OutputOptions
配置Recorder
。 - 如果需要,使用
withAudioEnabled()
启用音频。 - 使用
VideoRecordEvent
监听器调用start()
以开始录制。 - 针对
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()
来设置文件大小上限。其他选项特定于单个输出类型,例如 ParcelFileDescriptor
特定于 FileDescriptorOutputOptions
。
prepareRecording()
会返回 PendingRecording
对象,该对象是一个中间对象,用于创建相应的 Recording
对象。PendingRecording
是一个瞬态类,在大多数情况下应不可见,并且很少被应用缓存。
应用可以进一步配置录制对象,例如:
- 使用
withAudioEnabled()
启用音频。 - 使用
start(Executor, Consumer<VideoRecordEvent>)
注册监听器,以接收视频录制事件。
要开始录制,请调用 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)
控制活跃录制对象
您可以使用以下方法暂停、恢复和停止正在进行的 Recording
:
pause
,用于暂停当前的活跃录制。resume()
,用于恢复已暂停的活跃录制。stop()
,用于完成录制并清空所有关联的录制对象。
请注意,无论录制处于暂停状态还是活跃状态,您都可以调用 stop()
来终止 Recording
。
如果您已使用 PendingRecording.start()
注册了 EventListener
,Recording
会使用 VideoRecordEvent
进行通信。
VideoRecordEvent.EVENT_TYPE_STATUS
用于录制统计信息,例如当前文件的大小和录制的时间跨度。VideoRecordEvent.EVENT_TYPE_FINALIZE
用于录制结果,会包含最终文件的 URI 以及任何相关错误等信息。
在您的应用收到表示录制会话成功的 EVENT_TYPE_FINALIZE
后,您就可以从 OutputOptions
中指定的位置访问捕获的视频。
五、 CameraX、Camx要分清
从事高通平台Camera Hal开发的同学, 对Camx应该不陌生。CamX是高通目前最新的Camera框架,是Hal层实现的一套框架,高通旧的Camera框架是mm-camera框架。
所以对应CameraX,我一般会说成Google CameraX,方便有些同学搞混淆。
参考文档:
Android Jetpack介绍
https://developer.android.google.cn/jetpack?hl=zh-cn
CameraX架构
https://developer.android.google.cn/training/camerax/architecture?hl=zh_cn
相机使用示例代码
https://github.com/android/camera-samples/