Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems automatically resizing AVCaptureVideoPreviewLayer on rotation

Tags:

ios

ios5

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.

like image 666
Tafkadasoh Avatar asked Jan 16 '23 11:01

Tafkadasoh


1 Answers

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.

like image 115
Tafkadasoh Avatar answered Feb 05 '23 09:02

Tafkadasoh