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

Как уменьшить задержку запуска IOS AVPlayer

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

Я работаю над приложением iOS, которое требует воспроизведения видеофайлов с минимальной задержкой для запуска рассматриваемого видеоролика. К сожалению, мы не знаем, какой именно видеоролик будет дальше, пока нам не понадобится его запускать. В частности: когда один видеоролик воспроизводится, мы узнаем, что представляет собой следующий набор (примерно) 10 видеороликов, но мы не знаем, какой именно, пока не придет время "немедленно" воспроизвести следующий клип.

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

Из того, что я видел до сих пор, я обнаружил, что используя комбинацию загрузки AVAsset, а затем создавая AVPlayerItem от того, что он готов, а затем ждет AVPlayerStatusReadyToPlay, прежде чем я вызову игру, для начала клипа требуется от 1 до 3 секунд.

С тех пор я переключился на то, что, по моему мнению, примерно эквивалентен: звоните [AVPlayerItem playerItemWithURL:] и ждем AVPlayerItemStatusReadyToPlay для воспроизведения. Примерно такая же производительность.

Одна вещь, которую я наблюдаю, заключается в том, что первая загрузка элемента AVPlayer медленнее остальных. Кажется, одна идея заключается в предполетном AVPlayer с коротким/пустым активом, прежде чем пытаться воспроизвести первое видео может быть хорошей общей практикой. [Медленный запуск для AVAudioPlayer при первом воспроизведении звука

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

Обновление: идея 7 ниже, как реализовано, дает время переключения около 500 мс. Это улучшение, но было бы неплохо сделать это еще быстрее.

Идея 1: используйте N AVPlayers (не будет работать)

Использование объектов ~ 10 AVPPlayer и запуск и приостановка всех ~ 10 клипов, и как только мы узнаем, какой из них нам действительно нужен, переключитесь на правильную AVPlayer и отмените паузу и начните сначала заново следующий цикл.

Я не думаю, что это работает, потому что я читал, что в iOS имеется примерно 4 активных AVPlayer's. Кто-то спрашивал об этом в StackOverflow здесь и узнал о четырех ограничениях AVPlayer: fast-switching-between-videos-using-avfoundation

Идея 2: Использовать AVQueuePlayer (не работает)

Я не верю, что перетащить 10 AVPlayerItems в AVQueuePlayer будет предварительно загружать их все для бесшовного запуска. AVQueuePlayer - это очередь, и я думаю, что это действительно только делает следующее видео в очереди готовым к немедленному воспроизведению. Я не знаю, какой из 10 видеороликов мы хотим воспроизвести, пока не приступит к началу этого. ios-avplayer-video-preloading

Идея 3: загрузить, воспроизвести и сохранить AVPlayerItems в фоновом режиме (не на 100% еще, но не выглядящий хорошо)

Я смотрю, есть ли какая-либо польза для загрузки и воспроизведения первой секунды каждого видеоклипа в фоновом режиме (подавление вывода видео и аудио) и сохраняйте ссылку на каждый AVPlayerItem, и когда мы знаем, какие элемент должен быть воспроизведен для реального, поменяйте его и замените фоновый AVPlayer активным. Промыть и повторить.

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

Идея 4: Используйте другой формат файла - возможно, тот, который быстрее загружается?

В настоящее время я использую формат .m4v (video-MPEG4) H.264. В H.264 есть много различных вариантов кодеков, поэтому возможно, что некоторые параметры быстрее искать, чем другие. Я обнаружил, что использование более продвинутых параметров, которые делают размер файла меньше, увеличивают время поиска, но не нашли никаких параметров, которые идут другим путем.

Идея 5: Сочетание формата видео без потерь + AVQueuePlayer

Если есть видеоформат, который быстро загружается, но, возможно, там, где размер файла сумасшедший, одной из идей может быть предварительная подготовка первых 10 секунд каждого видеоклипа с раздутой версией, но более быстрой для загрузки, но обратно с актива, который закодирован в H.264. Используйте AVQueuePlayer и добавьте первые 10 секунд в формат несжатого файла и следуйте этому примеру, который находится в H.264, который получает до 10 секунд времени подготовки/предварительной загрузки. Таким образом, я получил бы "лучшее" из обоих миров: быстрое начало работы, но также выигрывает от более компактного формата.

Идея 6: используйте нестандартный AVPlayer/напишите мой собственный/используйте чужой

Учитывая мои потребности, возможно, я не могу использовать AVPlayer, но мне приходится прибегать к AVAssetReader и декодировать первые несколько секунд (возможно, писать сырые файлы на диск), а когда дело доходит до воспроизведения, используйте необработанный формат чтобы быстро воспроизвести его. Кажется, это огромный проект для меня, и если я буду заниматься наивным образом, это неясно/вряд ли даже лучше работает. Каждый декодированный и несжатый видеокадр составляет 2,25 МБ. Наивно говоря - если мы пойдем с ~ 30 кадров в секунду для видео, я бы закончил с требованием ~ 60 МБ/с для чтения с диска, что, вероятно, невозможно/подтолкнуло. Очевидно, нам нужно было бы сделать некоторый уровень сжатия изображения (возможно, родные форматы сжатия OpenGL/es через PVRTC)... но такого рода сумасшедшие. Может быть, есть библиотека, которую я могу использовать?

Идея 7: объединить все в один ресурс фильма и искатьToTime

Одна из идей, которая может быть проще, чем некоторые из вышеперечисленных, состоит в том, чтобы объединить все в один фильм и использовать seekToTime. Дело в том, что мы будем прыгать по всему месту. По сути, произвольный доступ к фильму. Я думаю, что это может на самом деле работать нормально: avplayer-movie-playing-lag-in-ios5

Какой подход, по вашему мнению, будет лучше? До сих пор я не добился такого большого прогресса в плане сокращения отставания.

4b9b3361

Ответ 1

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

Ответ 2

Сначала попробуйте вариант № 7, чтобы убедиться, что вы можете это сделать. Я подозреваю, что это не будет работать для ваших нужд, так как время поиска, вероятно, не будет достаточно быстрым, чтобы обеспечить плавное переключение между клипами. Если вы попробуете это и не получится, то я бы посоветовал вам сделать вариант 4/6 и взглянуть на мою iOS-библиотеку, разработанную специально для этой цели, просто выполните быстрый поиск Google на AVAnimator, чтобы узнать больше. Моя библиотека позволяет реализовать бесшовные циклы и переключиться с одного клипа на другой, это очень быстро, потому что видео необходимо предварительно декодировать в файл. В вашем случае все 10 видеоклипов будут дешифрованы в файлы до начала, но переход между ними будет быстрым.

Ответ 3

Не делая ничего подобного в прошлом, основываясь на ваших мыслях и опытах, я бы попытался использовать комбинацию 7 и 1: предварительно загрузите один AVPlayer с помощью первых нескольких секунд из 10 последующих видеороликов. Тогда пропуски, скорее всего, будут быстрее и надежнее из-за меньшего количества данных. Пока вы играете выбранную пьесу, у вас есть достаточно времени, чтобы подготовить AVPlayer для остальной части выбранного последующего видео в фоновом режиме. Когда начало закончено, вы переключаетесь на подготовленный AVPlayer. Таким образом, вы в любой момент времени загружаете максимум 2 AVPlayers.

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

(Добавил бы это как комментарий, если бы мог.)

Лучший, Питер

Ответ 4

Если я правильно понял вашу проблему, кажется, у вас есть одно непрерывное видео, на которое вам нужно загрузить звуковую дорожку на мгновение.

Если это так, я предлагаю изучить BASS. BASS - это аудио-библиотека, подобная AVPlayer, которая дает вам (относительно) легкий доступ к низкоуровневому API-интерфейсу среды AudioUnits в iOS. Что для вас значит? Это означает, что с небольшим количеством манипуляций с буфером (вам может и не понадобиться, зависит от того, насколько малы вы хотите задержку), вы можете сразу начать воспроизведение музыки.

Ограничения, тем не менее, распространяются на видео, как я уже сказал, это библиотека аудио, поэтому всевозможные манипуляции с видео будут выполняться с помощью AVPlayer. Однако, используя -seekToTime:toleranfeBefore:toleranceAfter:, вы должны иметь возможность быстро искать в видео, пока вы пререкаете все необходимые параметры.

Если вы синхронизируете несколько устройств (что может предложить ваше приложение), просто оставьте комментарий, и я с удовольствием отредактировал бы мой ответ.

PS: BASS сначала может выглядеть пугающе из-за его C-подобного формата, но он действительно очень прост в использовании для чего.

Ответ 5

Для iOS 10.x и выше, чтобы уменьшить задержку запуска AVPlayer, я установил: avplayer.automaticallyWaitsToMinimizeStalling = false; и это, казалось, исправило это для меня. Это может иметь и другие последствия, но я еще не поразил их.

Я получил эту идею от: fooobar.com/questions/14633411/...

Ответ 6

Вот несколько свойств и методов, предоставляемых классом AVAsset, которые могут помочь:

- (void)_pu_setCachedDuration:(id)arg1;
- (id)pu_cachedDuration; 
- (struct
 { 
   long long x1; 
   int x2;
   unsigned int x3; 
   long long x4; 
})pu_duration;
- (void)pu_loadDurationWithCompletionHandler:(id /* block */)arg1;