一篇文章带你了解Google CameraX

2022-09-22 11:38:45 浏览数 (1)

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 预览,请按以下步骤操作(稍后将对这些步骤进行说明):

  1. (可选)配置 CameraXConfig.Provider
  2. PreviewView 添加到布局。
  3. 请求 ProcessCameraProvider
  4. 在创建 View 时,请检查 ProcessCameraProvider
  5. 选择相机并绑定生命周期和用例。

使用 PreviewView 存在一些限制。使用 PreviewView 时,您无法执行以下任何操作:

  • 创建 SurfaceTexture,以在 TextureViewPreview.SurfaceProvider 上进行设置。
  • TextureView 检索 SurfaceTexture,并在 Preview.SurfaceProvider 上对其进行设置。
  • SurfaceView 获取 Surface,并在 Preview.SurfaceProvider 上对其进行设置。

如果出现上述任何一种情况,Preview 就会停止将帧流式传输到 PreviewView

将 PreviewView 添加到布局

以下示例显示了布局中的 PreviewView

代码语言:javascript复制
<FrameLayout
    android:id="@ id/container">
        <androidx.camera.view.PreviewView
            android:id="@ id/previewView" />
</FrameLayout>

请求 CameraProvider

以下代码展示了如何请求 CameraProvider

代码语言:javascript复制
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 后,请验证它能否在视图创建后成功初始化。以下代码展示了如何执行此操作:

代码语言:javascript复制
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 后,请执行以下操作:

  1. 创建 Preview
  2. 指定所需的相机 LensFacing 选项。
  3. 将所选相机和任意用例绑定到生命周期。
  4. 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_888RGBA_8888。默认格式为 YUV_420_888
  • Resolution 和 AspectRatio:您可以设置其中一个参数,但请注意,您不能同时设置这两个值。
  • 旋转角度。
  • 目标名称:使用该参数进行调试。* 图像流控制:
  • 后台执行器
  • 图像队列深度(分析器和 CamaraX 之间)
  • 背压策略

应用可以设置分辨率或宽高比,但不能同时设置这两个值。确切的输出分辨率取决于应用请求的大小(或宽高比)和硬件功能,并可能与请求的大小或宽高比不同。如需了解分辨率匹配算法,请参阅有关 setTargetResolution() 的文档

应用可以将输出图像像素配置为采用 YUV(默认)或 RGBA 颜色空间。设置 RGBA 输出格式时,CameraX 会在内部将图像从 YUV 颜色空间转换为 RGBA 颜色空间,并将图像位打包到 ImageProxy 第一个平面(其他两个平面未使用)的 ByteBuffer 中,序列如下:

代码语言:javascript复制
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 用例。

在分析器中,应用应执行以下操作:

  1. 尽快分析给定的帧,最好在给定的帧速率时间限制内进行分析(例如,如果帧速率为 30 fps,则用时应低于 32 毫秒)。如果应用无法足够快地分析帧,请考虑采用一种受支持的丢帧机制。
  2. 通过调用 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 ImageAnalysisPreview 用例绑定到了 lifeCycle 所有者:

代码语言:javascript复制
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 用例,既可以单独使用,也可以与其他用例搭配使用。受支持的具体组合取决于相机硬件功能,不过 PreviewVideoCapture 这一用例组合适用于所有设备。

注意VideoCapture 是在 CameraX 软件包内的 camera-video 库中实现的,在 1.1.0-alpha10 及更高版本中可用。

VideoCapture API 包含可与应用通信的以下对象:

  • VideoCapture 是顶级用例类。VideoCapture 通过 CameraSelector 和其他 CameraX 用例绑定到 LifecycleOwner。如需详细了解这些概念和用法,请参阅 CameraX 架构。
  • Recorder 是与 VideoCapture 紧密耦合的 VideoOutput 实现。 Recorder 用于执行视频和音频捕获操作。应用通过 Recorder 创建录制对象。
  • PendingRecording 会配置录制对象,同时提供启用音频和设置事件监听器等选项。您必须使用 Recorder 来创建 PendingRecordingPendingRecording 不会录制任何内容。
  • Recording 会执行实际录制操作。您必须使用 PendingRecording 来创建 Recording

图 3 展示了这些对象之间的关系:

图 3. 展示 VideoCapture 用例中发生的交互的示意图。

图例

  1. 使用 QualitySelector 创建 Recorder
  2. 使用其中一个 OutputOptions 配置 Recorder
  3. 如果需要,使用 withAudioEnabled() 启用音频。
  4. 使用 VideoRecordEvent 监听器调用 start() 以开始录制。
  5. 针对 Recording 使用 pause()/resume()/stop() 来控制录制操作。
  6. 在事件监听器内响应 VideoRecordEvents

详细的 API 列表位于源代码内的 current-txt 中。

使用 VideoCapture API

如需将 CameraX VideoCapture 用例集成到您的应用中,请执行以下操作:

  1. 绑定 VideoCapture
  2. 准备和配置录制。
  3. 开始和控制运行时录制。

后面的部分概述了您可以在每个步骤中执行哪些操作,以获取端到端录制会话。

绑定 VideoCapture

如需绑定 VideoCapure 用例,请执行以下操作:

  1. 创建一个 Recorder 对象。
  2. 创建 VideoCapture 对象。
  3. 绑定到 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 可以根据所选相机的功能确定最佳后备匹配项。如需了解详情,请参阅 QualitySelectorFallbackStrategy specification。例如,以下代码会请求支持的最高录制分辨率;如果所有请求分辨率都不受支持,则授权 CameraX 选择最接近 Quality.SD 分辨率的分辨率:

代码语言:javascript复制
val qualitySelector = QualitySelector.fromOrderedList(
         listOf(Quality.UHD, Quality.FHD, Quality.HD, Quality.SD),
         FallbackStrategy.lowerQualityOrHigherThan(Quality.SD))

  • 首先查询相机功能,然后使用 QualitySelector::from() 从受支持的分辨率中进行选择:
代码语言:javascript复制
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 用例或 VideoCapturePreview 用例的组合。与 ImageCaptureImageAnalysis 用例绑定时,如果请求的相机不支持所需的组合,CameraX 仍可能会绑定失败。

具有 QualitySelector 后,应用即可创建 VideoCapture 对象并执行绑定。请注意,此绑定与和其他用例的绑定相同:

代码语言:javascript复制
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 创建录制对象来执行视频和音频捕获操作。应用通过执行以下操作来创建录制对象:

  1. 使用 prepareRecording() 配置 OutputOptions
  2. (可选)启用录音功能。
  3. 使用 start() 注册 VideoRecordEvent 监听器,并开始捕获视频。

当您调用 start() 函数时,Recorder 会返回 Recording 对象。应用可以使用此 Recording 对象完成捕获或执行其他操作,例如暂停或恢复。

Recorder 一次支持一个 Recording 对象。对前面的 Recording 对象调用 Recording.stop()Recording.close() 后,您便可以开始新的录制。

我们来更详细地看看这些步骤。首先,应用使用 Recorder.prepareRecording() 为 Recorder 配置 OutputOptionsRecorder 支持以下类型的 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 文件中:

代码语言:javascript复制
// 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() 注册了 EventListenerRecording 会使用 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/

0 人点赞