AVCaptureVideoPreviewLayer landscape orientation
First, the answer
- (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;
}
I've come across several SO posts on this matter, and couldn't find any simple explanation so I thought I'd share my own.
If you follow Apple's sample on the matter, you'll run into two potential problems when you rotate your iOS device to landscape
- Capture will appear rotated (as if you're holding the camera 90 degrees off)
- It won't span its set bounds entirely
The problem here is that 'CALayer' doesn't support autorotation hence, unlike a 'UIView' you'd add as a subview, it won't rotate when its parent 'UIView' rotates. Therefore, you have to manually update its frame every time the parent view's bounds changes (not parent view's frame since frame stays the same after rotation). This is achieved by overriding 'viewWillLayoutSubviews' in the container view controller.
Secondly, you should use 'videoOrientation' property to inform AVFoundation about the orientation so it does the preview properly.
Hope this helps.
AVCaptureVideoPreviewLayer orientation - need landscape
The default camera orientation is Landscape Left (home button one the left). You need to do two things here:
1- Change the previewLayer frame to:
self.previewLayer.frame=self.view.bounds;
You need to set the preview layer frame to the bounds of the screen so that the frame of the preview layer changes when the screen rotates (you cannot use frame of the root view because that does not change with rotation but the bounds of the root view do). In your example, you are setting the previewlayer frame to a previewView property which I do not see.
2- You need to rotate the preview layer connection with the rotation of the device. Add this code in viewDidAppear:
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
//Get Preview Layer connection
AVCaptureConnection *previewLayerConnection=self.previewLayer.connection;
if ([previewLayerConnection isVideoOrientationSupported])
[previewLayerConnection setVideoOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
}
Hope this solves it.
Full Disclosure: This is a simplified version since you do not care if Landscape right or Landscape left.
Allow AVCaptureVideoPreviewLayer preview rotate with device
I fixed it - I just had to add this-
if UIDevice.current.orientation == .portrait {
previewLayer.connection?.videoOrientation = .portrait
} else if UIDevice.current.orientation == .portraitUpsideDown {
previewLayer.connection?.videoOrientation = .portraitUpsideDown
} else if UIDevice.current.orientation == .landscapeLeft {
previewLayer.connection?.videoOrientation = .landscapeRight
} else if UIDevice.current.orientation == .landscapeRight {
previewLayer.connection?.videoOrientation = .landscapeLeft
}
-which gets called when the device is rotated. I also call it on startup after I have initialized the AVCaptureVideoPreviewLayer
.
Problems with AVCaptureSession in landscape mode on iPad
Solved it, now it is working in all orientations. We need to set this
_previewLayer.connection.videoOrientation = [self videoOrientationFromCurrentDeviceOrientation];
where the method is:
- (AVCaptureVideoOrientation) videoOrientationFromCurrentDeviceOrientation {
switch (self.interfaceOrientation) {
case UIInterfaceOrientationPortrait: {
return AVCaptureVideoOrientationPortrait;
}
case UIInterfaceOrientationLandscapeLeft: {
return AVCaptureVideoOrientationLandscapeLeft;
}
case UIInterfaceOrientationLandscapeRight: {
return AVCaptureVideoOrientationLandscapeRight;
}
case UIInterfaceOrientationPortraitUpsideDown: {
return AVCaptureVideoOrientationPortraitUpsideDown;
}
}
}
Also on capture output we need to set:
AVCaptureConnection *output2VideoConnection = [videoOutput connectionWithMediaType:AVMediaTypeVideo];
output2VideoConnection.videoOrientation = [self videoOrientationFromCurrentDeviceOrientation];
Related Topics
Autorelease Pools and When Release Is Called Under iOS
Setneedsdisplayinrect: Causes the Whole View to Be Updated
Is It Just the iPhone Simulator That Is Restricted to Intel Only MAC'S
Core Location Not Working in iOS 8
Opening Word,Excel, and PDF Files Without Using Uiwebview on iOS
How to Port "Method_Getimplementation" and "Method_Setimplementation" to Monotouch
Exception with Insertobject:Atindex: on iOS6
Xcode 8 Gm Seed Storyboard Layout Issue
Get Average Color of Uiimage in Swift
Is There a Practical Way to Compress Nsdata
How to Make Camera Follow Sknode in Sprite Kit
Xcode: How to Change Layout of Views Between Landscape and Portrait Mode
Ios: How to Read an Audio File into a Float Buffer
Accessing the Settings App from Your App in iOS 8
The Simulator Can't Be Launched Because It Is Already in Use
How to Resize Uitableviewcell to Fit Its Content
How to Detect If the Currently Running App Was Installed from the App Store
Communicating With/Opening Containing App from Share Extension