AVPlayerItem завершается ошибкой с AVStatusFailed и кодом ошибки «Cannot Decode» - PullRequest
31 голосов
/ 22 декабря 2011

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

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

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

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

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

Ответы [ 4 ]

72 голосов
/ 30 марта 2012

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

Существует ограничение на количество одновременных видеоплееров, которые разрешает AVFoundation. Это связано с ограничениями аппаратного обеспечения iOS. Предел для текущих устройств составляет 4 игрока. Если вы создадите 5-го игрока, вы получите ошибку «невозможно декодировать». Это не ограничение на количество экземпляров 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, но не было ясно, какое приложение использует конвейер.

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

7 голосов
/ 06 марта 2012

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

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

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

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

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

3 голосов
/ 05 июля 2012

Этот был абсолютно убивающим меня, пока я не понял это, собирая подсказки из этой темы и нескольких других. Самая большая проблема в моем коде заключалась в том, что я запускал свой контроллер видеопроигрывателя каждый раз, когда я хотел воспроизвести видео. Теперь он получает экземпляр один раз в основном контроллере (в данном случае мой 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]]];
        }
    }
}
2 голосов
/ 24 декабря 2011

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...