AVCaptureVideoPreviewLayer横向定位

Ege*_*nar 13 landscape avfoundation calayer ios

如何让"AVCaptureVideoPreviewLayer"在横向显示时正确显示?它在纵向上工作正常但不旋转,并在父视图控制器处于横向时显示旋转的相机捕获.

Ege*_*nar 30

首先,答案

- (void)viewWillLayoutSubviews {
  _captureVideoPreviewLayer.frame = self.view.bounds;
  if (_captureVideoPreviewLayer.connection.supportsVideoOrientation) {
    _captureVideoPreviewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:[UIApplication sharedApplication].statusBarOrientation];
  }
}

- (AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation:(UIInterfaceOrientation)orientation {
  switch (orientation) {
    case UIInterfaceOrientationPortrait:
        return AVCaptureVideoOrientationPortrait;
    case UIInterfaceOrientationPortraitUpsideDown:
        return AVCaptureVideoOrientationPortraitUpsideDown;
    case UIInterfaceOrientationLandscapeLeft:
        return AVCaptureVideoOrientationLandscapeLeft;
    case UIInterfaceOrientationLandscapeRight:
        return AVCaptureVideoOrientationLandscapeRight;
    default:
        break;
  }
  NSLog(@"Warning - Didn't recognise interface orientation (%d)",orientation);
  return AVCaptureVideoOrientationPortrait;
}
Run Code Online (Sandbox Code Playgroud)

我在这个问题上遇到了几个SO帖子,找不到任何简单的解释,所以我想我会分享自己的.

如果你在这个问题上关注Apple的样本,当你将iOS设备旋转到横向时,你会遇到两个潜在的问题

  1. 捕捉将显示为旋转(就像您将相机保持90度关闭一样)
  2. 它不会完全跨越其设定范围

这里的问题是'CALayer'不支持自动旋转,因此,与你添加为子视图的'UIView'不同,当它的父'UIView'旋转时它不会旋转.因此,每次父视图的边界发生更改时,您必须手动更新其框架(而不是父视图的框架,因为框架在旋转后保持不变).这是通过覆盖容器视图控制器中的"viewWillLayoutSubviews"来实现的.

其次,您应该使用'videoOrientation'属性来告知AVFoundation方向,以便正确进行预览.

希望这可以帮助.


小智 9

斯威夫特 5(iOS 13.0+):

    func updateVideoOrientation() {
        guard let videoPreviewLayer = self.videoPreviewLayer else {
            return
        }
        guard videoPreviewLayer.connection!.isVideoOrientationSupported else {
            print("isVideoOrientationSupported is false")
            return
        }
        let statusBarOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
        let videoOrientation: AVCaptureVideoOrientation = statusBarOrientation?.videoOrientation ?? .portrait
        videoPreviewLayer.frame = view.layer.bounds
        videoPreviewLayer.connection?.videoOrientation = videoOrientation
        videoPreviewLayer.removeAllAnimations()
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        coordinator.animate(alongsideTransition: nil, completion: { [weak self] (context) in
            DispatchQueue.main.async(execute: {
                self?.updateVideoOrientation()
            })
        })
    }

extension UIInterfaceOrientation {
    var videoOrientation: AVCaptureVideoOrientation? {
        switch self {
        case .portraitUpsideDown: return .portraitUpsideDown
        case .landscapeRight: return .landscapeRight
        case .landscapeLeft: return .landscapeLeft
        case .portrait: return .portrait
        default: return nil
        }
    }
}

Run Code Online (Sandbox Code Playgroud)


neo*_*eye 7

Swift3

func updateVideoOrientation() {
    guard let previewLayer = self.previewLayer else {
        return
    }
    guard previewLayer.connection.isVideoOrientationSupported else {
        print("isVideoOrientationSupported is false")
        return
    }

    let statusBarOrientation = UIApplication.shared.statusBarOrientation
    let videoOrientation: AVCaptureVideoOrientation = statusBarOrientation.videoOrientation ?? .portrait

    if previewLayer.connection.videoOrientation == videoOrientation {
        print("no change to videoOrientation")
        return
    }

    previewLayer.frame = cameraView.bounds
    previewLayer.connection.videoOrientation = videoOrientation
    previewLayer.removeAllAnimations()
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate(alongsideTransition: nil, completion: { [weak self] (context) in
        DispatchQueue.main.async(execute: {
            self?.updateVideoOrientation()
        })
    })
}
Run Code Online (Sandbox Code Playgroud)
extension UIInterfaceOrientation {
    var videoOrientation: AVCaptureVideoOrientation? {
        switch self {
        case .portraitUpsideDown: return .portraitUpsideDown
        case .landscapeRight: return .landscapeRight
        case .landscapeLeft: return .landscapeLeft
        case .portrait: return .portrait
        default: return nil
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Jor*_*llo 6

override func viewWillLayoutSubviews() {
    self.previewLayer.frame = self.view.bounds
    if previewLayer.connection.isVideoOrientationSupported {
        self.previewLayer.connection.videoOrientation = self.interfaceOrientation(toVideoOrientation: UIApplication.shared.statusBarOrientation)
    }
}

func interfaceOrientation(toVideoOrientation orientation: UIInterfaceOrientation) -> AVCaptureVideoOrientation {
    switch orientation {
    case .portrait:
        return .portrait
    case .portraitUpsideDown:
        return .portraitUpsideDown
    case .landscapeLeft:
        return .landscapeLeft
    case .landscapeRight:
        return .landscapeRight
    default:
        break
    }

    print("Warning - Didn't recognise interface orientation (\(orientation))")
    return .portrait
}
Run Code Online (Sandbox Code Playgroud)

//SWIFT 3 转换