You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中如何将SurfaceView作为Preview的SurfaceProvider并让PreviewView显示USB相机?

Android CameraX USB相机绑定PreviewView异常问题

我在Android开发中有两个Fragment,各包含一个PreviewView用于显示相机画面:

  • DeviceFragment:显示内置相机画面,运行正常
  • UsbCameraFragment:应显示外接USB相机画面,但PreviewView始终显示内置相机画面,而该Fragment中的SurfaceView却能正常显示USB相机画面。

最终目标是通过CameraProvider.bindToLifecycle()处理相机画面,创建了Preview对象并设置PreviewView.getSurfaceProvider()作为其SurfaceProvider,但SurfaceView没有返回SurfaceProvider的方法,无法实现相同操作。

核心代码片段

private void bindCamera(ProcessCameraProvider cameraProvider) {
    ImageAnalysis imageAnalysis = imageAnalysisService.bindImageAnalysis(surfaceView); // 目前无关,后续可提供
    Preview preview = new Preview.Builder().build();
    preview.setSurfaceProvider(previewView.getSurfaceProvider()); // 此处希望使用SurfaceView或转换为PreviewView的SurfaceProvider
    CameraSelector cameraSelector = new CameraSelector.Builder()
                    .requireLensFacing(CameraSelector.LENS_FACING_BACK).build();

    cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
}

备注

  • 注释掉preview.setSurfaceProvider(previewView.getSurfaceProvider());后,SurfaceView可正常显示且不会被PreviewView覆盖
  • 保留该代码时,SurfaceView会短暂显示后被PreviewView渲染的内置相机画面覆盖
  • 尝试给CameraSelector添加过滤器,但发现USB相机未在可用相机列表中

问题根源

  1. CameraSelector匹配错误:默认的LENS_FACING_BACK仅匹配内置后置相机,USB相机不会被归类到该镜头朝向,且默认不在CameraX的可用相机列表中。
  2. PreviewView抢占渲染:绑定内置相机的Preview到PreviewView后,会覆盖SurfaceView的USB相机画面,CameraX绑定的渲染优先级更高。

解决步骤

1. 让CameraX识别USB相机

CameraX默认不支持USB相机,需添加扩展依赖并通过过滤器筛选:

  • 首先在build.gradle添加依赖:
implementation "androidx.camera:camera2-extensions:${cameraXVersion}"
  • 然后创建USB相机专属的CameraSelector:
CameraSelector usbCameraSelector = new CameraSelector.Builder()
    .addCameraFilter(cameraInfos -> {
        List<CameraInfo> usbCameras = new ArrayList<>();
        for (CameraInfo info : cameraInfos) {
            CameraCharacteristics characteristics = ((Camera2CameraInfo) info).getCameraCharacteristics();
            Integer deviceType = characteristics.get(CameraCharacteristics.INFO_DEVICE_TYPE);
            if (deviceType != null && deviceType == CameraCharacteristics.INFO_DEVICE_TYPE_EXTERNAL) {
                usbCameras.add(info);
            }
        }
        return usbCameras;
    })
    .build();

2. 为SurfaceView自定义SurfaceProvider

如果要继续用SurfaceView配合bindToLifecycle,可以实现自定义SurfaceProvider适配:

preview.setSurfaceProvider(new SurfaceProvider() {
    @Override
    public void onSurfaceRequested(@NonNull SurfaceRequest request) {
        Surface surface = surfaceView.getHolder().getSurface();
        if (surface.isValid()) {
            request.provideSurface(surface, Executors.newSingleThreadExecutor(), result -> {
                // 处理Surface使用结果
            });
        } else {
            surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(@NonNull SurfaceHolder holder) {
                    request.provideSurface(holder.getSurface(), Executors.newSingleThreadExecutor(), result -> {});
                    surfaceView.getHolder().removeCallback(this);
                }

                @Override
                public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}

                @Override
                public void surfaceDestroyed(@NonNull SurfaceHolder holder) {}
            });
        }
    }
});

3. 绑定USB相机

替换原CameraSelector,确保绑定的是USB相机:

cameraProvider.bindToLifecycle(this, usbCameraSelector, preview, imageAnalysis);

额外注意事项

  • 权限:需申请CAMERA权限,USB相机还需动态申请USB_PERMISSION并处理设备权限请求。
  • 兼容性:不同USB相机的适配差异较大,部分设备可能需要特定驱动支持。

内容的提问来源于stack exchange,提问作者Marcelo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:22:36