iOS开发中AVCaptureVideoDataOutput的captureOutput代理方法未被调用问题求助
先直接回答你的核心疑问:不需要必须设置预览层才能捕获视频输出,很多无预览的相机采集场景(比如后台帧处理、仅做图像分析)都能正常触发captureOutput回调,所以你的问题肯定出在其他配置环节。结合你的代码,我整理了几个关键排查点:
1. 最关键的遗漏:没有启动AVCaptureSession
你的startStreamingCamera方法里完成了输入输出的添加、代理设置,但从未调用captureSession.startRunning()!AVCaptureSession必须启动才会开始采集数据,这是最常见的低级错误。
修改你的代码,在配置完所有输入输出后启动会话:
do { let captureDeviceInput = try AVCaptureDeviceInput(device: inputCam!) let captureDeviceOutput = AVCaptureVideoDataOutput() guard self.captureSession.canAddInput(captureDeviceInput), self.captureSession.canAddOutput(captureDeviceOutput) else { return } self.captureSession.addInput(captureDeviceInput) self.captureSession.addOutput(captureDeviceOutput) captureDeviceOutput.setSampleBufferDelegate(self, queue: .global()) // 新增:启动采集会话 self.captureSession.startRunning() } catch { print("配置相机输入输出失败:\(error)") // 建议添加错误日志,方便排查 }
2. 检查CameraPlugin实例的生命周期
看你的调用代码:
guard let videoCaptureDevice = AVCaptureDevice.default(for: AVMediaType.video) else { return } let camPlugin = CameraPlugin() camPlugin.startStreamingCamera(cameraId: nil, camera: videoCaptureDevice, listener: self)
这里的camPlugin是局部变量,如果这段代码是在某个方法(比如viewDidLoad)里执行的,方法执行完毕后camPlugin会被ARC销毁,而AVCaptureOutput的代理是弱引用,实例被销毁后自然不会触发回调。
解决方法:把camPlugin保存为当前类的属性,比如:
class YourViewController: UIViewController, VideoSampleListener { private var camPlugin: CameraPlugin? // 保存为属性 override func viewDidLoad() { super.viewDidLoad() guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return } camPlugin = CameraPlugin() camPlugin?.startStreamingCamera(cameraId: nil, camera: videoCaptureDevice, listener: self) } }
3. 确保视频连接处于启用状态
有时候AVCaptureConnection会默认禁用(比如某些设备的特定格式),可以在添加输出后手动启用视频连接:
self.captureSession.addOutput(captureDeviceOutput) // 新增:启用视频连接 if let videoConnection = captureDeviceOutput.connection(with: .video) { videoConnection.isEnabled = true } captureDeviceOutput.setSampleBufferDelegate(self, queue: .global())
4. 配置合适的会话预设
你的代码没有设置captureSession.sessionPreset,默认的预设可能和设备支持的格式不兼容,导致无法输出帧数据。建议在添加输入前设置合适的预设,比如:
// 在添加输入前设置 self.captureSession.sessionPreset = .high // 或者根据需求选其他预设,比如 .medium/.hd1920x1080
5. 验证队列的有效性
你用了.global()队列作为代理队列,这本身没问题,但如果是并行队列,要注意videoSampleListener?.receivedVideoSample的线程安全性(比如更新UI必须回到主线程)。如果担心队列问题,可以改用串行队列:
let captureQueue = DispatchQueue(label: "com.yourapp.camera.capture") captureDeviceOutput.setSampleBufferDelegate(self, queue: captureQueue)
额外建议:添加错误日志
你的catch块是空的,建议打印错误信息,方便排查输入输出添加失败的情况:
catch { print("相机配置错误:\(error.localizedDescription)") }
按照以上步骤排查,应该能解决captureOutput不触发的问题。
内容的提问来源于stack exchange,提问作者Brad Priddy

