Método más efectivo para video como background en iOS

Quizás hayas notado una de las últimas tendencias en aplicaciones iOS: usar videos como backgrounds, principalmente en las pantallas de inicio de session o "primer lanzamiento". Ayer intenté imitar esto con un proyecto de testing muy simple (solo un controller de vista) y estoy satisfecho con los resultados a exception del performance . Al probarlo en el simulador de iOS (en un iPhone 6 simulado), el uso de la CPU fluctúa entre 70 y 110% . Esto parece muy poco razonable para una simple pantalla de inicio de session.

Esto es lo que parece en acción: http://oi57.tinypic.com/nqqntv.jpg

La pregunta es entonces: ¿hay una forma más efectiva de CPU para lograr esto? ¿Cómo hacen las aplicaciones como Vine, Spotify e Instagram?

Antes de contestar; el método que utilicé fue un video full-HD reproducido usando MPMoviePlayerController:

- (void)viewDidLoad { [super viewDidLoad]; // find movie file NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"arenaVideo" ofType:@"mp4"]; NSURL *movieURL = [NSURL fileURLWithPath:moviePath]; // load movie self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL]; self.moviePlayer.controlStyle = MPMovieControlStyleNone; self.moviePlayer.view.frame = self.view.frame; self.moviePlayer.scalingMode = MPMovieScalingModeAspectFill; [self.view addSubview:self.moviePlayer.view]; [self.view sendSubviewToBack:self.moviePlayer.view]; [self.moviePlayer play]; // loop movie [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(replayMovie:) name: MPMoviePlayerPlaybackDidFinishNotification object: self.moviePlayer]; } #pragma mark - Helper methods -(void)replayMovie:(NSNotification *)notification { [self.moviePlayer play]; } 

Por supuesto, los bordes del video podrían haberse recortado para que la resolución sea algo más en la línea de, digamos, 700×1080 en lugar de 1920×1080, pero ¿habría hecho una gran diferencia en el performance? ¿O debo comprimir el video con un determinado formatting y configuraciones para lograr un performance óptimo? Tal vez hay un enfoque totalmente alternativo a esto?

En realidad, intenté usar GIF como se describe en este artículo: https://medium.com/swift-programming/ios-make-an-awesome-video-background-view-objective-c-swift-318e1d71d0a2

El problema con eso es:

  • Crear GIFs de videos requiere mucho time y esfuerzo.
  • No vi disminución significativa del uso de CPU cuando lo probé.
  • Soportar varios tamaños de pantalla es un dolor total con este enfoque (al less cuando lo intenté, con Autolayout y Clases de tamaño habilitadas, no pude lograr que el GIF se escalara correctamente entre dispositivos)
  • La calidad del video es pobre.

La mejor forma de utilizar AVFoundation es controlar la capa de video en sí misma

En el file del encabezado, declare @property (nonatomic, strong) AVPlayerLayer *playerLayer;

 - (void)viewDidLoad { [super viewDidLoad]; [self.view.layer addSublayer:self.playerLayer]; // loop movie [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(replayMovie:) name: AVPlayerItemDidPlayToEndTimeNotification object:nil]; } -(AVPlayerLayer*)playerLayer{ if(!_playerLayer){ // find movie file NSString *moviePath = [[NSBundle mainBundle] pathForResource:@"arenaVideo" ofType:@"mp4"]; NSURL *movieURL = [NSURL fileURLWithPath:moviePath]; _playerLayer = [AVPlayerLayer playerLayerWithPlayer:[[AVPlayer alloc]initWithURL:movieURL]]; _playerLayer.frame = CGRectMake(0,0,self.view.frame.size.width, self.view.frame.size.height); [_playerLayer.player play]; } return _playerLayer } -(void)replayMovie:(NSNotification *)notification { [self.playerLayer.player play]; } 

Swift 2.0

 lazy var playerLayer:AVPlayerLayer = { let player = AVPlayer(URL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("LaunchMovie", ofType: "mov")!)) player.muted = true player.allowsExternalPlayback = false player.appliesMediaSelectionCriteriaAutomatically = false var error:NSError? // This is needed so it would not cut off users audio (if listening to music etc. do { try AVAudioSession.shanetworkingInstance().setCategory(AVAudioSessionCategoryAmbient) } catch var error1 as NSError { error = error1 } catch { fatalError() } if error != nil { print(error) } var playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.frame playerLayer.videoGravity = "AVLayerVideoGravityResizeAspectFill" playerLayer.backgroundColor = UIColor.blackColor().CGColor player.play() NSNotificationCenter.defaultCenter().addObserver(self, selector:"playerDidReachEnd", name:AVPlayerItemDidPlayToEndTimeNotification, object:nil) return playerLayer }() override func viewDidLoad() { super.viewDidLoad() self.view.layer.addSublayer(self.playerLayer) } override func viewWillDisappear(animated: Bool) { NSNotificationCenter.defaultCenter().removeObserver(self) } // If orientation changes override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { playerLayer.frame = self.view.frame } func playerDidReachEnd(){ self.playerLayer.player!.seekToTime(kCMTimeZero) self.playerLayer.player!.play() } 

Probado en iOS7 – iOS9

Me doy count de que se trata de una publicación anterior, pero como he tenido cierta experiencia en networkingucir el uso de la CPU en mi aplicación iOS, responderé.

El primer lugar para mirar es usar AVFoundationFramework

Implementar AVPlayer debería ayudar a networkingucir la CPU un poco

pero la mejor solución es utilizar la librería GPUImage de Brad Larson que utiliza OpenGl y networkingucirá el uso de la CPU en gran medida. Descargue la biblioteca y hay ejemplos de cómo usarla. Recomiendo usar GPUImageMovieWriter

Lo hago con AVAssetReader, GLKView y renderizado a través de una canalización CIImage. Cuando se reproduce ningún video filtrado en el simulador, se consume aproximadamente un 80% de CPU. En un dispositivo real, cuesta 1x% con filtrado en time real (CIFilter). Se puede configurar para bucle y controlar el FPS también. Lo hice en Github y le doy la bienvenida a alguien para que tenga una copy. Será una buena opción alternativa para alguien que no quiere soltar toda la GPUImage solo para una vista de background de video. Arrastra y suelta la vista y funciona. https://github.com/matthewlui/FSVideoView

Encontré este código en GitHub que funcionó para mí en iOS8 / 9

 - (void)viewDidLoad { [super viewDidLoad]; // Load the video from the app bundle. NSURL *videoURL = [[NSBundle mainBundle] URLForResource:@"video" withExtension:@"mov"]; // Create and configure the movie player. self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL]; self.moviePlayer.controlStyle = MPMovieControlStyleNone; self.moviePlayer.scalingMode = MPMovieScalingModeAspectFill; self.moviePlayer.view.frame = self.view.frame; [self.view insertSubview:self.moviePlayer.view atIndex:0]; [self.moviePlayer play]; // Loop video. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loopVideo) name:MPMoviePlayerPlaybackDidFinishNotification object:self.moviePlayer]; } - (void)loopVideo { [self.moviePlayer play]; } 

Para iOS9, utilicé el código de Andrius y agregué lo siguiente para el ciclo:

 -(void)replayBG:(NSNotification *)n { [playerLayer.player seekToTime:kCMTimeZero]; [playerLayer.player play]; }