Подтвердить что ты не робот

AVPlayerItem не работает с AVStatusFailed и кодом ошибки "Can not Decode"

У меня возникает странная проблема, я надеюсь, что кто-то может помочь.

В моем приложении iOS я создаю видео с помощью саундтрека, используя MutableComposition, объединяя видео из библиотеки фотографий пользователя и аудиофайла из пакета приложений. Затем я использую AVPlayer и AVPlayerItem для воспроизведения видео с помощью пользовательского видеопроигрывателя, который я сделал.

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

Все работает нормально, пока после того, как ровно 4 успешных видео создаются таким образом, каждая другая попытка создания проигрывателя выходит из строя с ошибкой Cannot Decode. Не имеет значения, если его одно и то же видео, которое я воссоздаю, не имеет никакого отношения к размеру/длине видео или аудиофайла, который он просто всегда терпит неудачу точно в пятой попытке, например, в часах. Как только он терпит неудачу, он всегда будет терпеть неудачу!

Это странно, потому что он просто декодировал одно и то же видео четыре раза без проблем, так что вдруг это не получилось? Итак, если у кого есть ключ, пожалуйста, дайте мне знать.

4b9b3361

Ответ 1

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

Существует ограничение на количество одновременных видеоплееров, которые AVFoundation позволит. Это связано с ограничениями оборудования iOS. Предел для текущих устройств - 4 игрока. Если вы создадите пятого игрока, вы получите ошибку "не может декодировать". Это не ограничение количества экземпляров AVPlayer или AVPlayerItem. Скорее, это ассоциация AVPlayerItem с AVPlayer, которая создает "конвейер рендеринга", и вы ограничены 4 из них. Например, это вызывает новый конвейер рендеринга:

AVPlayer *player = [AVPlayer playerWithPlayerItem:somePlayerItem];  
// assuming the AVPlayerItem is ready to go with an AVAsset that has been loaded

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

Итак, вы идете, это было полностью недокументировано, но это история.

Ответ 2

Я столкнулся с тем же сообщением об ошибке после создания 4 экземпляров AVPlayer, исправление в моем случае было не совсем таким же. Возможно, это поможет любому, кто сталкивается с этой проблемой.

В конце концов я обнаружил, что AVPlayers не выпускались, когда я думал, что это так. В моем случае я подталкивал свой AVPlayer View Controller к контроллеру навигации. Несмотря на то, что я создавал только один экземпляр AVPlayer за раз, когда контроллеры просмотра вышли из контроллера навигации, они не были немедленно выпущены. Тогда было очень легко достичь 4 экземпляров AVPlayer до того, как старые очистители View View были очищены.

Только когда я убедился, что предыдущие игроки были выпущены, эта проблема исчезла. Чтобы быть полным, я выпустил AVPlayerItem, AVPlayer и установил проигрыватель на AVPlayerLayer на ноль перед выпуском.

Мне нужно задаться вопросом, существует ли ограничение на экземпляры AVPlayer, непреднамеренное или нет. Связанный бит информации из документов: https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/02_Playback.html

"Многослойные слои: вы можете создавать произвольно многие объекты AVPlayerLayer из одного экземпляра AVPlayer, но только самый недавно созданный такой слой отобразит на экране любое видеоконтент.

Ответ 3

Хорошо, я понял решение, надеюсь, это поможет любому, кто может наткнуться на что-то похожее на эту проблему.

Решение в моем случае состояло в том, чтобы инициализировать ресурс для AVPlayer и AVPlayerItem в основном потоке и убедиться, что я не создаю фактический AVPlayerLayer до того, как playerItem и объекты игрока возвращаются со статусом ReadyToPlay.

Это оказалось сложным для изоляции, и я до сих пор не знаю, почему он работал первые 4 раза, а затем неудачно последовал в 5-й раз.

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

Ответ 4

Этот был абсолютно убит меня, пока я не понял это, взяв подсказки из этой темы и нескольких других. Самая большая проблема в моем коде была в том, что я создавал экземпляр моего контроллера видеоплеера каждый раз, когда я хотел играть в видео. Теперь он создается экземпляр один раз в основном контроллере (в данном случае мой DetailViewContoller):

@interface DetailViewController () {
    VideoPlayerViewController *videoPlayerViewController;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    videoPlayerViewController = [[VideoPlayerViewController alloc] initWithNibName: nil bundle: nil];
}

Когда я хочу показать видео, я вызываю метод DetailViewController startVideoPlayback:

- (void) startVideoPlayback: (NSString *)videoUID
{
    videoPlayerViewController.videoUID = videoUID;
    [self presentModalViewController: videoPlayerViewController animated: YES];
}

(ПРИМЕЧАНИЕ. Я передаю его "videoUID" - уникальный идентификатор, который был использован для создания видео в другой части приложения.)

В VideoPlayerViewController (который в значительной степени взят из Apple AVPlayerDemo образец), одноразовая настройка экрана (инициализация AVPlayer, установка вверх по панели инструментов и т.д.) выполняется в viewDidLoad, который теперь только вызывается один раз, а все настройки для каждого видеоролика выполняются в viewWillAppear, который затем вызывает prepareToPlay

- (void) prepareToPlay
{
    [self initScrubberTimer];   
    [self syncPlayPauseButtons];
    [self syncScrubber];

    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    //*** Retrieve and play video at associated with this videoUID
    NSString *destinationPath = [documentsDirectory stringByAppendingFormat: @"/%@.mov", videoUID];
    if ([self fileExists: destinationPath]) {

        //*** Show the activity indicator spinny thing
        [pleaseWait startAnimating];
        [self setURL: [NSURL fileURLWithPath: destinationPath]];
        //*** Get things going with the first video in this session
        if (isFirst) {
            isFirst = NO;
        //*** Subseqeunt videos replace the first one
        } else {
            [self.mPlayer replaceCurrentItemWithPlayerItem: [AVPlayerItem playerItemWithURL: [NSURL fileURLWithPath: destinationPath]]];
        }
    }
}