I've programmed a static framework, and therein I have a class called ViewfinderViewController, that set's up the camera with an AVCaptureSession. This ViewController also add's an AVCaptureVideoPreviewLayer as sublayer to its own view's layer:
// code in ViewfinderViewController.m
previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:captureSession];
previewLayer.frame = self.view.bounds;
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:previewLayer];
The ViewfinderViewController also does some video processing, and offers user's of the framework to register for some delegate methods, in case something of interest was found or was not found in one of the processed frames.
In the viewDidLoad method of my real application, I create an instance of ViewfinderViewController, set it's frame and add it's view as a subview:
// code in the app's view controller viewDidLoad method
ViewfinderViewController *vfVC = [[ViewfinderViewController alloc] init];
vfVC.view.frame = self.view.bounds;
[self.view addSubview:vfVC.view];
This works fine, as long as I disregard rotation (which I did until now). My main problem is, that ViewfinderViewController.view resizes its frame, but the AVCaptureVideoPreviewLayer does not. I'm a bit puzzeled: Shouldn't the previewLayer also resize automatically, as the view corresponding to it's superLayer is resized correctly?
Any ideas? I'll gladly provide more information, but to keep the question shorter I won't go any further for now. Thanks.
Finally, I've found the following to be working best for my app. In my application, I add the ViewFinderViewController now as child view controller:
- (void)viewWillAppear:(BOOL)animated;
{
if ([self.childViewControllers containsObject:self.viewfinderViewController] == NO) {
[self addChildViewController:self.viewfinderViewController];
self.viewfinderViewController.view.frame = self.view.bounds;
[self.view addSubview:self.viewfinderViewController.view];
[self.viewfinderViewController didMoveToParentViewController:self];
}
}
This way, the willAnimateRotationToInterfaceOrientation: method will be called automatically, which I previously forwarded from the view controller that added the viewfinder's view as it's subview.
Furthermore, I update the previewLayer size in this method of ViewfinderViewController:
- (void)viewWillLayoutSubviews;
{
self.previewLayer.frame = self.view.bounds;
}
I handle rotation of the previewLayer by implementing these two methods:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[CATransaction begin];
[CATransaction setAnimationDuration:duration];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self updatePreviewLayerForOrientation:toInterfaceOrientation];
[CATransaction commit];
}
- (void)updatePreviewLayerForOrientation:(UIInterfaceOrientation)interfaceOrientation;
{
// correct position of previewLayer
CGSize newSize = self.view.bounds.size;
self.previewLayer.position = CGPointMake(0.5 * newSize.width, 0.5 * newSize.height);
// rotate the previewLayer, in order to have camera picture right
switch (interfaceOrientation) {
case UIInterfaceOrientationPortrait:
[self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(0)];
break;
case UIInterfaceOrientationLandscapeLeft:
[self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI/2)];
break;
case UIInterfaceOrientationLandscapeRight:
[self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(-M_PI/2)];
break;
case UIDeviceOrientationPortraitUpsideDown:
[self.previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI)];
break;
default:
break;
}
}
I hope this helps everybody who is adding AVCaptureVideoPreviewLayer as a sublayer and has problems with resizing and orientation when it comes to interface rotation.
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