[Objective-C] AVPlayerを使って動画を再生する


`AVFoundation`を使います。

## セットアップ

`AVPlayer`が動画を再生するコンポーネントとなります。
これを適切にセットアップし、ビューに乗せてやります。

### AVPlayerViewの実装

```objc:AVPlayerView.h
#import <AVFoundation/AVFoundation.h>

@interface AVPlayerView : UIView

@end
```

```objc:AVPlayerView.m
@implementation AVPlayerView

+ (Class)layerClass
{
    return AVPlayerLayer.class;
}

@end
```

まずは`AVPlayerView`を定義して、その`layer`を`AVPlayerLayer`になるよう実装します。


### ViewControllerの実装

次に、上記ビューを利用するViewControllerを実装します。

```objc:properties
@interface ViewController ()

@property (nonatomic, strong) AVPlayerView *playerView;
@property (nonatomic, strong) AVPlayer     *player;

@end
```

```objc
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 動画のURLを生成
    NSString *urlString = @"https://example.com/hoge.mp4";
    NSURL *url = [NSURL URLWithString:urlString];
    
    // URLを元に`AVPlayer`を生成
    self.player = [[AVPlayer alloc] initWithURL:url];
    
    // viewのlayerに`AVPlayer`のインスタンスをセット
    self.playerView = [[AVPlayerView alloc] initWithFrame:self.view.frame];
    [(AVPlayerLayer*)self.playerView.layer setPlayer:self.player];
    
    // 該当のビューを表示
    [self.view addSubview:self.playerView];
    
    // `status`の変化を監視
    [self.player addObserver:self
                  forKeyPath:@"status"
                     options:NSKeyValueObservingOptionNew
                     context:nil];
}

// `status`の値を監視して、再生可能になったら再生
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if (self.player.status == AVPlayerItemStatusReadyToPlay) {
        [self.player removeObserver:self forKeyPath:@"status"];
        [self.player play];
        return;
    }
    
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
```


-------------------------------------------

## 動画再生中に一定時間おきに経過時間を取得する

`addPeriodicTimeObserverForInterval:queue:usingBlock:`を使いintervalを`CMTime`で指定することで、その時間間隔でblocksの中身が呼ばれるようになります。

ちなみに`CMTime`については[こちらを参考](http://blog.livedoor.jp/sen_ritsu/archives/51342320.html)にしました。

```objc
CMTime time = CMTimeMake(200, 600);
[self.player addPeriodicTimeObserverForInterval:time queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
	NSLog(@"Time: %f", CMTimeGetSeconds(time));
}];
```


-------------------------------------------

## 動画の再生が終わったことを検知する

`NSNotificationCenter`を利用して以下のようにします。

```objc:detect-end
// 検知するためには`AVPlayerItem`クラスを使う必要があります。
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:url];

self.player = [[AVPlayer alloc] initWithPlayerItem:playerItem];

[NSNotificationCenter.defaultCenter addObserver:self
                                       selector:@selector(handleEndPlay:)
                                           name:AVPlayerItemDidPlayToEndTimeNotification
                                         object:playerItem];
```

ちなみに、`AVPlayer`を`initWithURL`で生成した場合はこの通知が行われないので注意が必要です。
終わりを検知したい場合は`AVPlayerItem`クラスを使って動画の再生を行います。


-------------------------------------------

## 参考記事

- [AVFoundationの基礎知識](http://qiita.com/Yuchi/items/1f7a4658c1ee396adfa0)
- [AVPlayer Class Reference | Apple](https://developer.apple.com/library//ios/documentation/AVFoundation/Reference/AVPlayer_Class/index.html)