I'm playing around with using AVFoundation in Swift
Normally when I set up a video camera capture session I do something like the following in objective-c
[[cameraView.previewLayer connection] setVideoOrientation:(AVCaptureVideoOrientation)[self interfaceOrientation]]
In swift it seems like I have to do something like this (because of optional type)
if let connection = cameraView.previewLayer?.connection {
connection.videoOrientation = self.interfaceOrientation as AVCaptureVideoOrientation
}
however this complains with
‘AVCaptureVideoOrientation’ is not a subtype of ‘UIInterfaceOrientation’
After reading about the down-casting methodology this makes a lot of sense, but I'm struggling to find how to actually get this working.
Do I need to write a helper method that basically does a switch statement through all the available values of UIInterfaceOrientation to get this working?
extension UIDeviceOrientation {
var videoOrientation: AVCaptureVideoOrientation? {
// Unlike UIInterfaceOrientation, the UIDeviceOrientation has reversed landscape left/right. Doh!
switch self {
case .portraitUpsideDown: return .portraitUpsideDown
case .landscapeRight: return .landscapeLeft
case .landscapeLeft: return .landscapeRight
case .portrait: return .portrait
default: return nil
}
}
}
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
}
}
}
Thanks, David. I updated to Swift 3 and added UIDeviceOrientation:
extension AVCaptureVideoOrientation {
var uiInterfaceOrientation: UIInterfaceOrientation {
get {
switch self {
case .landscapeLeft: return .landscapeLeft
case .landscapeRight: return .landscapeRight
case .portrait: return .portrait
case .portraitUpsideDown: return .portraitUpsideDown
}
}
}
init(ui:UIInterfaceOrientation) {
switch ui {
case .landscapeRight: self = .landscapeRight
case .landscapeLeft: self = .landscapeLeft
case .portrait: self = .portrait
case .portraitUpsideDown: self = .portraitUpsideDown
default: self = .portrait
}
}
init?(orientation:UIDeviceOrientation) {
switch orientation {
case .landscapeRight: self = .landscapeLeft
case .landscapeLeft: self = .landscapeRight
case .portrait: self = .portrait
case .portraitUpsideDown: self = .portraitUpsideDown
default:
return nil
}
}
}
Then I use it with AVCapturePhotoOutput like this:
if let connection = imageOutput.connection(withMediaType: AVMediaTypeVideo),
connection.isVideoOrientationSupported,
let orientation = AVCaptureVideoOrientation(orientation: UIDevice.current.orientation) {
connection.videoOrientation = orientation
}
It may not be perfect for every scenario but since my interface doesn't change with orientation I skip listening for orientation changes.
It's probably better in general to change your UI so users have an idea of what orientation they're using.
As I noted in my comments, since AVCaptureVideoOrientation and UIInterfaceOrientation don't match up their cases, you can use something like:
extension AVCaptureVideoOrientation {
var uiInterfaceOrientation: UIInterfaceOrientation {
get {
switch self {
case .LandscapeLeft: return .LandscapeLeft
case .LandscapeRight: return .LandscapeRight
case .Portrait: return .Portrait
case .PortraitUpsideDown: return .PortraitUpsideDown
}
}
}
init(ui:UIInterfaceOrientation) {
switch ui {
case .LandscapeRight: self = .LandscapeRight
case .LandscapeLeft: self = .LandscapeLeft
case .Portrait: self = .Portrait
case .PortraitUpsideDown: self = .PortraitUpsideDown
default: self = .Portrait
}
}
}
then use it as:
if let connection = cameraView.previewLayer?.connection {
connection.videoOrientation = AVCaptureVideoOrientation(ui:self.interfaceOrientation)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With