Why AVCaptureSession output a wrong orientation?

Viewed 60154

So, I followed Apple's instructions to capture video session using AVCaptureSession: http://developer.apple.com/iphone/library/qa/qa2010/qa1702.html. One problem I'm facing is that even though the orientation of the camera / iPhone device is vertical (and the AVCaptureVideoPreviewLayer shows a vertical camera stream), the output image seems to be in the landscape mode. I checked the width and height of imageBuffer inside imageFromSampleBuffer: of the sample code, and I got 640px and 480px respectively. Does anyone know why this's the case?

Thanks!

11 Answers

First of all, in the configuration of your video output, put these lines:

guard let connection = videoOutput.connection(withMediaType: 
AVFoundation.AVMediaTypeVideo) else { return }
guard connection.isVideoOrientationSupported else { return }
guard connection.isVideoMirroringSupported else { return }
connection.videoOrientation = .portrait
connection.isVideoMirrored = position == .front

Then, configure your Target to support just Portait, by unchecking Landscape modes in General configuration.

(Source)

// #1
AVCaptureVideoOrientation newOrientation = AVCaptureVideoOrientationLandscapeRight;
if (@available(iOS 13.0, *)) {
    // #2
    for (AVCaptureConnection *connection in [captureSession connections]) {
        if ([connection isVideoOrientationSupported]) {
            connection.videoOrientation = newOrientation;
            break;
        }
    } // #3
} else if ([previewLayer.connection isVideoOrientationSupported]) {
    previewLayer.connection.videoOrientation = newOrientation;
}

Once that you can correctly use your AVCaptureSession, you can set a video orientation. Here a detailed description of the code above. Remember, this code has to be executed after the [captureSession startRunning] execution:

  1. Choose the orientation that you prefer
  2. For ios version >= 13.0 you have to retrieve the active connection from the captureSession. Remember: only video connection supports videoOrientation
  3. For ios version < 13.0 you can use the connection from the previewLayer

If your viewController doesn't have a fixed orientation you can set a new videoOrientation to your connection once the device orientation changes.

You can try this:

private func startLiveVideo() {

    let captureSession = AVCaptureSession()
    captureSession.sessionPreset = .photo
    let captureDevice = AVCaptureDevice.default(for: .video)

    let input = try! AVCaptureDeviceInput(device: captureDevice!)
    let output = AVCaptureVideoDataOutput()
    captureSession.addInput(input)
    captureSession.addOutput(output)

    output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue"))
    output.connection(with: .video)?.videoOrientation = .portrait

    let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.frame = view.bounds
    view.layer.addSublayer(previewLayer)

    captureSession.startRunning()
}
Related