如何结合AVCaptureVideoPreviewLayer使用PiP?启动遇连接错误求助
解决AVCaptureVideoPreviewLayer结合PiP时的4099错误及视图消失问题
核心问题分析
你遇到的NSCocoaErrorDomain Code=4099错误,本质是PiP相关对象被过早释放导致与系统PiP服务(com.apple.pegasus)的连接失效;视图消失则是因为视图层级未正确配置、约束缺失。
修复步骤及代码示例
1. 持有PiP相关对象(关键)
将AVPictureInPictureVideoCallViewController和AVPictureInPictureController声明为类的实例属性,避免方法执行完后被ARC自动释放:
class YourViewController: UIViewController { // 持有PiP控制器和通话视图控制器 private var pipController: AVPictureInPictureController? private var pipVideoCallVC: AVPictureInPictureVideoCallViewController? // 你的视频预览视图和捕获会话 private let videoView = UIView() private var captureSession: AVPictureInPictureController? // ... 其他业务代码 }
2. 正确配置PiP视图层级与约束
确保视频预览视图从原父视图移除,并在PiP控制器视图中添加完整约束:
@available(iOS 15.0, *) private func startPictureInPicture() { // 先验证捕获会话是否已启动 guard let captureSession = captureSession, captureSession.isRunning else { print("捕获会话未启动") return } // 移除视频预览视图的原父视图绑定 videoView.removeFromSuperview() // 创建并配置PiP通话视图控制器 let pipVC = AVPictureInPictureVideoCallViewController() pipVC.preferredContentSize = CGSize(width: 160, height: 160) // 添加视频预览视图并设置约束 videoView.translatesAutoresizingMaskIntoConstraints = false pipVC.view.addSubview(videoView) NSLayoutConstraint.activate([ videoView.topAnchor.constraint(equalTo: pipVC.view.topAnchor), videoView.leadingAnchor.constraint(equalTo: pipVC.view.leadingAnchor), videoView.trailingAnchor.constraint(equalTo: pipVC.view.trailingAnchor), videoView.bottomAnchor.constraint(equalTo: pipVC.view.bottomAnchor) ]) self.pipVideoCallVC = pipVC // 创建PiP内容源 let contentSource = AVPictureInPictureController.ContentSource( activeVideoCallSourceView: videoView, contentViewController: pipVC ) // 初始化并配置PiP控制器 guard let pipController = try? AVPictureInPictureController(contentSource: contentSource) else { print("创建PiP控制器失败") return } pipController.canStartPictureInPictureAutomaticallyFromInline = true pipController.delegate = self // 可选:设置代理监听PiP状态 self.pipController = pipController // 启动PiP pipController.startPictureInPicture() }
3. 验证AVCapturePreviewLayer配置
确保预览层正确添加到视频视图,且跟随视图尺寸变化:
private func setupPreviewLayer() { guard let captureSession = captureSession else { return } let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.videoGravity = .resizeAspectFill previewLayer.frame = videoView.bounds videoView.layer.addSublayer(previewLayer) // 监听视图尺寸变化,更新预览层 videoView.addObserver(self, forKeyPath: "bounds", options: .new, context: nil) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "bounds", let previewLayer = videoView.layer.sublayers?.first as? AVCaptureVideoPreviewLayer { previewLayer.frame = videoView.bounds } }
4. 检查Info.plist配置
确保添加必要权限:
NSCameraUsageDescription:相机权限描述(必填)UIBackgroundModes:添加voip或audio(后台运行PiP需要)NSMicrophoneUsageDescription:若使用音频则添加
可选:监听PiP状态排查问题
实现AVPictureInPictureControllerDelegate,可以更直观地排查PiP启动及运行状态:
extension YourViewController: AVPictureInPictureControllerDelegate { func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { print("PiP启动成功") } func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) { print("PiP启动失败:\(error.localizedDescription)") } }
内容的提问来源于stack exchange,提问作者Matheus Weber
相关产品推荐
相关产品推荐

