Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVCaptureVideoPreviewLayer wrong orientation when UI rotation is disabled

I have a AVCaptureVideoPreviewLayer instance added to a view controller view hierarchy.

- (void) loadView {
   ...

   self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:nil];
   self.previewLayer.frame = self.view.bounds;
   self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

   [self.view.layer addSublayer: _previewLayer];

   // adding other UI elements
   ...
}

...

- (void) _setupPreviewLayerWithSession: (AVCaptureSession*) captureSession
{
   self.previewLayer.session = self.captureManager.captureSession;
   self.previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}

The layer frame is updated in -viewDidLayoutSubviews method. View controller orientation is locked to UIInterfaceOrientationMaskLandscapeRight.

The issue is as following:

  1. the device is held in landscape orientation
  2. the view controller is presented modally - video layer displays correctly. Correct orientation
  3. the device is then locked and while it's locked the device is rotated to portrait orientation.
  4. the device is then unlocked while still being in portrait orientation and for several seconds the video layer is displayed rotated 90 degrees. However, the frame for the video layer is correct. All other UI elements display correctly. After several seconds the layer snaps to correct orientation. Please find the bounds for the layer and UI elements below Incorrect orientation

I've tried updating the video layer orientation as following (with no results):

  • subscribing to AVCaptureSessionDidStartRunningNotification and UIApplicationDidBecomeActiveNotification notifications
  • calling the update when -viewWillTransitionToSize:withTransitionCoordinator: method is called
  • on -viewWillAppear:

The issue doesn't seem to be connected to video layer orientation itself, but more to view hierarchy layout.

UPDATE:

As suggested, I also tried updating the video layer orientation on device orientation change which didn't help.

I also noticed that the issue mostly happens after the application is launched and the screen is presented for the first time. On subsequent screen presentations during the same session, the reproduce rate for the issue is really low (something like 1/20).

like image 307
NikGreen Avatar asked Apr 27 '17 13:04

NikGreen


1 Answers

Try this code:

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(orientationChanged:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];
-(void)orientationChanged:(NSNotification *)notif {

    [_videoPreviewLayer setFrame:_viewPreview.layer.bounds];
    if (_videoPreviewLayer.connection.supportsVideoOrientation) {
        _videoPreviewLayer.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;
}
like image 54
Sargis Avatar answered Nov 07 '22 22:11

Sargis