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

如何让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 19:20:53