Разочарования AVQueuePlayer (обработка опустошения буфера)

У меня чертовски много времени с AVQueuePlayer. Очень просто, я делаю это на основе массива AVPlayerItems, созданного с помощью playerItemWithURL: и указывающего на видеоресурсы на сервере в сети.

Если я попытаюсь запустить эту штуку в стимуляторе (sic), она проиграет первый ассет, начнет проигрывать второй и просто умрет. Иногда он даже не проходит через первый актив.

Теперь я понимаю, что сим ведет себя иначе, чем устройство, поэтому я попробовал и на устройстве, с той же проблемой.

Когда я логирую различные изменения состояния предмета, я вижу, что буфер заканчивается, и игрок просто умирает. Мне это кажется немного глупым для конструкции, которая воспроизводит очередь элементов... конечно, буфер может быть переполнен, но почему он просто умирает?

Я что-то не так делаю, или так и должно быть?

Я обошел эту проблему, наблюдая за свойством loadingTimeRanges и когда оно изменяется, отправляя PLAY игроку. Но это приводит к заиканию воспроизведения, что тоже отстой.

Вот мой код. Может кто-нибудь, пожалуйста, скажите мне, как это сделать, чтобы воспроизведение не было полным дерьмом?

- (void)viewDidLoad {
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePlayerItemReachedEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.queuePlayer];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePlayerStalled:) name:AVPlayerItemPlaybackStalledNotification object:self.queuePlayer];

    NSString *baseURL = @"http://www.aDomain.com/assets/";
    NSMutableArray *vidItemArray = [[NSMutableArray alloc] initWithCapacity:5];

    for (int i = 1; i <= 5; i++) {
        AVPlayerItem *vid = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:[baseURL stringByAppendingFormat:@"%d.mov", i]]];
        [vid addObserver:self forKeyPath:@"status" options:0 context:nil];
        [vid addObserver:self forKeyPath:@"playbackBufferEmpty" options:0 context:nil];
        [vid addObserver:self forKeyPath:@"loadedTimeRanges" options:0 context:nil];
        [vidItemArray addObject:vid];
    }

    self.queuePlayer = [AVQueuePlayer queuePlayerWithItems:vidItemArray];
    [self.mPlaybackView setPlayer:self.queuePlayer];
}

- (void)handlePlayerItemReachedEnd:(NSNotification *)notification {
    NSLog(@"Clip #%d finished playing", [self.queuePlayer.items indexOfObject:self.queuePlayer.currentItem]);
}

- (void)handlePlayerStalled:(NSNotification *)notification {
    NSLog(@"CLIP STALLED...");
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([object isKindOfClass:[AVPlayerItem class]]) {
        AVPlayerItem *item = (AVPlayerItem *)object;

        if ([keyPath isEqualToString:@"status"]) {
            switch (item.status) {
                case AVPlayerItemStatusFailed:
                    NSLog(@"player item status failed");
                break;
                case AVPlayerItemStatusReadyToPlay:
                    NSLog(@"player item status is ready to play");
                [self.queuePlayer play];
                break;
                case AVPlayerItemStatusUnknown:
                    NSLog(@"player item status is unknown");
                break;
            }
        }
        else if ([keyPath isEqualToString:@"playbackBufferEmpty"]) {
            if (item.playbackBufferEmpty) {
                NSLog(@"player item playback buffer is empty");
            }
        }
        else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
            NSLog(@"Loaded time range = %@", item.loadedTimeRanges);
            self.queuePlayer play];
        }
    }
}

person Raconteur    schedule 09.01.2013    source источник
comment
У кого-нибудь есть какие-либо мнения по этому поводу?? Это действительно изводит меня, и я знаю, что это не может быть вездесущим... или может?   -  person Raconteur    schedule 11.01.2013
comment
Да, у меня тоже полно таких проблем, как у тебя. Похоже, что, несмотря на то, что Apple заработала десятки миллиардов долларов, Apple вполне счастлива выпустить такое дерьмо для разработчиков. Какой смысл в очередном игроке, который задыхается в очереди?!!   -  person macduff    schedule 19.03.2019


Ответы (1)


Вы не должны изначально добавлять много AVPlayerItem к AVQueuePlayer, потому что они начнут буферизироваться одновременно, по усмотрению фреймворка.

Попробуйте загрузить один файл, а затем на KVO currentItem изменить очередь следующего, это может решить вашу проблему. Я использую это для достижения непрерывного воспроизведения.

person kain    schedule 11.01.2013
comment
Эй, Каин, не могли бы вы дать мне некоторые рекомендации (или, что еще лучше, пример кода) о том, как вы меняете очередь на следующий элемент? - person Raconteur; 12.01.2013
comment
У меня есть класс с массивом для хранения текущих медиафайлов, когда пришло время предварительно загрузить следующую дорожку в KVO, я просто запускаю метод для вычисления следующего индекса на основе предпочтений в случайном порядке/повторении. - person kain; 16.01.2013