如何让AVCaptureSession支持全方向旋转,适配iPhone屏幕旋转
实现相机视图随设备旋转的解决方案
1. 移除固定方向设置,初始匹配设备当前方向
修改你的setupCaptureSession方法,不再硬编码固定方向,而是根据设备当前状态动态设置初始视频方向:
func setupCaptureSession(camera: AVCaptureDevice.Position = .front) { guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: camera) else { fatalError("Error getting AVCaptureDevice.") } guard let input = try? AVCaptureDeviceInput(device: device) else { fatalError("Error getting AVCaptureDeviceInput") } DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } self.session = AVCaptureSession() self.session?.sessionPreset = .hd1280x720 self.session?.addInput(input) let output = AVCaptureVideoDataOutput() output.alwaysDiscardsLateVideoFrames = true output.setSampleBufferDelegate(self, queue: .main) self.session?.addOutput(output) // 初始时匹配设备当前方向 if let connection = output.connections.first, connection.isVideoOrientationSupported { connection.videoOrientation = self.currentVideoOrientation() } self.session?.startRunning() } } // 辅助方法:将设备方向转换为AVCaptureVideoOrientation private func currentVideoOrientation() -> AVCaptureVideoOrientation { let deviceOrientation = UIDevice.current.orientation switch deviceOrientation { case .portrait: return .portrait case .portraitUpsideDown: return .portraitUpsideDown case .landscapeLeft: return .landscapeRight case .landscapeRight: return .landscapeLeft default: return .portrait } }
2. 监听设备旋转,动态更新视频方向
推荐使用视图控制器的旋转回调方法,在设备旋转时同步更新相机方向:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) // 转场动画完成后更新,避免画面卡顿 coordinator.animate(alongsideTransition: nil) { [weak self] _ in self?.updateVideoOrientation() } } private func updateVideoOrientation() { guard let session = self.session, let output = session.outputs.first as? AVCaptureVideoDataOutput else { return } // 在session队列中修改配置,保证线程安全 DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } session.beginConfiguration() if let connection = output.connections.first, connection.isVideoOrientationSupported { connection.videoOrientation = self.currentVideoOrientation() } session.commitConfiguration() } }
额外注意点
- 线程安全:修改AVCaptureSession相关配置必须用
beginConfiguration()和commitConfiguration()包裹,或者在session的串行队列中执行,避免线程冲突。 - 前置摄像头镜像:如果使用前置摄像头,旋转后可能需要开启镜像,可在设置方向时添加
connection.isVideoMirrored = camera == .front。 - 方向映射:设备的横屏方向和相机的视频方向是反向的,比如
UIDeviceOrientation.landscapeLeft对应AVCaptureVideoOrientation.landscapeRight,代码中已经做了对应处理。
内容的提问来源于stack exchange,提问作者Marcus FK
相关产品推荐
相关产品推荐

