Воспроизведение

Для управления воспроизведением активов Вы используете AVPlayer объект. Во время воспроизведения можно использовать AVPlayerItem экземпляр для управления состоянием представления актива в целом, и AVPlayerItemTrack объект управлять состоянием представления отдельной дорожки. Для отображения видео Вы используете AVPlayerLayer объект.

Игра активов

Проигрыватель является объектом контроллера, который Вы используете для управления воспроизведением актива, например запускаясь и останавливая воспроизведение, и ища на определенное время. Вы используете экземпляр AVPlayer играть единственный актив. Можно использовать AVQueuePlayer возразите для игры многих элементов в последовательности (AVQueuePlayer подкласс AVPlayer). На OS X у Вас есть опция использования платформы Набора AV AVPlayerView класс для воспроизведения содержания в представлении.

Проигрыватель предоставляет Вам информацию о состоянии воспроизведения так, если Вы должны, можно синхронизировать пользовательский интерфейс с состоянием проигрывателя. Вы обычно прямой вывод проигрывателя к специализированному Базовому Слою анимации (экземпляр AVPlayerLayer или AVSynchronizedLayer). Для узнавания больше об уровнях см. Базовое Руководство по программированию Анимации.

Несмотря на то, что в конечном счете Вы хотите играть актив, Вы не обеспечиваете активы непосредственно для AVPlayer объект. Вместо этого Вы обеспечиваете экземпляр AVPlayerItem. Элемент проигрывателя управляет состоянием представления актива, с которым это связано. Элемент проигрывателя содержит дорожки элемента проигрывателя — экземпляры AVPlayerItemTrack— это соответствует дорожкам в активе.

../Art/avplayerLayer_2x.png

Эта абстракция означает, что можно играть данный актив с помощью различных проигрывателей одновременно, но представленный по-разному каждым проигрывателем. Используя дорожки элемента, можно, например, отключить определенную дорожку во время воспроизведения (например, Вы не могли бы хотеть играть звуковой компонент).

../Art/playerObjects_2x.png

Можно инициализировать элемент проигрывателя с существующим активом, или можно инициализировать элемент проигрывателя непосредственно от URL так, чтобы можно было играть ресурс в определенном расположении (AVPlayerItem тогда создаст и сконфигурирует актив для ресурса). Как с AVAsset, Тем не менее, просто инициализация элемента проигрывателя не обязательно означает, что это готово к непосредственному воспроизведению. Можно наблюдать (использующий наблюдение значения ключа) элемент status свойство для определения, если и когда это готово играть.

Обработка различных типов актива

Путем Вы конфигурируете актив для воспроизведения, может зависеть от вида актива, который Вы хотите играть. Вообще говоря существует два основных типа: основанные на файле активы, к которым у Вас есть произвольный доступ (такой как от локального файла, рулона камеры или Библиотеки Носителей), и активы на основе потоков (HTTP Живой Формат потоковой передачи).

Загрузить и играть основанный на файле актив. Существует несколько шагов к игре основанного на файле актива:

Этот подход проиллюстрирован в Соединении Всего этого: Игра Видеофайла Используя 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 Вы имеете, выполняете эти шаги:

  1. Попытайтесь инициализировать AVURLAsset с помощью URL затем загрузите tracks ключ.

    Если дорожки загружаются успешно, то Вы создаете элемент проигрывателя для актива.

  2. Если 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];
}

Контроль воспроизведения

Можно контролировать много аспектов и состояния представления проигрывателя и играемого элемента проигрывателя. Это особенно полезно для изменений состояния, не находящихся под Вашим прямым управлением. Например:

Можно использовать наблюдение значения ключа для наблюдения изменений к значениям этих свойств.

Реакция на изменение в состоянии

Когда проигрыватель или изменения состояния элемента проигрывателя, это испускает значение ключа, наблюдая уведомление изменения. Если объект неспособен играть по некоторым причинам (например, если мультимедийные службы сбрасываются), изменения состояния в 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 объект может быть направлен. Можно создать простой подкласс 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];
}