在应用中添加预览时,请使用 PreviewView
,它是一个可以裁剪、缩放和旋转以进行正确显示的 View
。
当相机激活时,图像预览会流式传输到 PreviewView
内部的表面。
使用 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
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
后,请执行以下操作
- 创建一个
Preview
。 - 指定所需的相机
LensFacing
选项。 - 将选定的相机和任何用例绑定到生命周期。
- 将
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
显示视频流,但在某些情况下回退到TextureView
。SurfaceView
有一个专用的绘图表面,更有可能由内部硬件合成器使用硬件叠加层实现,尤其是在预览视频顶部没有其他 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_CENTER
、FIT_START
和FIT_END
用于留黑边。整个视频内容会缩放(向上或向下)到可以在目标PreviewView
中显示的最大可能尺寸。但是,尽管整个视频帧可见,但屏幕的某些部分可能为空白。根据您选择的三种缩放类型中的哪一种,视频帧会与目标 View 的中心、开头或结尾对齐。FILL_CENTER
、FILL_START
、FILL_END
用于裁剪。如果视频与PreviewView
的纵横比不匹配,则只会显示一部分内容,但视频会填充整个PreviewView
。
CameraX 使用的默认缩放类型是FILL_CENTER
。使用PreviewView.setScaleType()
设置最适合您应用程序的缩放类型。以下代码示例设置了FIT_CENTER
缩放类型
Kotlin
// viewFinder is a PreviewView instance viewFinder.scaleType = PreviewView.ScaleType.FIT_CENTER
显示视频的过程包括以下步骤
- 缩放视频
- 对于
FIT_*
缩放类型,使用min(dst.width/src.width, dst.height/src.height)
缩放视频。 - 对于
FILL_*
缩放类型,使用max(dst.width/src.width, dst.height/src.height)
缩放视频。
- 对于
- 将缩放后的视频与目标
PreviewView
对齐- 对于
FIT_CENTER/FILL_CENTER
,将缩放后的视频和目标PreviewView
居中对齐。 - 对于
FIT_START/FILL_START
,将缩放后的视频和目标PreviewView
相对于各自的左上角对齐。 - 对于
FIT_END/FILL_END
,将缩放后的视频和目标PreviewView
相对于各自的右下角对齐。
- 对于
例如,这是一个 640x480 的源视频和一个 1920x1080 的目标PreviewView
下图显示了FIT_START
/ FIT_CENTER
/ FIT_END
缩放过程
该过程的工作原理如下
- 使用
min(1920/640, 1080/480) = 2.25
缩放视频帧(保持原始纵横比),以获得 1440x1080 的中间视频帧。 - 将 1440x1080 的视频帧与 1920x1080 的
PreviewView
对齐。- 对于
FIT_CENTER
,将视频帧与PreviewView
窗口的**中心**对齐。PreviewView
的起始和结束 240 像素列为空白。 - 对于
FIT_START
,将视频帧与PreviewView
窗口的**开头**(左上角)对齐。PreviewView
的结束 480 像素列为空白。 - 对于
FIT_END
,将视频帧与PreviewView
窗口的**结尾**(右下角)对齐。PreviewView
的起始 480 像素列为空白。
- 对于
下图显示了FILL_START
/ FILL_CENTER
/ FILL_END
缩放过程
该过程的工作原理如下
- 使用
max(1920/640, 1080/480) = 3
缩放视频帧,以获得 1920x1440 的中间视频帧(大于PreviewView
的尺寸)。 - 裁剪 1920x1440 的视频帧以适合 1920x1080 的
PreviewView
窗口。- 对于
FILL_CENTER
,从 1920x1440 缩放视频的**中心**裁剪 1920x1080。视频的顶部和底部 180 行不可见。 - 对于
FILL_START
,从 1920x1440 缩放视频的**开头**裁剪 1920x1080。视频的底部 360 行不可见。 - 对于
FILL_END
,从 1920x1440 缩放视频的**结尾**裁剪 1920x1080。视频的顶部 360 行不可见。
- 对于
其他资源
要了解有关 CameraX 的更多信息,请参阅以下其他资源。
Codelab
代码示例