Вопрос

Кто-нибудь знает, если AVQueuePlayer Начинает буферизировать следующий AVPlayerItem Когда текущий элемент собирается закончить играть?

Я знаю, что в документах нет ничего, чтобы предложить это, я спрашиваю в основном, если кто-то заметил такого поведения или нет.

Это было полезно?

Решение

Хорошо, я снова посмотрел на эту проблему и написал какой-код, чтобы проверить AVQueuePlayer.

Ответ Джольликокооа указал меня в правильном направлении, предлагая наблюдать за собственностью статуса на AVPlayerItem. Отказ Однако документация не означает, что это свойство (и это AVPlayerItemStatusReadyToPlay Значение в частности) может быть связано с буферией.

Однако AVPlayerItem's loadedTimeRanges Собственность кажется более связанным с буферией.

Делая KVO на этом массиве было немного сложнее - сам объект массива не изменится, только это предметы делают - поэтому я прибегал к печати его содержания каждую секунду.

То, что я узнал, это то, что несколько секунд в первом пункте очереди, loadedTimeRanges Для второго элемента отображается новый CMTimeRange С началом начала 0 и некоторая небольшая продолжительность. Продолжительность может увеличиваться до 60 или около того секунды, пока предыдущий элемент продолжает играть.

Краткий ответ: AVQueuePlayer Будет буфер следующий AVPlayerItem Во время воспроизведения текущего.

Другие советы

Начиная с iOS 5, кажется, что AvqueuePlayer больше не предварительно буферов. Он сделал предварительный буфер следующую дорожку в iOS 4.

Я не уверен, почему было изменение или если это даже преднамеренно на части Apple или просто ошибка. В любом случае, это боль, и я буду отправлять их об этом об этом.

Нашел работу вокруг !!! После многих часов поиска и неудачных тестов я нашел решение, которое работает на iOS 5 и выше.

Это будет воспроизводить файлы без какой-либо задержки между ними. Не так удобно, если вы хотите переключиться между файлами, но, безусловно, поставит все вместе для вас. Все еще возможно отслеживать, где каждый файл запускается, при добавлении AVURLASSET, держите переменную CMTime, что-то вроде:

NSValue *toJumpTo = [NSValue valueWithCMTime:composition.duration];
[array addObject:toJumpTo];

А потом просто пройдите через массив, проверяя текущую ценность времени и сравнивая его с помощью CMTimeCompare.

Редактировать: был найден на эта страница Видимый из веб-архива (ссылка в настоящее время указывает на спам).

Я экспериментировал с AvqueuePlayer, используя фильмы, предоставляемые сервером. В этом конкретном тесте я настроил QueuePlayer с AVPLAYERITEMS, инициализированными с URL-адресом двумя разными видеоабами разных типов. Один из них является .mp4-файл (прогрессивный загрузка), другой файл http .m3u8. Это действительно действует немного фанк, я должен сказать.

В зависимости от порядка, в котором я очередь файлы, я получаю совсем другое поведение. Если я начну с файла .mp4-файла, avplayerlayer уходит пусто и молчит, когда nextiTem запускает игрок (.m3u8-файл). Если я изменю порядок и начну с файла M3U8, AVPlayerLayer выходит пустой, но звук из второго файла играет нормально.

Мое впечатление, от того, что я видел до сих пор, это то, что AvqueuePlayer делает НЕТ Начните загрузку следующей AVPlayerItem до того, как текущий AVPlayerItem закончил играть. Но я мог бы ошибаться.

Быть продолженным, я думаю ...

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

Редактировать2: вместо этого добавляя мое объяснение, поскольку комментарий оставил меня без параметров форматирования. (Лучшая практика для этого приветствуется, если это плохой способ обрабатывать обновления ответов)

Во всяком случае, я помимо моих предметов помех добавляя наблюдение за свойство состояния с использованием KVO ...

[playerItem addObserver: self forKeyPath:@"status" options: 0 context: NULL];

Я также устанавливаю свой контроллер в качестве наблюдателя уведомления AVPLAYERITEM Avplayeritemdidplayteendtimenotification:

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

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

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

Однако! Я создаю массив с AVPLAYERITEMS, которые я использую для создания моего игрока. Чтение AVFoundation Docs на Avassets, я создаю впечатление, что это скачивает их активы асинхронно, но я все еще не уверен, когда эти загрузки инициируются IAPLAYERITEM. У меня все еще есть какое-то фамяное поведение, когда добавляю .m3u8-файл в очередь, что заставляет меня удивляться, если эти активы начнут загрузку на момент создания (кажется мне немного странным для меня).

Я сделал простую демонстрацию для вас и других, которые хотят сократить время буферизации каждого видео с URL.

ПРИМЕЧАНИЕ: Не знаю, что это правильно или нет, но он работает идеально для меня без какого-либо проблемы. Если кто-то знает больше или захочет улучшить код для лучшего результата, а затем добро пожаловать, чтобы изменить мой ответ.

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

Выполните следующие шаги.

1) в videoplayervc.h. файл.

#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>

@interface videoPlayerVC : UIViewController
{
    AVPlayerViewController *avPlyrViewController;
    AVPlayerItem *currentAVPlyrItem;

    int currentVideoNO;  // For current video track.
    NSMutableArray *arrOfAVPItems;
    NSMutableArray *arrOfPlyer;
}

2) в videoplayervc.m. файл

Здесь вы можете начать играть в видео на кнопку на кнопку. Ниже приведен метод действий кнопки.

-(void)clickOnPlayVideosImage:(UIButton *)sender
{
   // In my App. all video URLs is up to 15 second.
    currentVideoNO = 0;
    NSMutableArray *arrForVideoURL = [[NSMutableArray alloc]initWithObjects:
                                      [NSURL URLWithString:@"http://videos/url1.mov"],
                                      [NSURL URLWithString:@"http://videos/url2.mov"],
                                      [NSURL URLWithString:@"http://videos/url3.mov"],
                                      [NSURL URLWithString:@"http://videos/url3.mov"],
                                      [NSURL URLWithString:@"http://videos/url4.mov"],
                                      [NSURL URLWithString:@"http://videos/url5.mov"], nil];

    AVPlayerItem *thePlayerItemA = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:0]];
    AVPlayerItem *thePlayerItemB = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:1]];
    AVPlayerItem *thePlayerItemC = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:2]];
    AVPlayerItem *thePlayerItemD = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:3]];
    AVPlayerItem *thePlayerItemE = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:4]];
    AVPlayerItem *thePlayerItemF = [[AVPlayerItem alloc] initWithURL:[arrForVideoURL objectAtIndex:5]];

    if(arrOfAVPItems.count > 0)
       [arrOfAVPItems removeAllObjects];
    arrOfAVPItems = nil;

    if(arrOfPlyer.count > 0)
        [arrOfPlyer removeAllObjects];
    arrOfPlyer = nil;
    arrOfPlyer = [[NSMutableArray alloc] init];

    arrOfAVPItems = [NSMutableArray arrayWithObjects:thePlayerItemA, thePlayerItemB, thePlayerItemC, thePlayerItemD, thePlayerItemE, thePlayerItemF, nil]; // Add All items in the Array

    for(AVPlayerItem *myPlyrItem in arrOfAVPItems)
    {
        AVPlayer *videoPlayerNext = [AVPlayer playerWithPlayerItem:myPlyrItem]; /// Add item in the player
        [videoPlayerNext play]; 
        [videoPlayerNext pause];
        [arrOfPlyer addObject:videoPlayerNext]; /// Make Array of  "AVPlayer" just reduce buffering of each video. 
    }

    avPlyrViewController = [AVPlayerViewController new];
    avPlyrViewController.delegate = self;
    avPlyrViewController.player = (AVPlayer *)arrOfPlyer[0]; // Add first player from the Array.
    avPlyrViewController.showsPlaybackControls = YES;
    avPlyrViewController.allowsPictureInPicturePlayback = YES;
    avPlyrViewController.videoGravity = AVLayerVideoGravityResizeAspect;

    [self presentViewController:avPlyrViewController animated:YES completion:^{
        [self performSelector:@selector(playVideos) withObject:nil afterDelay:1];/// call method after one second for play video.

        UISwipeGestureRecognizer * swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleftToNextVideo:)];
        swipeleft.direction=UISwipeGestureRecognizerDirectionLeft;
        [avPlyrViewController.view addGestureRecognizer:swipeleft]; // Add left swipe for move on next video

        UISwipeGestureRecognizer * swiperight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeleftToPerviousVideo:)];
        swiperight.direction=UISwipeGestureRecognizerDirectionRight;
        [avPlyrViewController.view addGestureRecognizer:swiperight]; // Add right swipe for move on previous video
    }];
}

Теперь пиши playVideos код метода.

#pragma mark - AVPlayer Methods -

-(void)playVideos
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem]; // remove current "AVPlayerItem" from the notification observe.

    if(arrOfAVPItems.count > 0)
    {
        currentAVPlyrItem = (AVPlayerItem *)arrOfAVPItems[currentVideoNO]; // Add "AVPlayerItem" from the array.

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem]; // Add notification observer to indication current "AVPlayerItem" is finish.

        // pause and nil previous player if available.
        [avPlyrViewController.player pause];
        avPlyrViewController.player = nil;

        avPlyrViewController.player = (AVPlayer *)arrOfPlyer[currentVideoNO]; // add new player from the array
        [avPlyrViewController.player.currentItem seekToTime:kCMTimeZero]; // set for start video on initial position.
        [avPlyrViewController.player play]; // Play video

    }
}

Уведомление наблюдателя, чтобы указать видео заканчивается.

- (void)playerItemDidReachEnd:(NSNotification *)notification
{
    NSLog(@"IT REACHED THE END");
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:currentAVPlyrItem];  // remove current "AVPlayerItem" from the notification observe.

    [self swipeleftToNextVideo:nil]; // Call method for next video.
}

Метод играть в следующее видео

-(void)swipeleftToNextVideo:(UISwipeGestureRecognizer*)gestureRecognizer
{
    currentVideoNO++;
    if(currentVideoNO > (arrOfAVPItems.count -1))
        currentVideoNO = 0;

    NSLog(@"current - %d and last - %d", currentVideoNO, (int)(arrOfAVPItems.count -1));

    [self playVideos];
}

Метод для воспроизведения предыдущего видео.

-(void)swipeleftToPerviousVideo:(UISwipeGestureRecognizer*)gestureRecognizer
{
    currentVideoNO--;
    if(currentVideoNO < 0)
        currentVideoNO = (int)(arrOfAVPItems.count -1);

    NSLog(@"current - %d and last - %d", currentVideoNO, (int)(arrOfAVPItems.count -1));

    [self playVideos];
}

Следуй этим шагам. Если какие-либо сомнения, тогда прокомментируйте пожалуйста.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top