2011-06-06 13 views
5

Estoy trabajando en un reproductor de video personalizado para iOS utilizando AVFoundation. La idea es poder cambiar a un video diferente con un gesto (tocar, deslizar, lo que sea). En este momento el reproductor funciona perfectamente en el simulador, pero cuando lo pruebo en un dispositivo real, la vista queda en blanco después de 3 o 4 golpes. Incluso he creado controles de reproducción para mi reproductor, cuando la vista se queda en blanco, estos controles se cargan correctamente pero no hacen nada. Alguna idea chicos? Esta es la inicialización para el jugadorReproducción de muchos videos diferentes en el iPhone con AVPlayer

  - (id)initWithContentURL:(NSString *)aContentURL delegate:(id)aDelegate { 
     self = [super initWithNibName:@"NoCashMoviePlayer" bundle:nil]; 
     if (self == nil) 
      return nil; 
     delegate = aDelegate; 
     systemPath = [aContentURL retain]; 
     contentURL = [[NSURL alloc]initFileURLWithPath:systemPath]; 
     asset = [AVURLAsset URLAssetWithURL:contentURL options:nil]; 
     playerItem = [AVPlayerItem playerItemWithAsset:asset]; 
     isPaused = false; 
     controlsHidden = false; 
     self.player = [[AVPlayer playerWithPlayerItem:playerItem] retain]; 
     duration = self.player.currentItem.asset.duration; 

     return self; 
    } 

Este es el código que reproduce el vídeo:

-(void)playMovie{ 

     UITapGestureRecognizer *tapRecon = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(toggleControls:)]; 
     [tapRecon setNumberOfTapsRequired:2]; 
     [self.movieContainer addGestureRecognizer:tapRecon]; 
     [tapRecon release]; 

     NSLog(@"Playing item: %@",contentURL); 
     playerLayer = [AVPlayerLayer playerLayerWithPlayer:player]; 
     [movieContainer.layer addSublayer:playerLayer]; 
     playerLayer.frame = movieContainer.layer.bounds; 
     playerLayer.videoGravity = AVLayerVideoGravityResizeAspect; 
     self.seeker.alpha = 1.0; 
     [self.view addSubview:movieContainer]; 
     [self.movieContainer addSubview:controls]; 
     [self setSlider]; 
     [player play]; 
     player.actionAtItemEnd = AVPlayerActionAtItemEndNone; 

     [[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(playerItemDidReachEnd:) 
              name:AVPlayerItemDidPlayToEndTimeNotification 
              object:[player currentItem]]; 


    } 

El código para seleccionar el clip para ser jugado:

-(void)viewSelect: (double) curTime{ 
     self.myView.backgroundColor = [UIColor blackColor]; 
     UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeFrom:)]; 
     swipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight; 
     [self.myView addGestureRecognizer:swipeRecognizer]; 
     [swipeRecognizer release]; 

     UISwipeGestureRecognizer *leftRecognizer = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeFromLeft:)]; 
     swipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft; 
     [self.myView addGestureRecognizer:leftRecognizer]; 
     [leftRecognizer release]; 


     if(isMain){ 
      [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationTransitionFlipFromLeft animations:^{ 
       self.myView.alpha = 1.0; 
       moviePlayer = [[NoCashMoviePlayer alloc]initWithContentURL:[self movieURL:vidIndex] delegate:self]; 
       self.moviePlayer.view.frame = self.myView.bounds; 
       self.moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight; 
       [self.myView addSubview:moviePlayer.view]; 

      }completion:^(BOOL finished) { 
       [self.moviePlayer.player seekToTime:CMTimeMake(curTime, 1)]; 
       [self.moviePlayer playMovie]; 
      }]; 
     }else{ 

      [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationTransitionFlipFromLeft animations:^{ 
       self.otherView.alpha = 1.0; 
       moviePlayer = [[NoCashMoviePlayer alloc]initWithContentURL:[self movieURL:vidIndex] delegate:self]; 
       self.moviePlayer.view.frame = self.otherView.bounds; 
       self.moviePlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |UIViewAutoresizingFlexibleHeight; 
       [self.otherView addSubview:moviePlayer.view]; 

      }completion:^(BOOL finished) { 

       [self.moviePlayer.player seekToTime:CMTimeMake(curTime, 1)]; 
       [self.moviePlayer playMovie]; 
      }]; 
     } 
    } 

Y por último, la acción del gesto:

- (void)handleSwipeFromLeft:(UISwipeGestureRecognizer *)recognizer { 

     double elapsedTime = 0.0; 
     if(vidIndex==0){ 
      vidIndex = 3; 
     }else vidIndex = vidIndex --; 
     elapsedTime = [self.moviePlayer currentTimeInSeconds]; 
     [self.moviePlayer stopMovie]; 
     isMain = !isMain; 
     [self viewSelect: elapsedTime]; 

    } 

EDITAR: Intenté usar diferentes AVPlayerLayers para cada archivo de video, la misma situación, funciona en el simulador, no en el iPad.

EDIT 2: me encontré con instrumentos para analizar el rendimiento del núcleo de animación, y cuando se reproduce el vídeo está mostrando una tasa de fotogramas de unos 30 fps, cuando el jugador se queda en blanco que cae hasta el fondo a 1 o 2 fps. Esto puede ser ovbioso, pero aún así, si ayuda a dar un poco más de luz ...

EDIT 3: Bien, finalmente estoy llegando a algún lugar, sé cuál es el problema, tengo una memoria de animación central Fugas, en el simulador "funciona" porque la computadora tiene MUCHA más memoria que el iPad, pero como el iPad tiene memoria muy limitada, deja de funcionar muy rápido. Si alguien tiene algún consejo con respecto a las filtraciones de Core Animation, será muy bien recibido.

Respuesta

4

RESUELTO FINALMENTE. El diseño que tenía era muy pobre, tenía una mala gestión de la memoria, etc. Lo que hice fue, en lugar de liberar todo lo que pude, incluyendo vistas, capas, jugadores, activos, etc., simplemente creé un método para actualizar el activo y el elemento del jugador, reciclando el jugador, vistas, capas, etc.

[player pause]; 
    contentURL = [[NSURL alloc] initFileURLWithPath:newPath]; 
    AVAsset *newAsset = [AVURLAsset URLAssetWithURL:contentURL options:nil]; 
    AVPlayerItem *newPlayerItem = [AVPlayerItem playerItemWithAsset:newAsset]; 
    [player replaceCurrentItemWithPlayerItem:newPlayerItem]; 
    [contentURL release]; 

Y ahora está funcionando de maravilla. Gracias por toda tu ayuda.

1

Hay 2 lugares en el código donde ha retenido un objeto, y no veo el lanzamiento correspondiente en ninguna parte del código que ha publicado. Comenzaría asegurándome de que los incrementos y decrementos de la cuenta de referencia de la memoria estén todos equilibrados adecuadamente.

La primera retención parece sospechosa para mí. En general, usted debe primero AutoRelease la variable que se está asignando a y luego retener de la siguiente manera:

[systemPath autorelease]; 
systemPath = [aContentURL retain] 

En el código anterior es fácil ver que la coincidencia de retener/liberación se mantiene, y es mucho menos errores propenso que otros esquemas. Tenga en cuenta que si systemPath == aContentURL el objeto no será liberado.

+0

Todos los objetos retenidos se liberan en el método 'dealloc'. ¿Sería eso suficiente? En realidad, solía tener el reproductor sin la palabra clave 'retener', pero fue peor, finalmente provocó un bloqueo, porque el objeto se estaba liberando en algún momento durante el tiempo de ejecución. – Samssonart

+0

No estoy seguro sin ver el código exacto. Pero el primer retener no parece seguir el patrón estándar. –

+0

Gracias por la ayuda de Himadri, he intentado algunas soluciones diferentes de conteo de memoria/referencia, pero todavía no está funcionando. Intenté usar instrumentos y hubo algunas filtraciones, los cuidé y todavía nada. Seguiré intentando. – Samssonart

Cuestiones relacionadas