KMM集成MLKit扫码时iOS相机周期性卡顿问题
解决KMM iOS端MLKit条码扫描周期性卡顿问题
问题分析
在KMM的iOS模块中集成MLKit条码扫描时,创建VisionImage后出现周期性卡顿(15帧流畅→卡顿10秒→循环),核心原因是MLKit对CMSampleBuffer的处理逻辑与AVCaptureSession的内存/线程调度冲突,手动释放SampleBuffer会引发过度释放崩溃,复制SampleBuffer无法解决本质问题。
有效解决方案
1. 确保处理队列是独立串行队列
AVCaptureVideoDataOutput的处理队列必须是独立的串行队列,避免和主线程或其他队列竞争资源。如果你的processingQueue未正确初始化,直接创建串行队列:
@OptIn(ExperimentalForeignApi::class) private val processingQueue = dispatch_queue_create("com.your.app.camera.processing", DISPATCH_QUEUE_SERIAL)
在setupCaptureSession中使用这个队列:
videoOutput = AVCaptureVideoDataOutput().apply { setSampleBufferDelegate(this@CameraViewController, processingQueue) // 其他配置... }
2. 改用CVPixelBuffer创建VisionImage
直接传递CMSampleBuffer给MLKit可能导致内存持有延迟,改为提取CVPixelBuffer来创建VisionImage,减少不必要的资源绑定:
override fun captureOutput( output: AVCaptureOutput, didOutputSampleBuffer: CMSampleBufferRef?, fromConnection: AVCaptureConnection ) { didOutputSampleBuffer ?: return frameCounter += 1 logging("CViewC").i { "FRAME #$frameCounter" } // 提取CVPixelBuffer val pixelBuffer = CMSampleBufferGetImageBuffer(didOutputSampleBuffer) ?: return // 用CVPixelBuffer创建VisionImage val visionImage = MLKVisionImage(pixelBuffer) // 设置相机方向(根据你的设备方向调整) visionImage.imageOrientation = UIImageOrientationUp.toMLKImageOrientation() // 执行条码扫描 val scanner = MLKBarcodeScanner.barcodeScanner() scanner.processImage(visionImage) { barcodes, error -> error ?: barcodes?.firstOrNull()?.rawValue?.let { // 回到主线程回调结果 dispatch_async(dispatch_get_main_queue()) { onQRCodeDetected(it) } } } }
添加UIImageOrientation到MLKImageOrientation的扩展:
fun UIImageOrientation.toMLKImageOrientation(): MLKImageOrientation { return when (this) { UIImageOrientationUp -> MLKImageOrientationUp UIImageOrientationDown -> MLKImageOrientationDown UIImageOrientationLeft -> MLKImageOrientationLeft UIImageOrientationRight -> MLKImageOrientationRight UIImageOrientationUpMirrored -> MLKImageOrientationUpMirrored UIImageOrientationDownMirrored -> MLKImageOrientationDownMirrored UIImageOrientationLeftMirrored -> MLKImageOrientationLeftMirrored UIImageOrientationRightMirrored -> MLKImageOrientationRightMirrored } }
3. 禁止手动释放原CMSampleBuffer
AVCaptureSession会自动管理didOutputSampleBuffer的生命周期,绝对不要调用CFRelease(didOutputSampleBuffer),否则会引发CFTypeRef过度释放崩溃。
4. 优化AVCaptureSession配置
- 确认
alwaysDiscardsLateVideoFrames = true,避免积压未处理的帧导致内存暴涨 - 可尝试降低分辨率(比如
AVCaptureSessionPreset640x480),减少MLKit的处理压力 - 确保视频格式
kCVPixelFormatType_32BGRA是MLKit优化支持的格式
验证步骤
- 运行应用后观察帧计数日志,确认是否持续流畅输出
- 检查Xcode的Memory Graph Debugger,查看内存是否稳定无暴涨
- 测试扫码功能是否正常,无卡顿或崩溃
内容的提问来源于stack exchange,提问作者BvitCzty
相关产品推荐
相关产品推荐

