Воспроизведение сложенных видеороликов

У меня есть несколько подвид представлений изображений, которые собираются на основе моих входящих данных. В основном все эти подвидности либо настроены на изображение, либо видеослот на основе моих входящих данных. Проблема в том, что я играю видео. Я могу воспроизвести первое видео в стеке, но каждое видео после этого является только звуком первого видео. Как я могу играть соответственно?

просмотры просматриваются с помощью события tap, такого как snapchat. см. ниже:

@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);





}

Ответ 1

Что сказал Брукс Хейнс, вы сохраняете приоритет в avplayer. Это то, что я предлагаю вам сделать:

  • Добавьте жест выделения к imageView вместо экрана (или для более чистого подхода используйте UIButton):

    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];
    

Таким образом, в вашем методе viewTapped: вы можете получить тег прессованного изображения следующим образом: gesture.view.tag вместо использования myCounter.

  1. Чтобы получить работу с видео, вы можете создать новый AVPlayer для каждого видео, но это может стать довольно дорогостоящей памятью. Лучше использовать AVPlayerItem и переключать AVPlayer AVPlayerItem при изменении видео.

Итак, в цикле for сделайте что-то вроде этого, где self.videoFiles является свойством 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];

Теперь в 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];
}

Или используйте self.videoFiles, а затем вам не нужно self.videoCounterTags вообще:

 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];
 }

Это его суть.

Ответ 2

Посмотрите, как вы настраиваете переменную myCounter. Он устанавливается один раз и никогда не изменяется до тех пор, пока не будет прослушен вид, а затем он будет установлен на количество сцен, -1.

Кроме того, попробуйте посмотреть, как вы настраиваете указатель _avPlayer var. Он всегда устанавливается снова и снова, и кажется, что в цикле for вы хотите хранить ссылки вместо простого обновления того же указателя на значение, последнее в коллекции сцен.

Кроме того, от Apple documentation:

Вы можете создать произвольное количество слоев игроков с тем же самым объектом AVPlayer. Только последний созданный слой игрока фактически отобразит видеоконтент на экране.

Итак, возможно, что, поскольку вы используете один и тот же объект AVPlayer для создания всех этих слоев AVPlayer, вы никогда не увидите больше, чем один фактический уровень видеоизображения.