iphone - guide - ios frameworks
AVPlayerItem replaceCurrentItemWithPlayerItem Blocking (2)
Primero un pequeño contexto sobre la aplicación ...
- Hay una gran cantidad de operaciones pesadas de UI que involucran reproductores de video (principalmente desplazamiento)
- Los videos son dinámicos y cambian según nuestra página actual.
- entonces el video debe ser dinámico y seguir cambiando, y también la interfaz de usuario debe ser receptiva
Inicialmente estaba usando un MPMoviePlayerController
pero luego, debido a ciertos requisitos, tuve que recurrir al AVPlayer
Hice mi propio envoltorio para el AVPlayer
.
Para cambiar el contenido en el videoPlayer, este es el aspecto del método en la clase 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];
}
Ahora, por supuesto, todo estaba funcionando bien ... excepto ...
[self.videoPlayer replaceCurrentItemWithPlayerItem:tempItem];
Parece estar bloqueando la IU durante una fracción de segundo y durante el desplazamiento esto hace que la IU realmente no responda y feo, también esta operación no se puede realizar en segundo plano.
¿Hay alguna solución o solución para esto ...?
La solución que encontré fue asegurar que el AVAsset
subyacente esté listo para devolver información básica, como su duración, antes de alimentarlo al AVPlayer
. AVAsset
tiene un método loadValuesAsynchronouslyForKeys:
que es útil para esto:
AVAsset *asset = [AVAsset assetWithURL:self.mediaURL];
[asset loadValuesAsynchronouslyForKeys:@[@"duration"] completionHandler:^{
AVPlayerItem *newItem = [[AVPlayerItem alloc] initWithAsset:asset];
[self.avPlayer replaceCurrentItemWithPlayerItem:newItem];
}];
En mi caso, la URL es un recurso de red y replaceCurrentItemWithPlayerItem:
realidad bloqueará durante varios segundos replaceCurrentItemWithPlayerItem:
espera que esta información se descargue.
Tuvimos el mismo problema al construir Ultravisual. No recuerdo exactamente cómo lo resolvimos, pero IIRC implicaba hacer la mayor cantidad posible de configuración de elementos en un hilo de fondo, y esperar hasta que el nuevo elemento informe que está ''listo para jugar'' antes de llamar a replaceCurrentItemWithPlayerItem
.
Lamentablemente, esto implica un baile de vudú con KVO asíncrono algo inconsistente, que no es divertido.