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

Camera2框架下ImageReader无法读取图像,添加后应用崩溃求助

Camera2框架ImageReader捕获图像崩溃问题解决

核心问题分析

错误码4对应ERROR_INVALID_ARGUMENT,本质是ImageReader的配置与相机输出不兼容,或是会话创建与请求配置的Surface逻辑不匹配:只把ImageReader加入会话但未在请求中指定输出,监听器自然不会触发;若直接在请求中添加未纳入会话的Surface,或尺寸/格式不兼容,就会触发参数无效崩溃。

分步解决方案

1. 确保ImageReader配置符合相机支持的输出参数

不要硬编码尺寸和格式,先从相机特性中获取兼容配置:

val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!

// 获取相机支持的YUV格式输出尺寸(建议用YUV_420_888,兼容性最好)
val supportedSizes = configMap.getOutputSizes(ImageFormat.YUV_420_888)
// 选择与SurfaceView尺寸最接近的尺寸,避免缩放报错
val targetSize = supportedSizes.firstOrNull { 
    it.width == surfaceView.width && it.height == surfaceView.height 
} ?: supportedSizes[0]

// 创建ImageReader,最大缓存2帧避免内存溢出
val imageReader = ImageReader.newInstance(
    targetSize.width, 
    targetSize.height, 
    ImageFormat.YUV_420_888, 
    2
)

2. 严格遵循会话与请求的Surface关联逻辑

  • 创建会话时,必须把**所有需要接收相机数据的Surface(SurfaceView + ImageReader)**都传入集合:
  • 在预览请求中添加需要输出的Surface,同时确保参数配置正确:
val surfaces = listOf(surfaceView.holder.surface, imageReader.surface)
cameraDevice.createCaptureSession(surfaces, object : CameraCaptureSession.StateCallback() {
    override fun onConfigured(session: CameraCaptureSession) {
        // 构建预览请求
        val previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
        // 添加SurfaceView用于预览显示
        previewRequestBuilder.addTarget(surfaceView.holder.surface)
        // 添加ImageReader用于持续捕获图像(如果是拍照时才捕获,就只在拍照请求中添加)
        previewRequestBuilder.addTarget(imageReader.surface)
        // 开启自动对焦,提升预览体验
        previewRequestBuilder.set(
            CaptureRequest.CONTROL_AF_MODE, 
            CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE
        )
        // 启动重复预览请求
        session.setRepeatingRequest(
            previewRequestBuilder.build(), 
            null, 
            Handler(Looper.getMainLooper())
        )
    }

    override fun onConfigureFailed(session: CameraCaptureSession) {
        // 处理会话配置失败逻辑,比如弹出提示
    }
}, Handler(Looper.getMainLooper()))

3. 正确设置ImageReader监听器

提前设置监听器,避免错过图像回调,且必须及时关闭Image对象防止内存泄漏:

imageReader.setOnImageAvailableListener({ reader ->
    val image = reader.acquireLatestImage() ?: return@setOnImageAvailableListener
    // 这里处理图像数据,比如转Bitmap、保存文件等
    // 处理完成后必须关闭Image
    image.close()
}, Handler(Looper.getMainLooper()))

4. 模拟器适配注意事项

Pixel 3a API31模拟器的Camera2支持有限,需额外注意:

  • 确保模拟器相机设置为「虚拟场景」或已连接物理相机
  • 避免使用过高分辨率,优先选择模拟器支持的中等尺寸

关键逻辑澄清

  • 会话是输出通道集合:所有要接收相机数据的Surface必须先加入CaptureSession,否则无法在请求中使用
  • 请求指定输出目标:只有在CaptureRequest中添加已纳入会话的Surface,相机才会向该Surface输出数据
  • 两者必须严格匹配,否则要么监听器无回调,要么触发参数无效崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:06:27