AVPlayerItem replaceCurrentItemWithPlayerItem Blocking
Сначала немного контекста о приложении...
- Там много тяжелой работы пользовательского интерфейса с участием видеоплееров (в основном прокрутки)
- Видеоролики динамичны и меняются в зависимости от нашей текущей страницы.
- поэтому видео должно быть динамичным и постоянно меняться, а пользовательский интерфейс должен быть отзывчивым
Сначала я использовал MPMoviePlayerController
, но затем из-за определенных требований мне пришлось вернуться на AVPlayer
Я сделал свою собственную упаковку для AVPlayer
.
Чтобы изменить содержимое в видеоплеере, это выглядит так, как в классе AVPlayer-wrapper
/**We need to change the whole playerItem each time we wish to change a video url */
-(void)initializePlayerWithUrl:(NSURL *)url
{
AVPlayerItem *tempItem = [AVPlayerItem playerItemWithURL:url];
[tempItem addObserver:self forKeyPath:@"status"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:nil];
[tempItem addObserver:self forKeyPath:@"playbackBufferEmpty"
options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
context:nil];
//Not sure if this should be stopped or paused under the ideal circumstances
//These will be changed to custom enums later
[self setPlaybackState:MPMoviePlaybackStateStopped];
[self setLoadState:MPMovieLoadStateUnknown];
[self.videoPlayer replaceCurrentItemWithPlayerItem:tempItem];
//This is required only if we wish to pause the video immediately as we change the url
//[self.videoPlayer pause];
}
Теперь, конечно, все работает нормально...... кроме.
[self.videoPlayer replaceCurrentItemWithPlayerItem:tempItem];
Кажется, что блокировка пользовательского интерфейса на долю секунды и во время прокрутки делает пользовательский интерфейс действительно невосприимчивым и уродливым, и эта операция не может выполняться в фоновом режиме
Есть ли какое-либо исправление или обходное решение для этого.?
Ответы
Ответ 1
Решение, которое я нашел, состояло в том, чтобы гарантировать, что базовый AVAsset
готов вернуть основную информацию, такую как ее продолжительность, перед подачей ее в AVPlayer
. AVAsset
имеет метод loadValuesAsynchronouslyForKeys:
, который удобен для этого:
AVAsset *asset = [AVAsset assetWithURL:self.mediaURL];
[asset loadValuesAsynchronouslyForKeys:@[@"duration"] completionHandler:^{
AVPlayerItem *newItem = [[AVPlayerItem alloc] initWithAsset:asset];
[self.avPlayer replaceCurrentItemWithPlayerItem:newItem];
}];
В моем случае URL-адрес является сетевым ресурсом, а replaceCurrentItemWithPlayerItem:
будет фактически блокироваться в течение нескольких секунд, ожидая, когда эта информация будет загружена в противном случае.
Ответ 2
У нас была такая же проблема при создании Ultravisual. Я не могу точно помнить, как мы это решили, но в рамках IIRC он выполнял как можно больше настроек элемента в фоновом потоке и ожидал, пока новый элемент не сообщит, что он "готов играть" перед вызовом replaceCurrentItemWithPlayerItem
.
К сожалению, это связано с танцем вуду с несколько непоследовательным асинхронным KVO, что не является забавой.