Быстрый поворот устройства iOS на 180 градусов приводит к перевернутому просмотру камеры.


Я реализовал код ниже, чтобы изменить ориентацию AVCaptureVideoSession на основе UIInterfaceOrientation:

- (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 (%ld)",(long)orientation);
    return AVCaptureVideoOrientationPortrait;
}
Этот код работает почти идеально. Однако одна из проблем, которая возникает, заключается в том, что если вы быстро повернете устройство iOS на 180 градусов, камера будет показана вверх ногами.

Вот как выглядит вид камеры перед вращением:

Введите описание изображения здесь

И вот как это выглядит после вращения:

Введите описание изображения здесь

Кроме того, вот мой реализация viewDidLayoutSubviews:

- (void)viewDidLayoutSubviews {

    [super viewDidLayoutSubviews];

    previewLayer.frame = self.view.bounds;

    self.view.translatesAutoresizingMaskIntoConstraints = NO;
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:previewLayer];

    if (previewLayer.connection.supportsVideoOrientation) {
        previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation:[UIApplication sharedApplication].statusBarOrientation];
    }
}

Есть ли у кого-нибудь идея о том, почему вид камеры будет вверх ногами, когда происходит это вращение на 180 градусов?

2 11

2 ответа:

У меня была та же проблема до этого, что решило мою проблему.

Я объявил глобальную переменную:

@interface YourViewController ()
{
    ...
    UIDevice *iOSDevice;
}

..

@end

Под implementation (.m file) я объявил nsnotification observer под -viewWillAppear как:

@implementation YourViewController

-(void)viewWillAppear:(BOOL)animated
{
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

    [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification  object:[UIDevice currentDevice]];

}

-(void)viewWillDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}

- (void)orientationChanged:(NSNotification *)notification
{
    iOSDevice = notification.object;

    previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation];

    //or

    [self setAutoVideoConnectionOrientation:YES];

}

Я сделал функцию, которая возвращает ориентацию скопированного текущего устройства, как:

Возьмите бабло у моего метода -interfaceOrientationToVideoOrientation, он преобразует iOSDevice.orientation в AVCaptureVideoOrientation то же самое, что у вас есть..


(в моем случае мне нужна была эта функция ниже, но взгляните на нее может быть вам полезно по какой-то причине)

- (AVCaptureVideoOrientation)interfaceOrientationToVideoOrientation
{
    switch (iOSDevice.orientation) {

        case UIInterfaceOrientationPortraitUpsideDown:

            return AVCaptureVideoOrientationPortraitUpsideDown;

        case UIInterfaceOrientationLandscapeLeft:

            return AVCaptureVideoOrientationLandscapeLeft;

        case UIInterfaceOrientationLandscapeRight:

            return AVCaptureVideoOrientationLandscapeRight;

        default:
        case UIDeviceOrientationPortrait:
            return AVCaptureVideoOrientationPortrait;
    }
}

- (AVCaptureConnection *)setAutoVideoConnectionOrientation:(BOOL)status
{
    AVCaptureConnection *videoConnection = nil;

    //This is for me
    //for (AVCaptureConnection *connection in stillImageOutput.connections) {

    //This might be for you
    for (AVCaptureConnection *connection in previewLayer.connection) {

        for (AVCaptureInputPort *port in [connection inputPorts])
        {
            if ([[port mediaType] isEqual:AVMediaTypeVideo])
            {
                videoConnection = connection;

                if (status == YES)
                {
                    [videoConnection setVideoOrientation:[self interfaceOrientationToVideoOrientation]];
                }
                else
                {
                    [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
                }
            }
            if (videoConnection)
            {
                break;
            }
        }
    }
    return videoConnection;
}

Edit

Для ориентации по умолчанию: вам нужно проверить" текущую " ориентацию.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // assuming you finish setting the `previewLayer`

    ..
    // after all of that code, when the view is ready for displaying
    // if you implemented this approach the best thing to do is:

    // set this 
    iOSDevice = [UIDevice currentDevice];

    // then call 
    previewLayer.connection.videoOrientation = [self interfaceOrientationToVideoOrientation];
    // to update the `previewLayer.connection.videoOrientation ` for default orientation        

}

Примечание:

Используя NSNotificationCenter пусть вращение устройства будет установлено первым перед запуском..

Надеюсь, что это поможет вам..

Я считаю, что это происходит, потому что viewDidLayoutSubviews не вызывается, когда вид меняется с портретной ориентации на перевернутую. Когда вы вращаетесь очень быстро, он переходит от одного к другому прямо. Если вы медленно вращаетесь, он проходит через ландшафтную ориентацию, и поэтому viewDidLayoutSubviews вызывается, а затем ваш метод.

Я советую вам использовать один из методов, которые вызываются при изменении ориентации. Я знаю, что Apple советует использовать их все меньше и меньше, потому что они хотят, чтобы представления менялись, когда размер изменения, но бывают случаи, как этот, когда вам действительно нужно знать, что ориентация изменилась.

Например, вы можете зарегистрироваться, чтобы получать такие уведомления: UIApplicationDidChangeStatusBarOrientationNotification