Search code examples
iosswiftipadios-camera

How to rotate a AVCaptureVideoPreviewLayer by 90 degrees to correct it in iOS11?


I have an AVCaptureVideoPreviewLayer which is set to capture the live preview of a session using the front camera feed. However, the output is rotated by 90 degrees, and I am trying to get the layer to be aligned to the rest of my app, which is in Landscape orientation. Is there a way to rotate it by 90 degrees in order to correct it?

Here is my code so far:

override func viewDidLoad() {
    super.viewDidLoad()

    let captureSession = AVCaptureSession()

    guard let captureDevice = getDevice(position: .front) else { return }
    guard let input = try? AVCaptureDeviceInput(device: captureDevice) else { return }
    captureSession.addInput(input)

    captureSession.startRunning()

    let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    view.layer.addSublayer(previewLayer)
    previewLayer.frame = view.frame
    previewLayer.videoGravity = .resizeAspectFill
    previewLayer.connection?.automaticallyAdjustsVideoMirroring = false
    previewLayer.connection?.isVideoMirrored = false
}

func getDevice(position: AVCaptureDevice.Position) -> AVCaptureDevice? {
    let devices = AVCaptureDevice.devices() as NSArray;
    for de in devices {
        let deviceConverted = de as! AVCaptureDevice
        if(deviceConverted.position == position){
            return deviceConverted
        }
    }
    return nil
}

Solution

  • Can you add previewLayer to another UIView, and try rotating like so:

    private var captureView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.captureView = UIView(frame: self.view.bounds)
        self.captureView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        self.view.addSubview(captureView)
    
        // ...
        captureView.layer.addSublayer(previewLayer)
        // ...
    
        self.rotateView(animated: false)
    }
    
    // Rotating captureView based on device orientation
    func rotateView(animated: Bool) {
        var transform: CGAffineTransform?
        switch UIDevice.current.orientation {
        case .portraitUpsideDown:
            transform = CGAffineTransform(rotationAngle: CGFloat.pi)
        case .landscapeLeft:
            transform = CGAffineTransform(rotationAngle: CGFloat.pi / 2)
        case .landscapeRight:
            transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)
        default:
            break
        }
    
        guard animated else {
            self.captureView.transform(transform)
            return
        }
    
        UIView.animate(withDuration: 0.5, animations: {[weak self] in
            self?.captureView.transform(transform)
        })
    }