Переключение видео в AVPlayer создает Flash при изменении

Я использую AVFoundation AVPlayer для воспроизведения 2 видеоклипов, сделанных из 1 более длинного видео (так что конец первого совпадает с началом второго)

Когда первое видео заканчивается и пользовательские нажатия, я создаю новый AVPlayer и назначаю его моему PlayerView и начинаю играть второй клип.

Все это работает, однако, есть видный экран "мерцание".

Мое предположение заключается в том, что это вызвано просмотром плеера, снимающим первый клип, а затем показывающим второй клип.

Мне нужно, чтобы этот мерцание не появлялся, так что между двумя клипами не получается.

Кто-нибудь знает, есть ли способ остановить этот flickr, либо через классы AVPlayer *, либо способ "подделать" его, сделав что-то, чтобы сделать это, чтобы это не было видно.

Спасибо

Ниже приведен код моего метода загрузки и воспроизведения:

- (void)loadAssetFromFile
{
    NSURL *fileURL = nil;

    switch (playingClip)
    {
        case 1:
            fileURL = [[NSBundle mainBundle] URLForResource:@"wh_3a" withExtension:@"mp4"];
        break;

        case 2:
            fileURL = [[NSBundle mainBundle] URLForResource:@"wh_3b" withExtension:@"mp4"];
        break;

        case 3:
            fileURL = [[NSBundle mainBundle] URLForResource:@"wh_3c" withExtension:@"mp4"];
        break;

        case 4:
            fileURL = [[NSBundle mainBundle] URLForResource:@"wh_3d" withExtension:@"mp4"];
        break;

        default:
            return;
        break;
    }

    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
    NSString *tracksKey = @"tracks";

    [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:tracksKey] completionHandler:
 ^{
     // The completion block goes here.
     NSError *error = nil;
     AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error];

     if (status == AVKeyValueStatusLoaded)
     {
         self.playerItem = [AVPlayerItem playerItemWithAsset:asset];

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

         self.player = [AVPlayer playerWithPlayerItem:playerItem];
         [playerView setPlayer:player];

         [self.player seekToTime:kCMTimeZero];

         [self play];
     }
     else {
         // Deal with the error appropriately.
         NSLog(@"The asset tracks were not loaded:\n%@", [error localizedDescription]);
     }
 }];
}

Ответ 1

Вам не нужно повторно создавать AVPlayer для этой задачи. Вы можете просто иметь несколько AVPlayerItem, а затем переключиться, какой из них осуществляется через [AVPlayer replaceCurrentItemWithPlayerItem:item].

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

 static void* CurrentItemObservationContext = &CurrentItemObservationContext;

... После создания игрока зарегистрируйте наблюдателя:

 [player1 addObserver:self 
                   forKeyPath:kCurrentItemKey 
                      options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                      context:CurrentItemObservationContext];

...

 - (void)observeValueForKeyPath:(NSString*) path 
                  ofObject:(id)object 
                    change:(NSDictionary*)change 
                   context:(void*)context {
     if (context == CurrentItemObservationContext) {
         AVPlayerItem *item = [change objectForKey:NSKeyValueChangeNewKey];
         if (item != (id)[NSNull null]) {
             [player1 play];
         }
     }
 }

Ответ 2

Есть два обходных пути, которые я нашел. Для меня оба подхода работали, и я предпочитаю второй.

Во-первых, как отметил @Alex Kennberg, создайте два набора AVPlayerLayer и AVPlayer. и переключая их при переключении между видео. Обязательно установите цвет фона для очистки цвета.

Во-вторых, используйте UIImageView как вид владельца AVPlayerLayer. Создайте эскиз видео и установите его в изображение перед переключением видео. Убедитесь, что режим просмотра установлен правильно.

Ответ 3

Я попробовал это, и это сработало для меня.

 if (layerView1.playerLayer.superlayer) {
        [layerView1.playerLayer removeFromSuperlayer];
 }

Но я также выделяю свой собственный AVPlayerLayer вместо того, чтобы использовать IB для этого.