Воспроизведение
Для управления воспроизведением активов Вы используете AVPlayer
объект. Во время воспроизведения можно использовать AVPlayerItem
экземпляр для управления состоянием представления актива в целом, и AVPlayerItemTrack
объект управлять состоянием представления отдельной дорожки. Для отображения видео Вы используете AVPlayerLayer
объект.
Игра активов
Проигрыватель является объектом контроллера, который Вы используете для управления воспроизведением актива, например запускаясь и останавливая воспроизведение, и ища на определенное время. Вы используете экземпляр AVPlayer
играть единственный актив. Можно использовать AVQueuePlayer
возразите для игры многих элементов в последовательности (AVQueuePlayer
подкласс AVPlayer
). На OS X у Вас есть опция использования платформы Набора AV AVPlayerView
класс для воспроизведения содержания в представлении.
Проигрыватель предоставляет Вам информацию о состоянии воспроизведения так, если Вы должны, можно синхронизировать пользовательский интерфейс с состоянием проигрывателя. Вы обычно прямой вывод проигрывателя к специализированному Базовому Слою анимации (экземпляр AVPlayerLayer
или AVSynchronizedLayer
). Для узнавания больше об уровнях см. Базовое Руководство по программированию Анимации.
Несмотря на то, что в конечном счете Вы хотите играть актив, Вы не обеспечиваете активы непосредственно для AVPlayer
объект. Вместо этого Вы обеспечиваете экземпляр AVPlayerItem
. Элемент проигрывателя управляет состоянием представления актива, с которым это связано. Элемент проигрывателя содержит дорожки элемента проигрывателя — экземпляры AVPlayerItemTrack
— это соответствует дорожкам в активе.
Эта абстракция означает, что можно играть данный актив с помощью различных проигрывателей одновременно, но представленный по-разному каждым проигрывателем. Используя дорожки элемента, можно, например, отключить определенную дорожку во время воспроизведения (например, Вы не могли бы хотеть играть звуковой компонент).
Можно инициализировать элемент проигрывателя с существующим активом, или можно инициализировать элемент проигрывателя непосредственно от URL так, чтобы можно было играть ресурс в определенном расположении (AVPlayerItem
тогда создаст и сконфигурирует актив для ресурса). Как с AVAsset
, Тем не менее, просто инициализация элемента проигрывателя не обязательно означает, что это готово к непосредственному воспроизведению. Можно наблюдать (использующий наблюдение значения ключа) элемент status
свойство для определения, если и когда это готово играть.
Обработка различных типов актива
Путем Вы конфигурируете актив для воспроизведения, может зависеть от вида актива, который Вы хотите играть. Вообще говоря существует два основных типа: основанные на файле активы, к которым у Вас есть произвольный доступ (такой как от локального файла, рулона камеры или Библиотеки Носителей), и активы на основе потоков (HTTP Живой Формат потоковой передачи).
Загрузить и играть основанный на файле актив. Существует несколько шагов к игре основанного на файле актива:
Создайте использование актива
AVURLAsset
.Создайте экземпляр
AVPlayerItem
использование актива.Свяжите элемент с экземпляром
AVPlayer
.Ожидайте до элемента
status
свойство указывает, что это готово играть (обычно, Вы используете наблюдение значения ключа для получения уведомления, когда состояние изменяется).
Этот подход проиллюстрирован в Соединении Всего этого: Игра Видеофайла Используя AVPlayerLayer.
Создать и подготовить прямую трансляцию HTTP к воспроизведению. Инициализируйте экземпляр AVPlayerItem
использование URL. (Вы не можете непосредственно создать AVAsset
экземпляр для представления носителей в Прямой трансляции HTTP.)
NSURL *url = [NSURL URLWithString:@"<#Live stream URL#>]; |
// You may find a test stream at <http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8>. |
self.playerItem = [AVPlayerItem playerItemWithURL:url]; |
[playerItem addObserver:self forKeyPath:@"status" options:0 context:&ItemStatusContext]; |
self.player = [AVPlayer playerWithPlayerItem:playerItem]; |
При соединении элемента проигрывателя с проигрывателем он начинает становиться готовым играть. Когда это готово играть, элемент проигрывателя создает AVAsset
и AVAssetTrack
экземпляры, которые можно использовать для проверки содержания прямой трансляции.
Для получения продолжительности элемента потоковой передачи можно наблюдать duration
свойство на элементе проигрывателя. Когда элемент становится готовым играть, это свойство обновления к правильному значению для потока.
Если Вы просто хотите играть прямую трансляцию, можно срезать путь и создать проигрыватель непосредственно с помощью использования URL следующий код:
self.player = [AVPlayer playerWithURL:<#Live stream URL#>]; |
[player addObserver:self forKeyPath:@"status" options:0 context:&PlayerStatusContext]; |
Как с активами и элементами, инициализируя проигрыватель не означает, что это готово к воспроизведению. Необходимо наблюдать проигрыватель status
свойство, изменяющееся на AVPlayerStatusReadyToPlay
когда это готово играть. Можно также наблюдать currentItem
свойство для доступа к элементу проигрывателя, создаваемому для потока.
Если Вы не знаете, какой URL Вы имеете, выполняете эти шаги:
Попытайтесь инициализировать
AVURLAsset
с помощью URL затем загрузитеtracks
ключ.Если дорожки загружаются успешно, то Вы создаете элемент проигрывателя для актива.
Если 1 сбой, создайте
AVPlayerItem
непосредственно от URL.Наблюдайте проигрыватель
status
свойство, чтобы определить, становится ли это играемым.
Если любой маршрут успешно выполняется, Вы заканчиваете с элементом проигрывателя, который можно тогда связать с проигрывателем.
Игра элемента
Для запуска воспроизведения Вы отправляете a play
обменивайтесь сообщениями к проигрывателю.
- (IBAction)play:sender { |
[player play]; |
} |
В дополнение к простой игре можно управлять различными аспектами воспроизведения, такими как уровень и расположение playhead. Можно также контролировать состояние игры проигрывателя; это полезно, если Вы хотите, например, синхронизируйтесь, пользовательский интерфейс к состоянию представления актива — посмотрите Контролирующее Воспроизведение.
Изменение скорости воспроизведения
Вы изменяете уровень воспроизведения путем установки проигрывателя rate
свойство.
aPlayer.rate = 0.5; |
aPlayer.rate = 2.0; |
Значение 1,0 означает “игру на естественном уровне текущего элемента”. Установка уровня к 0,0 совпадает с приостанавливающимся воспроизведением — можно также использовать pause
.
Элементы, поддерживающие обратное воспроизведение, могут использовать свойство уровня с отрицательным числом для установки уровня обратного воспроизведения. Вы определяете тип обратной игры, поддерживающейся при помощи playerItem свойств canPlayReverse
(поддерживает значение уровня-1.0), canPlaySlowReverse
(уровни поддержек между 0,0 и 1.0) и canPlayFastReverse
(уровень поддержек оценивает меньше чем-1.0).
Поиск — менять местоположение Playhead
Для перемещения playhead в определенное время Вы обычно используете seekToTime:
следующим образом:
CMTime fiveSecondsIn = CMTimeMake(5, 1); |
[player seekToTime:fiveSecondsIn]; |
seekToTime:
метод, однако, настраивается для производительности, а не точности. Если необходимо переместить playhead точно, вместо этого Вы используете seekToTime:toleranceBefore:toleranceAfter:
как в следующем фрагменте кода:
CMTime fiveSecondsIn = CMTimeMake(5, 1); |
[player seekToTime:fiveSecondsIn toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; |
Используя допуск нуля может потребовать, чтобы платформа декодировала большой объем данных. Необходимо использовать нуль, только если Вы, например, пишете сложные носители, редактируя приложение, требующее точного управления.
После воспроизведения голова проигрывателя установлена до конца элемента и дальнейших вызовов play
не имейте никакого эффекта. Для расположения playhead назад в начале элемента можно зарегистрироваться для получения AVPlayerItemDidPlayToEndTimeNotification
уведомление от элемента. В методе обратного вызова уведомления Вы вызываете seekToTime:
с параметром kCMTimeZero
.
// Register with the notification center after creating the player item. |
[[NSNotificationCenter defaultCenter] |
addObserver:self |
selector:@selector(playerItemDidReachEnd:) |
name:AVPlayerItemDidPlayToEndTimeNotification |
object:<#The player item#>]; |
- (void)playerItemDidReachEnd:(NSNotification *)notification { |
[player seekToTime:kCMTimeZero]; |
} |
Игра многократных элементов
Можно использовать AVQueuePlayer
возразите для игры многих элементов в последовательности. AVQueuePlayer
класс является подклассом AVPlayer
. Вы инициализируете проигрыватель очереди с массивом элементов проигрывателя.
NSArray *items = <#An array of player items#>; |
AVQueuePlayer *queuePlayer = [[AVQueuePlayer alloc] initWithItems:items]; |
Можно тогда играть использование очереди play
, так же, как Вы были бы AVPlayer
объект. Проигрыватель очереди играет каждый элемент поочередно. Если Вы хотите пропустить к следующему элементу, Вы отправляете проигрыватель очереди advanceToNextItem
сообщение.
Можно изменить использование очереди insertItem:afterItem:
, removeItem:
, и removeAllItems
. При добавлении нового элемента необходимо обычно проверять, может ли он быть вставлен в очередь, с помощью canInsertItem:afterItem:
. Вы передаете nil
как второй параметр тесту, может ли новый элемент быть добавлен очереди.
AVPlayerItem *anItem = <#Get a player item#>; |
if ([queuePlayer canInsertItem:anItem afterItem:nil]) { |
[queuePlayer insertItem:anItem afterItem:nil]; |
} |
Контроль воспроизведения
Можно контролировать много аспектов и состояния представления проигрывателя и играемого элемента проигрывателя. Это особенно полезно для изменений состояния, не находящихся под Вашим прямым управлением. Например:
Если пользователь использует многозадачность для переключения на различное приложение, проигрыватель
rate
свойство спадет0.0
.Если Вы играете удаленные носители, элемент проигрывателя
loadedTimeRanges
иseekableTimeRanges
свойства изменятся, поскольку больше данных становится доступным.Эти свойства говорят Вам, какие части временной шкалы элемента проигрывателя доступны.
Проигрыватель
currentItem
изменения свойства как элемент проигрывателя создаются для прямой трансляции HTTP.Элемент проигрывателя
tracks
свойство может измениться при игре прямой трансляции HTTP.Если поток предлагает различные кодировки для содержания, это может произойти; если проигрыватель переключается на различное кодирование, дорожки изменяются.
Проигрыватель или элемент проигрывателя
status
если воспроизведение перестало работать по некоторым причинам, свойство может измениться.
Можно использовать наблюдение значения ключа для наблюдения изменений к значениям этих свойств.
Реакция на изменение в состоянии
Когда проигрыватель или изменения состояния элемента проигрывателя, это испускает значение ключа, наблюдая уведомление изменения. Если объект неспособен играть по некоторым причинам (например, если мультимедийные службы сбрасываются), изменения состояния в AVPlayerStatusFailed
или AVPlayerItemStatusFailed
как надлежащий. В этой ситуации, значении объекта error
свойство изменяется на ошибочный объект, описывающий, почему объект больше не не быть в состоянии играть.
Основа AV не указывает то, что распараллеливает это, уведомление переслано. Если Вы хотите обновить пользовательский интерфейс, необходимо удостовериться, что любой соответствующий код вызывается на основной поток. Этот пример использование dispatch_async
выполнить код основного потока.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object |
change:(NSDictionary *)change context:(void *)context { |
if (context == <#Player status context#>) { |
AVPlayer *thePlayer = (AVPlayer *)object; |
if ([thePlayer status] == AVPlayerStatusFailed) { |
NSError *error = [<#The AVPlayer object#> error]; |
// Respond to error: for example, display an alert sheet. |
return; |
} |
// Deal with other status change if appropriate. |
} |
// Deal with other change notifications if appropriate. |
[super observeValueForKeyPath:keyPath ofObject:object |
change:change context:context]; |
return; |
} |
Отслеживание готовности к дисплею
Можно наблюдать AVPlayerLayer
объект readyForDisplay
свойство, которое будет уведомлено, когда уровень имеет видимое пользователем содержание. В частности Вы могли бы вставить уровень проигрывателя в дерево уровня только, когда существует что-то для пользователя, чтобы посмотреть на и затем выполнить переход от.
Отслеживание времени
Отслеживать изменения в позиции playhead в AVPlayer
объект, можно использовать addPeriodicTimeObserverForInterval:queue:usingBlock:
или addBoundaryTimeObserverForTimes:queue:usingBlock:
. Вы могли бы сделать это к, например, обновить Ваш пользовательский интерфейс с информацией в истекшее время или время, оставаясь, или выполнять некоторую другую синхронизацию пользовательского интерфейса.
С
addPeriodicTimeObserverForInterval:queue:usingBlock:
, блок, который Вы обеспечиваете, вызывается в интервале, который Вы указываете, если время переходит, и когда воспроизведение запускается или останавливается.С
addBoundaryTimeObserverForTimes:queue:usingBlock:
, Вы передаете массивCMTime
структуры, содержавшиеся вNSValue
объекты. Блок, который Вы обеспечиваете, вызывается каждый раз, когда пересечено любое из тех времен.
Оба из методов возвращают непрозрачный объект, служащий наблюдателем. Необходимо сохранить сильную ссылку к возвращенному объекту, пока Вы хотите, чтобы блок наблюдения времени был вызван проигрывателем. Необходимо также сбалансировать каждый вызов этих методов с соответствующим вызовом к removeTimeObserver:
.
С обоими из этих методов Основа AV не гарантирует, что вызвала Ваш блок для каждого интервала, или граница передала. Если выполнение ранее вызванного блока не завершилось, основа AV не вызывает блок. Необходимо удостовериться, поэтому, что работа, которую Вы выполняете в блоке, не чрезмерно облагает налогом систему.
// Assume a property: @property (strong) id playerObserver; |
Float64 durationSeconds = CMTimeGetSeconds([<#An asset#> duration]); |
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 1); |
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 1); |
NSArray *times = @[[NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird]]; |
self.playerObserver = [<#A player#> addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{ |
NSString *timeDescription = (NSString *) |
CFBridgingRelease(CMTimeCopyDescription(NULL, [self.player currentTime])); |
NSLog(@"Passed a boundary at %@", timeDescription); |
}]; |
Достижение конца элемента
Можно зарегистрироваться для получения AVPlayerItemDidPlayToEndTimeNotification
уведомление когда элемент проигрывателя завершил воспроизведение.
[[NSNotificationCenter defaultCenter] addObserver:<#The observer, typically self#> |
selector:@selector(<#The selector name#>) |
name:AVPlayerItemDidPlayToEndTimeNotification |
object:<#A player item#>]; |
Соединение всего этого: игра видеофайла Используя AVPlayerLayer
Этот краткий пример кода иллюстрирует, как можно использовать AVPlayer
возразите для игры видеофайла. Это показывает как:
Сконфигурируйте представление для использования
AVPlayerLayer
уровеньСоздайте
AVPlayer
объектСоздайте
AVPlayerItem
объект для основанного на файле актива и наблюдения значения ключа использования для наблюдения его состоянияРеагируйте на элемент, становящийся готовыми играть путем включения кнопки
Играйте элемент и затем восстановите голову проигрывателя к началу
Для концептуального введения в воспроизведение пропустите к Игре Активов.
Представление проигрывателя
Для игры визуального компонента актива Вам нужно представление, содержащее AVPlayerLayer
уровень тот, к который вывод AVPlayer
объект может быть направлен. Можно создать простой подкласс UIView
размещать это:
#import <UIKit/UIKit.h> |
#import <AVFoundation/AVFoundation.h> |
@interface PlayerView : UIView |
@property (nonatomic) AVPlayer *player; |
@end |
@implementation PlayerView |
+ (Class)layerClass { |
return [AVPlayerLayer class]; |
} |
- (AVPlayer*)player { |
return [(AVPlayerLayer *)[self layer] player]; |
} |
- (void)setPlayer:(AVPlayer *)player { |
[(AVPlayerLayer *)[self layer] setPlayer:player]; |
} |
@end |
Простой контроллер представления
Предположите, что у Вас есть простой контроллер представления, объявленный следующим образом:
@class PlayerView; |
@interface PlayerViewController : UIViewController |
@property (nonatomic) AVPlayer *player; |
@property (nonatomic) AVPlayerItem *playerItem; |
@property (nonatomic, weak) IBOutlet PlayerView *playerView; |
@property (nonatomic, weak) IBOutlet UIButton *playButton; |
- (IBAction)loadAssetFromFile:sender; |
- (IBAction)play:sender; |
- (void)syncUI; |
@end |
syncUI
метод синхронизирует состояние кнопки с состоянием проигрывателя:
- (void)syncUI { |
if ((self.player.currentItem != nil) && |
([self.player.currentItem status] == AVPlayerItemStatusReadyToPlay)) { |
self.playButton.enabled = YES; |
} |
else { |
self.playButton.enabled = NO; |
} |
} |
Можно вызвать syncUI
в контроллере представления viewDidLoad
метод для обеспечения непротиворечивого пользовательского интерфейса, когда представление сначала выведено на экран.
- (void)viewDidLoad { |
[super viewDidLoad]; |
[self syncUI]; |
} |
Другие свойства и методы описаны в остающихся разделах.
Создание актива
Вы создаете актив из использования URL AVURLAsset
. (Следующий пример предполагает, что Ваш проект содержит подходящий ресурс видео.)
- (IBAction)loadAssetFromFile:sender { |
NSURL *fileURL = [[NSBundle mainBundle] |
URLForResource:<#@"VideoFileName"#> withExtension:<#@"extension"#>]; |
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil]; |
NSString *tracksKey = @"tracks"; |
[asset loadValuesAsynchronouslyForKeys:@[tracksKey] completionHandler: |
^{ |
// The completion block goes here. |
}]; |
} |
В блоке завершения Вы создаете экземпляр AVPlayerItem
для актива и набора это в качестве проигрывателя для представления проигрывателя. Как с созданием актива, просто создавая элемент проигрывателя не означает, что это готово использовать. Для определения, когда это готово играть можно наблюдать элемент status
свойство. Необходимо сконфигурировать это наблюдение прежде, чем связать экземпляр элемента проигрывателя с самим проигрывателем.
Вы инициировали подготовку элемента проигрывателя для игры при соединении ее с проигрывателем.
// Define this constant for the key-value observation context. |
static const NSString *ItemStatusContext; |
// Completion handler block. |
dispatch_async(dispatch_get_main_queue(), |
^{ |
NSError *error; |
AVKeyValueStatus status = [asset statusOfValueForKey:tracksKey error:&error]; |
if (status == AVKeyValueStatusLoaded) { |
self.playerItem = [AVPlayerItem playerItemWithAsset:asset]; |
// ensure that this is done before the playerItem is associated with the player |
[self.playerItem addObserver:self forKeyPath:@"status" |
options:NSKeyValueObservingOptionInitial context:&ItemStatusContext]; |
[[NSNotificationCenter defaultCenter] addObserver:self |
selector:@selector(playerItemDidReachEnd:) |
name:AVPlayerItemDidPlayToEndTimeNotification |
object:self.playerItem]; |
self.player = [AVPlayer playerWithPlayerItem:self.playerItem]; |
[self.playerView setPlayer:self.player]; |
} |
else { |
// You should deal with the error appropriately. |
NSLog(@"The asset's tracks were not loaded:\n%@", [error localizedDescription]); |
} |
}); |
Реакция на изменение состояния элемента проигрывателя
Когда состояние элемента проигрывателя изменяется, контроллер представления получает значение ключа, наблюдая уведомление изменения. Основа AV не указывает то, что распараллеливает это, уведомление переслано. Если Вы хотите обновить пользовательский интерфейс, необходимо удостовериться, что любой соответствующий код вызывается на основной поток. Этот пример использование dispatch_async
поставить сообщение в очередь на основном потоке для синхронизации пользовательского интерфейса.
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object |
change:(NSDictionary *)change context:(void *)context { |
if (context == &ItemStatusContext) { |
dispatch_async(dispatch_get_main_queue(), |
^{ |
[self syncUI]; |
}); |
return; |
} |
[super observeValueForKeyPath:keyPath ofObject:object |
change:change context:context]; |
return; |
} |
Игра элемента
Игра элемента включает отправку a play
обменивайтесь сообщениями к проигрывателю.
- (IBAction)play:sender { |
[player play]; |
} |
Элемент играется только один раз. После воспроизведения голова проигрывателя установлена до конца элемента и дальнейших вызовов play
метод не будет иметь никакого эффекта. Для расположения playhead назад в начале элемента можно зарегистрироваться для получения AVPlayerItemDidPlayToEndTimeNotification
от элемента. В методе обратного вызова уведомления вызвать seekToTime:
с параметром kCMTimeZero
.
// Register with the notification center after creating the player item. |
[[NSNotificationCenter defaultCenter] |
addObserver:self |
selector:@selector(playerItemDidReachEnd:) |
name:AVPlayerItemDidPlayToEndTimeNotification |
object:[self.player currentItem]]; |
- (void)playerItemDidReachEnd:(NSNotification *)notification { |
[self.player seekToTime:kCMTimeZero]; |
} |