实现预览

在应用中添加预览时,请使用 PreviewView,它是一个可以裁剪、缩放和旋转以进行正确显示的 View

当相机激活时,图像预览会流式传输到 PreviewView 内部的表面。

使用 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

<FrameLayout
    android:id="@+id/container">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
</FrameLayout>

请求一个CameraProvider

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

Kotlin

import androidx.camera.lifecycle.ProcessCameraProvider
import com.google.common.util.concurrent.ListenableFuture

class MainActivity : AppCompatActivity() {
    private lateinit var cameraProviderFuture : ListenableFuture<ProcessCameraProvider>
    override fun onCreate(savedInstanceState: Bundle?) {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
    }
}

Java

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后,在视图创建时验证其初始化是否成功。以下代码演示了如何执行此操作

Kotlin

cameraProviderFuture.addListener(Runnable {
    val cameraProvider = cameraProviderFuture.get()
    bindPreview(cameraProvider)
}, ContextCompat.getMainExecutor(this))

Java

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

以下代码显示了一个示例

Kotlin

fun bindPreview(cameraProvider : ProcessCameraProvider) {
    var preview : Preview = Preview.Builder()
            .build()

    var cameraSelector : CameraSelector = CameraSelector.Builder()
          .requireLensFacing(CameraSelector.LENS_FACING_BACK)
          .build()

    preview.setSurfaceProvider(previewView.getSurfaceProvider())

    var camera = cameraProvider.bindToLifecycle(this as LifecycleOwner, cameraSelector, preview)
}

Java

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对象。有关控制相机输出(如缩放和曝光)的更多信息,请参阅相机输出

现在,您已完成相机预览的实现。构建您的应用并确认预览是否显示在您的应用中并按预期工作。

PreviewView的其他控件

CameraX PreviewView提供了一些其他 API 来配置属性,例如

实现模式

PreviewView可以使用以下模式之一将预览流渲染到目标View

  • PERFORMANCE是默认模式。PreviewView使用SurfaceView显示视频流,但在某些情况下回退到TextureViewSurfaceView有一个专用的绘图表面,更有可能由内部硬件合成器使用硬件叠加层实现,尤其是在预览视频顶部没有其他 UI 元素(如按钮)时。通过使用硬件叠加层渲染,视频帧可以避免 GPU 路径,从而可以降低平台功耗和延迟。

  • COMPATIBLE模式。在此模式下,PreviewView使用TextureView,它与SurfaceView不同,没有专用的绘图表面。因此,视频会进行混合渲染,以便可以显示。在此额外步骤期间,应用程序可以执行其他处理,例如无限制地缩放和旋转视频。

使用PreviewView.setImplementationMode()选择适合您应用程序的实现模式。如果默认的PERFORMANCE模式不适合您的应用程序,以下代码示例演示了如何设置COMPATIBLE模式

Kotlin

// viewFinder is a PreviewView instance
viewFinder.implementationMode = PreviewView.ImplementationMode.COMPATIBLE

缩放类型

当预览视频分辨率与目标PreviewView的尺寸不同时,需要通过裁剪或留黑边(保持原始纵横比)将视频内容适合视图。PreviewView为此提供了以下ScaleTypes

  • FIT_CENTERFIT_STARTFIT_END用于留黑边。整个视频内容会缩放(向上或向下)到可以在目标PreviewView中显示的最大可能尺寸。但是,尽管整个视频帧可见,但屏幕的某些部分可能为空白。根据您选择的三种缩放类型中的哪一种,视频帧会与目标 View 的中心、开头或结尾对齐。

  • FILL_CENTERFILL_STARTFILL_END用于裁剪。如果视频与PreviewView的纵横比不匹配,则只会显示一部分内容,但视频会填充整个PreviewView

CameraX 使用的默认缩放类型是FILL_CENTER。使用PreviewView.setScaleType()设置最适合您应用程序的缩放类型。以下代码示例设置了FIT_CENTER缩放类型

Kotlin

// viewFinder is a PreviewView instance
viewFinder.scaleType = PreviewView.ScaleType.FIT_CENTER

显示视频的过程包括以下步骤

  1. 缩放视频
    • 对于FIT_*缩放类型,使用min(dst.width/src.width, dst.height/src.height)缩放视频。
    • 对于FILL_*缩放类型,使用max(dst.width/src.width, dst.height/src.height)缩放视频。
  2. 将缩放后的视频与目标PreviewView对齐
    • 对于FIT_CENTER/FILL_CENTER,将缩放后的视频和目标PreviewView居中对齐。
    • 对于FIT_START/FILL_START,将缩放后的视频和目标PreviewView相对于各自的左上角对齐。
    • 对于FIT_END/FILL_END,将缩放后的视频和目标PreviewView相对于各自的右下角对齐。

例如,这是一个 640x480 的源视频和一个 1920x1080 的目标PreviewView

Image showing a 640x480 video compared to a 1920x1080 preview

下图显示了FIT_START / FIT_CENTER / FIT_END缩放过程

Image showing the FIT_START, FIT_CENTER, and FIT_END scaling process

该过程的工作原理如下

  1. 使用min(1920/640, 1080/480) = 2.25缩放视频帧(保持原始纵横比),以获得 1440x1080 的中间视频帧。
  2. 将 1440x1080 的视频帧与 1920x1080 的PreviewView对齐。
    • 对于FIT_CENTER,将视频帧与PreviewView窗口的**中心**对齐。PreviewView的起始和结束 240 像素列为空白。
    • 对于FIT_START,将视频帧与PreviewView窗口的**开头**(左上角)对齐。PreviewView的结束 480 像素列为空白。
    • 对于FIT_END,将视频帧与PreviewView窗口的**结尾**(右下角)对齐。PreviewView的起始 480 像素列为空白。

下图显示了FILL_START / FILL_CENTER / FILL_END缩放过程

Image showing the FILL_START, FILL_CENTER, and FILL_END scaling process

该过程的工作原理如下

  1. 使用max(1920/640, 1080/480) = 3缩放视频帧,以获得 1920x1440 的中间视频帧(大于PreviewView的尺寸)。
  2. 裁剪 1920x1440 的视频帧以适合 1920x1080 的PreviewView窗口。
    • 对于FILL_CENTER,从 1920x1440 缩放视频的**中心**裁剪 1920x1080。视频的顶部和底部 180 行不可见。
    • 对于FILL_START,从 1920x1440 缩放视频的**开头**裁剪 1920x1080。视频的底部 360 行不可见。
    • 对于FILL_END,从 1920x1440 缩放视频的**结尾**裁剪 1920x1080。视频的顶部 360 行不可见。

其他资源

要了解有关 CameraX 的更多信息,请参阅以下其他资源。

Codelab

  • CameraX 入门
  • 代码示例

  • CameraX 示例应用