Nano Hash - криптовалюты, майнинг, программирование

AVCaptureMovieFileOutput NSInvalidArgumentException нет активных/включенных соединений

Иногда я получаю исключение NSInvalidArgumentException, когда начинаю записывать видео в viewController, но только после съемки фотографий в предыдущем контроллере представления. Я попробовал пару предложений от Google и So, но все равно получаю эту ошибку при вызове startRecordingToOutputFileURL:fileURL.

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

Я думаю, что после фотографирования осталось немного хлама, но когда я инициализирую контроллер представления видеомагнитофона, я не получаю ошибок при настройке сеансов и еще чего-то. Любые идеи, что происходит или как оправиться от этого? Почему это NSInvalidArgumentException исключение? Спасибо!

Вот мой код:

dispatch_async(dispatch_get_main_queue(), ^{

            // Try to Fix bug:
            // http://stackoverflow.com/questions/5979962/error-while-recording-video-on-iphone-using-avfoundation

            [self.captureSession beginConfiguration];

            // Ensure session is running
            if ( [self.captureSession isRunning] == NO ) {
                NSLog(@"Capture session is NOT running... Starting it now!");
                [self.captureSession startRunning];
            }
            else {
                NSLog(@"Capture session is ALREADY running...");
            }

            NSLog(@"File URL is: %@",fileURL);
            NSLog(@"FileOutput is: %@",self.fileOutput);

            [self.fileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];

            // Try to Fix bug:
            // http://stackoverflow.com/questions/5979962/error-while-recording-video-on-iphone-using-avfoundation
            [self.captureSession commitConfiguration];

        });

Вот трассировка ошибки:

2014-05-18 16:01:38.818 app[1699:60b] *** Start recording
2014-05-18 16:01:38.820 app[1699:60b] Capture session is ALREADY running...
2014-05-18 16:01:38.827 app[1699:60b] Capture session is ALREADY running...
2014-05-18 16:01:38.828 app[1699:60b] File URL is: file:////var/mobile/Applications/73FFC590-05A8-4D74-82D9-EBA122B00A20/Documents/2014-05-18-16-01-38-0.mp4
2014-05-18 16:01:38.828 app[1699:60b] FileOutput is: <AVCaptureMovieFileOutput: 0x16513b10>
2014-05-18 16:01:38.829 app[1699:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] - no active/enabled connections.'
*** First throw call stack:
(0x2fe5ff0b 0x3a5f6ce7 0x2ed5751d 0xfb4b5 0x3aadfd53 0x3aadfd3f 0x3aae26c3 0x2fe2a681 0x2fe28f4d 0x2fd93769 0x2fd9354b 0x34d006d3 0x326f2891 0xe40c9 0x3aaf4ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException

Вот как инициализируется CaptureSession (из проекта OpenSource здесь: https://github.com/shu223/SlowMotionVideoRecorder):

- (id)initWithPreviewView:(UIView *)previewView {

    self = [super init];

    if (self) {

        NSError *error;

        self.captureSession = [[AVCaptureSession alloc] init];
        self.captureSession.sessionPreset = AVCaptureSessionPresetInputPriority;

        AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        AVCaptureDeviceInput *videoIn = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];

        if (error) {
            NSLog(@"Video input creation failed");
            return nil;
        }

        if (![self.captureSession canAddInput:videoIn]) {
            NSLog(@"Video input add-to-session failed");
            return nil;
        }
        [self.captureSession addInput:videoIn];


        // save the default format
        self.defaultFormat = videoDevice.activeFormat;
        defaultVideoMaxFrameDuration = videoDevice.activeVideoMaxFrameDuration;


        AVCaptureDevice *audioDevice= [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
        AVCaptureDeviceInput *audioIn = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
        [self.captureSession addInput:audioIn];

        self.fileOutput = [[AVCaptureMovieFileOutput alloc] init];
        [self.captureSession addOutput:self.fileOutput];


        self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
        self.previewLayer.frame = previewView.bounds;
        self.previewLayer.contentsGravity = kCAGravityResizeAspectFill;
        self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        [previewView.layer insertSublayer:self.previewLayer atIndex:0];

        [self.captureSession startRunning];
    }
    return self;
}

Мой код использует этот код инициализации, подобный этому, в viewDidLoad:

self.captureManager = [[AVCaptureManager alloc] initWithPreviewView:self.view];
self.captureManager.delegate = self;

Код, который фактически запускает и останавливает запись, выполняется из метода IBAction следующим образом:

- (IBAction)recButtonTapped:(id)sender {

    // REC START
    if (self.captureManager.isRecording == NO ) {

        NSLog(@"*** Start recording");

        // change UI
        [self.recBtn setImage:self.recStopImage
                     forState:UIControlStateNormal];
        self.fpsControl.enabled = NO;

        // timer start
        startTime = [[NSDate date] timeIntervalSince1970];
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
                                                      target:self
                                                    selector:@selector(timerHandler:)
                                                    userInfo:nil
                                                     repeats:YES];

        [self.captureManager startRecording];

    }
    // REC STOP
    else {

        NSLog(@"*** Stop recording");

        isNeededToSave = YES;
        [self.captureManager stopRecording];

        [self.timer invalidate];
        self.timer = nil;

        // change UI
        [self.recBtn setImage:self.recStartImage
                     forState:UIControlStateNormal];
        self.fpsControl.enabled = YES;

    }
}

РЕДАКТИРОВАТЬ. Я определенно закрываю сеанс в режиме просмотра фотографий, вот этот код. Я убедился, что он вызывается, когда я выхожу из контроллера просмотра фотографий.

        NSLog(@"RELEASE PHOTO SESSION NOW!");

        for(AVCaptureInput *input1 in _mySesh.inputs) {
            [_mySesh removeInput:input1];
        }

        for(AVCaptureOutput *output1 in _mySesh.outputs) {
            [_mySesh removeOutput:output1];
        }


        [_mySesh stopRunning];

        // Fix closing of session
        dispatch_after(
                       dispatch_time(0,500000000),
                       dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
                       ^{
                           _mySesh = nil;
                       }

        );
UPDATE #####

Согласно единственному ответу ниже, я пытался «отвязать» файл перед началом записи. Это все еще не сработало.

NSURL *fileURL = [NSURL URLWithString:[@"file://" stringByAppendingString:filePath]];

    //NSLog(@"Beginning to record to output file...");

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{

        // Wait for session to start
        //[NSThread sleepForTimeInterval:1.0];

        dispatch_async(dispatch_get_main_queue(), ^{

            // Ensure session is running
            if ( [self.captureSession isRunning] == NO ) {
                NSLog(@"Capture session is NOT running... Starting it now!");
                [self.captureSession startRunning];
            }
            else {
                NSLog(@"Capture session is ALREADY running...");
            }

            NSLog(@"File URL is: %@",fileURL);
            NSLog(@"FileOutput is: %@",self.fileOutput);

            // Delete the file
            unlink([[@"file://" stringByAppendingString:filePath] UTF8String]);

            [self.fileOutput startRecordingToOutputFileURL:fileURL recordingDelegate:self];

        });

    });
UPDATE

Просто для потомков я вызываю метод делегата didFinishRecordingToOutputFileAtURL:

- (void)                 captureOutput:(AVCaptureFileOutput *)captureOutput
   didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
                       fromConnections:(NSArray *)connections error:(NSError *)error
{

    // Print any errors
    if ( error ) {
        NSLog(@"Error Recording Video! %@",error.localizedDescription);
    }

    _isRecording = NO;

    if ([self.delegate respondsToSelector:@selector(didFinishRecordingToOutputFileAtURL:error:)]) {
        [self.delegate didFinishRecordingToOutputFileAtURL:outputFileURL error:error];
    }

}

  • Ваши beginConfiguration и commitConfiguration бессмысленны, поскольку вы не выполняете никаких настроек. Действительно, весь вопрос, который вы не затрагиваете в показанном вами коде, заключается в том, как настроен self.captureSession. Когда это было сделано и что было сделано? 19.05.2014
  • Спасибо за комментарий - я добавил больше информации к вопросу. 19.05.2014
  • Вы уверены, что должным образом уничтожаете сеансы, когда закончите с ними? iOS не поддерживает несколько экземпляров AVCaptureSession. Возможно сессия для фотосъемки не освобождается. Когда вы создаете другой сеанс, он не может создавать соединения, поскольку входные порты удерживаются другим экземпляром сеанса. Либо проверьте это сами, либо покажите нам код для захвата фото и видео как с выделением, так и с освобождением сеансов. 21.05.2014
  • Я показываю код, который я использую для закрытия сеанса выше. Я все еще получаю сбой, когда начинаю запись видео. 22.05.2014
  • If a file at the given URL already exists when capturing starts, recording to the new file will fail. Вы проверили это? 27.05.2014
  • Кстати, вы можете удалить такой файл unlink([fileURL UTF8String]); перед вызовом start 27.05.2014
  • такая же ошибка возникает, когда у вас нет разрешения на запись в фотопленку. Обратите внимание, что в iOS 7 разрешение на просмотр камеры = разрешение камеры. В iOS 8 это два отдельных разрешения. 09.02.2015

Ответы:


1

Из того, что я вижу, это связано с уже существующим файлом.

Попробуйте удалить файл перед вызовом startRecordingToOutputFileURL: с помощью: [[NSFileManager defaultManager] removeItemAtPath:fileURL]; Вы можете дважды проверить с помощью: [[NSFileManager defaultManager] fileExistsAtPath:fileURL];

If a file at the given URL already exists when capturing starts, recording to the new file will fail.

Еще одна вещь, которая может вызвать сбой, - это если у вас не реализован метод делегата.

Требуется реализовать: captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:

потому что это единственное надежное место для получения результатов.

Еще одна подозрительная вещь:

Когда вы создаете fileURL, вы делаете

NSURL *fileURL = [NSURL URLWithString:[@"file://" stringByAppendingString:filePath]];

Можете ли вы изменить это на

NSURL *fileURL = [NSURL fileURLWithPath:filePath];

И убедитесь, что filePath действителен.

Из документации: This method throws an NSInvalidArgumentException if the URL is not a valid file URL.

27.05.2014
  • Я пробовал это, но это все еще не исправило ошибку. Спасибо за предложения, вы можете придумать что-нибудь еще? Я разместил код удаления как редактирование моего вопроса. 28.05.2014
  • @PhilBot Можете ли вы дважды проверить, правильно ли он удален? Из вашего выходного журнала у вашего filePath уже есть file://, но вы снова добавили его. Не могли бы вы также проверить наличие файла с BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];? Просто хочу убедиться! 28.05.2014
  • @PhilBot Если это не сработает, установлен ли у вас метод делегата captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:? Я считаю, что это может привести к сбою, если у вас нет этого метода делегата, он необходим. 28.05.2014
  • Когда он падает, этого файла НЕ существует. Я проверил это вызовом fileExistsAtPath. 28.05.2014
  • Кроме того, я вызываю метод делегата didFinishRecordingToOutputFileAtURL — спасибо за вклад, но есть ли у вас другие идеи? 28.05.2014

  • 2

    Прежде всего, сначала запустите AVCaptureSession. После этого вы можете создать AVPreviewLayer и AVCaptureMovieFileOutput.

    Во-вторых, используйте -[AVCaptureSession canAddOutput:] и -[AVCaptureSession canAddInput:] перед добавлением чего-либо в сеанс захвата, это сэкономит вам много времени и нервов.

    В-третьих, вам нужны только beginConfiguration и commitConfiguration, когда вы хотите изменить сразу много вещей в CaptureSession, например. удалить ввод, изменить предустановку. Это полезно при переключении передней/задней камеры, если вы собираетесь это реализовать. Запуск или остановка сеанса между этими вызовами бесполезна.

    28.05.2014

    3

    Попробуйте прокомментировать строку self.captureSession.sessionPreset = ... и посмотрите, поможет ли это. Это помогло мне. Причина проблемы заключалась в том, что я пытался захватить фотографии с максимальным качеством и FOV, но с этой настройкой я получал исключение «нет активных/включенных подключений», когда пытался захватить видео.

    01.08.2014
  • Знаете ли вы способ записи видео без установки предустановки? Иногда вам нужно напрямую установить activeFormat, как предлагает Apple. 11.09.2017

  • 4

    Просто сделайте sessionPreset высоким.

    swift 4 self.captureSession.sessionPreset = .high

    06.09.2018
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..