Предварительная буферизация для AVQueuePlayer

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

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

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

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

Однако свойство loadedTimeRanges от 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.

Редактировать: было найдено на http://www.developers-life.com/avplayer-looping-video-without-hiccupdelays.html но, как отметил в комментариях Стефан Кендалл, теперь это спам-сайт. Думал, что я оставлю ссылку для целей присвоения, но не посещать ее!

Я экспериментировал с AVQueuePlayer, используя фильмы, предоставляемые сервером. В этом конкретном тесте я установил queuePlayer с AVPlayerItems, инициализированными URL-адресами, двумя различными видео-активами разных типов. Один – .mp4-файл (прогрессивная загрузка), другой – файл http-streaming .m3u8. Должен сказать, он действует немного фанк.

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

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

Продолжение следует …

Edit: Хорошо, поэтому я провел еще несколько тестов, и кажется, что следующие предметы начинают загружаться до того, как последний элемент закончит игру. См. Сообщение ниже. Обводьте «НЕ» …

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

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

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

Я также установил мой controller в качестве наблюдателя AVPlayerItem Notification AVPlayerItemDidPlayToEndTimeNotification :

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

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

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

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

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

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

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

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

1) В файле videoPlayerVC.h .

 #import  #import  @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 метода 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]; } 

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

  • iPhone: как передавать данные между несколькими Viewcontrollers в приложении Tabbar
  • Добавить анимированное изображение Gif в Iphone UIImageView
  • Проверка подлинности электронной почты на textField в iPhone sdk
  • Преобразование миллисекунд в NSDate
  • Должен ли я использовать NSUserDefaults или plist для хранения данных?
  • XCode 4 зависает при «Присоединении к (имя приложения)»
  • Есть ли документальный способ настройки ориентации iPhone?
  • CALayer: добавить границу только с одной стороны
  • Как проверить локальный Wi-Fi (не только сотовую связь) с помощью iPhone SDK?
  • Прокрутка двумя пальцами с помощью UIScrollView
  • Остановить UIWebView от «подпрыгивания» по вертикали?
  • Давайте будем гением компьютера.