ios objective-c video avfoundation

ios - Reproducción de videos apilados



objective-c avfoundation (2)

Eche un vistazo a la forma en que está configurando la variable myCounter. Se establece una vez y nunca cambia hasta que se toca una vista, y luego se establece en el recuento de escenas, -1.

Además, intente ver la forma en que está configurando la var del puntero _avPlayer. Siempre se está configurando, una y otra vez, y parece que en un bucle for querría almacenar referencias en lugar de simplemente actualizar el mismo puntero al valor más reciente en la colección de escenas.

Además, de la documentación de Apple:

Puede crear números arbitrarios de capas de jugador con el mismo objeto AVPlayer. Solo la capa de jugador creada más recientemente mostrará el contenido de video en pantalla.

Por lo tanto, es posible que, dado que esté utilizando el mismo objeto AVPlayer para crear todas estas capas AVPlayer, nunca vea más de una capa de video real.

Tengo varias subvistas de la vista de imagen que se apilan en función de mis datos entrantes. Básicamente, todas estas subvistas están configuradas en una imagen o en una capa de video en función de mis datos entrantes. El problema que tengo es reproducir videos. Puedo reproducir el primer video en la pila, pero cada video posterior es solo el sonido del primer video. ¿Cómo puedo jugar cada uno en consecuencia?

las vistas se navegan a través de un evento tap como snapchat. vea abajo:

@interface SceneImageViewController () @property (strong, nonatomic) NSURL *videoUrl; @property (strong, nonatomic) AVPlayer *avPlayer; @property (strong, nonatomic) AVPlayerLayer *avPlayerLayer; @end @implementation SceneImageViewController - (void)viewDidLoad { [super viewDidLoad]; self.mySubviews = [[NSMutableArray alloc] init]; self.videoCounterTags = [[NSMutableArray alloc] init]; int c = (int)[self.scenes count]; c--; NSLog(@"int c = %d", c); self.myCounter = [NSNumber numberWithInt:c]; for (int i=0; i<=c; i++) { //create imageView UIImageView *imageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)]; [imageView setUserInteractionEnabled:YES]; // <--- This is very important imageView.tag = i; // <--- Add tag to track this subview in the view stack [self.view addSubview:imageView]; NSLog(@"added image view %d", i); //get scene object PFObject *sceneObject = self.scenes[i]; //get the PFFile and filetype PFFile *file = [sceneObject objectForKey:@"file"]; NSString *fileType = [sceneObject objectForKey:@"fileType"]; //check the filetype if ([fileType isEqual: @"image"]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ //get image NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url]; NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl]; dispatch_async(dispatch_get_main_queue(), ^{ imageView.image = [UIImage imageWithData:imageData]; }); }); } //its a video else { // the video player NSURL *fileUrl = [NSURL URLWithString:file.url]; self.avPlayer = [AVPlayer playerWithURL:fileUrl]; self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; //self.avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:[self.avPlayer currentItem]]; CGRect screenRect = [[UIScreen mainScreen] bounds]; self.avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height); [imageView.layer addSublayer:self.avPlayerLayer]; NSNumber *tag = [NSNumber numberWithInt:i+1]; NSLog(@"tag = %@", tag); [self.videoCounterTags addObject:tag]; //[self.avPlayer play]; } } UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTapped:)]; [self.view bringSubviewToFront:self.screen]; [self.screen addGestureRecognizer:tapGesture]; } - (void)viewTapped:(UIGestureRecognizer *)gesture{ NSLog(@"touch!"); [self.avPlayer pause]; int i = [self.myCounter intValue]; NSLog(@"counter = %d", i); for(UIImageView *subview in [self.view subviews]) { if(subview.tag== i) { [subview removeFromSuperview]; } } if ([self.videoCounterTags containsObject:self.myCounter]) { NSLog(@"play video!!!"); [self.avPlayer play]; } if (i == 0) { [self.avPlayer pause]; [self.navigationController popViewControllerAnimated:NO]; } i--; self.myCounter = [NSNumber numberWithInt:i]; NSLog(@"counter after = %d", i); }


Lo que Brooks Hanes dijo es correcto, sigues anulando al avplayer. Esto es lo que sugiero que hagas:

  1. Agregue el gesto de tap a imageView en lugar de a la pantalla (o para un enfoque más limpio use UIButton en UIButton lugar):

    UIImageView *imageView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)]; [imageView setUserInteractionEnabled:YES]; // <--- This is very important imageView.tag = i; // <--- Add tag to track this subview in the view stack [self.view addSubview:imageView]; NSLog(@"added image view %d", i); UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:imageView action:@selector(viewTapped:)]; [imageView addGestureRecognizer:tapGesture];

De esta forma, en su método viewTapped: podría obtener la etiqueta de la imagen presionada de la siguiente manera: gesture.view.tag lugar de usar myCounter .

  1. Para que el video funcione, podría crear un nuevo AVPlayer para cada video, pero eso podría volverse bastante costoso para la memoria. Un mejor enfoque será usar AVPlayerItem y cambiar el AVPlayer del AVPlayerItem al cambiar el video.

Entonces en el ciclo for haga algo como esto donde self.videoFiles es una propiedad NSMutableDictionary :

// the video player NSNumber *tag = [NSNumber numberWithInt:i+1]; NSURL *fileUrl = [NSURL URLWithString:file.url]; //save your video file url paired with the ImageView it belongs to. [self.videosFiles setObject:fileUrl forKey:tag]; // you only need to initialize the player once. if(self.avPlayer == nil){ AVAsset *asset = [AVAsset assetWithURL:fileUrl]; AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset]; self.avPlayer = [[AVPlayer alloc] initWithPlayerItem:item]; self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:[self.avPlayer currentItem]]; } // you don''t need to keep the layer as a property // (unless you need it for some reason AVPlayerLayer* avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer]; avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; CGRect screenRect = [[UIScreen mainScreen] bounds]; avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height); [imageView.layer addSublayer:avPlayerLayer]; NSLog(@"tag = %@", tag); [self.videoCounterTags addObject:tag];

Ahora en su vista viewTapped :

if ([self.videoCounterTags containsObject:gesture.view.tag]) { NSLog(@"play video!!!"); AVAsset *asset = [AVAsset assetWithURL:[self.videoFiles objectForKey:gesture.view.tag]]; AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset]; self.avPlayer replaceCurrentItemWithPlayerItem: item]; [self.avLayer play]; }

O use self.videoFiles en self.videoFiles lugar y luego no necesita self.videoCounterTags en absoluto:

NSURL* fileURL = [self.videoFiles objectForKey:gesture.view.tag]; if (fileURL!=nil) { NSLog(@"play video!!!"); AVAsset *asset = [AVAsset assetWithURL:fileURL]; AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset]; self.avPlayer replaceCurrentItemWithPlayerItem: item]; [self.avLayer play]; }

Esa es la esencia de eso.