Как изменить ориентацию видео AVCaptureMovieFileOutput во время сеанса работы?

#ios #iphone #video #avfoundation

#iOS #iPhone #Видео #avfoundation

Вопрос:

Я создал код, который фиксирует видеовход устройства, и пока он работает нормально. Вот что я установил

 // add preview layer
_previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
_previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.videoView.layer addSublayer:_previewLayer];

// add movie output
_movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
[_session addOutput:_movieFileOutput];
AVCaptureConnection *movieFileOutputConnection = [_movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
movieFileOutputConnection.videoOrientation = [self videoOrientationFromCurrentDeviceOrientation];

// start session
[_session startRunning];
  

где:

 - (AVCaptureVideoOrientation) videoOrientationFromCurrentDeviceOrientation {
    switch ([[UIApplication sharedApplication] statusBarOrientation]) {
        case UIInterfaceOrientationPortrait: {
            return AVCaptureVideoOrientationPortrait;
        }
        case UIInterfaceOrientationLandscapeLeft: {
            return AVCaptureVideoOrientationLandscapeLeft;
        }
        case UIInterfaceOrientationLandscapeRight: {
            return AVCaptureVideoOrientationLandscapeRight;
        }
        case UIInterfaceOrientationPortraitUpsideDown: {
            return AVCaptureVideoOrientationPortraitUpsideDown;
        }
        case UIInterfaceOrientationUnknown: {
            return 0;
        }
    }
}
  

Теперь, когда меняется ориентация интерфейса, я хочу, чтобы мой вывод также изменился, поэтому у меня есть это:

 - (void) updatePreviewLayer {
    _previewLayer.frame = CGRectMake(0, 0, self.videoView.frame.size.width, self.videoView.frame.size.height);
    _previewLayer.connection.videoOrientation = [self videoOrientationFromCurrentDeviceOrientation];
    [_session beginConfiguration];
    AVCaptureConnection *movieFileOutpurConnection = [_movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    movieFileOutpurConnection.videoOrientation = [self videoOrientationFromCurrentDeviceOrientation];
    [_session commitConfiguration];
}
  

Но, увы, это не работает. Кажется, как только я впервые установил ориентацию видео при выводе фильма, оно остается таким, как есть, его нельзя изменить позже. Итак, если я начну снимать в альбомном режиме, а затем переключусь на портретный, видео будет нормально для альбомного режима, но портретный режим будет повернут. То же самое, если я начну в портретном режиме, то пейзаж будет повернут.

Есть ли какой-нибудь способ сделать это правильно?

Ответ №1:

Попробуйте добавить это перед началом сеанса:

 [_movieFileOutput setRecordsVideoOrientationAndMirroringChanges:YES asMetadataTrackForConnection:movieFileOutputConnection];
  

Документация по заголовочному файлу для этого метода звучит очень похоже на то, что вы ищете:

Определяет, будет ли на выходе видеофайла создаваться временная дорожка метаданных, которая записывает сэмплы, отражающие изменения, внесенные в видеоориентацию данного соединения и свойства videoMirrored во время записи.

Там есть более интересная информация, я бы все прочитал.

Однако этот метод фактически не поворачивает ваши кадры, он использует временные метаданные для указания проигрывателям делать это во время воспроизведения, поэтому возможно, что не все проигрыватели будут поддерживать эту функцию. Если это нарушает условия сделки, то вы можете отказаться AVCaptureMovieFileOutput в пользу комбинации более низкого уровня AVCaptureVideoDataOutput AVAssetWriter , где ваши videoOrientation изменения фактически поворачивают кадры, в результате чего файлы будут правильно воспроизводиться в любом проигрывателе:

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

ps. Я не думаю, что вам нужна beginConfiguration / commitConfiguration pair, если вы меняете только одно свойство, поскольку оно предназначено для пакетной передачи нескольких изменений в одно атомарное обновление.

Ответ №2:

Вы пробовали приостановить сеанс перед изменением конфигурации?