AVFoundationの基礎知識

## AVPlayerで動画を再生する
AVPlayerを使えばとても簡単に動画を再生することができます。

![iOSシミュレータのスクリーンショット 2014.04.19 19.06.27.png](https://qiita-image-store.s3.amazonaws.com/0/42112/8f68350d-85e6-22cc-c400-efd3edc266d7.png)

まずはAVPlayerを表示するためのViewを作成し、以下のメソッドを追加します。

` #import <AVFoundation/AVFoundation.h>
`

```objectivec:AVPlayerView.m

+(Class)layerClass
{
    return [AVPlayerLayer class];
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

```

` +(Class)layerClass`では、AVPlayerのレイヤークラスを返しています。
この後記述するViewControllerの中で生成したAVPlayerクラスとを紐づけるための処理です。※1

次にrootViewControllerとなるクラスを作成して下記のように記述します。

` #import <AVFoundation/AVFoundation.h>
`

```objectivec:ViewController.m

@class AVPlayer;

@interface ViewController ()
{
    AVPlayerView    *playerView;
    AVPlayer        *player;
}


- (void)viewDidLoad
{
    [super viewDidLoad];

    /*表示したいビデオのパスを取得
		アプリ内のドキュメントフォルダから動画ファイルを取得する前提です
	*/
    NSArray *array = NSSearchPathForDirectoriesInDomains(
                                                         NSDocumentDirectory,
                                                         NSUserDomainMask,
                                                         YES);

    NSString *dirPath = [array objectAtIndex:0];
    NSString *path = [dirPath stringByAppendingPathComponent:@"movie.MOV"];
    NSURL *url = [NSURL fileURLWithPath:path];
    
    //プレイヤーを設定
    float playerHeight = self.view.frame.size.height-(self.view.frame.size.height/2);
    player = [[AVPlayer alloc]initWithURL:url];
    playerView = [[AVPlayerView alloc]initWithFrame:CGRectMake(0,
                                                               0,
                                                               self.view.frame.size.width,
                                                               playerHeight)];
	//*1で説明したAVPlayerとViewとを紐づける処理
    [(AVPlayerLayer*)playerView.layer setPlayer:player];
    
    [self.view addSubview:playerView];
    [self.view bringSubviewToFront:playerView];
    
    //ステータスの変更を受け取るオブサーバの設定
    [player addObserver:self
             forKeyPath:@"status"
                options:NSKeyValueObservingOptionNew
                context:&player];
    
}


#pragma mark - ステータス変更時に呼ばれるオブサーバ（１）
-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(NSDictionary *)change
                      context:(void *)context
{
    //再生準備が整い次第、動画を再生させる。
    if([player status] == AVPlayerItemStatusReadyToPlay){
        
        [player removeObserver:self forKeyPath:@"status"];
        
        [player play];

        return;
    }
    
    [super observeValueForKeyPath:keyPath
                         ofObject:object
                           change:change
                          context:context];
}

```

（１）オブサーバを設定することにより、動画のステータスを取得したタイミングで処理を行うことができます。
取得できるステータスは次の通りです。

**AVPlayerItemStatus**

| Status |  |
|:-----------|------------:|
| AVPlayerItemStatusReadyToPlay |   再生の準備ができた場合 |
| AVPlayerItemStatusFailed      |   再生ができなかった場合 |
| AVPlayerItemStatusUnknown     |　取得に失敗した場合　　| 


あとは任意のタイミングで、再生開始と一時停止のメソッドを呼んであげるだけ。

`[player play];`			再生開始
`[player pause];`			一時停止
`[player setRate:2.0f];`	倍速再生
※倍速再生の設定を行った後に[player play]を実行すると通常再生となるので注意が必要です。

以上で、動画再生が可能となります。

なお、動画再生時間を表すスライダーを実装する場合に必要な情報は下記のように取得できます。
※UISliderの実装部分は割愛しています。

**UISliderのmaximumValue（最大値）に設定する値を取得する**

```objectivec:
        AVPlayerItem *item = [player currentItem];
        CMTime cmTime = item.asset.duration;
        Float64 sec = CMTimeGetSeconds(cmTime);

```

**動画再生時間をリアルタイムに取得してスライダーを更新させる**

```objectivec:

id timeObserver;
-(void)MoviePlay
{
	//0.5秒おきにスライダーを更新する
    CMTime time = CMTimeMakeWithSeconds(0.5f, NSEC_PER_SEC);
    __block ViewController *blockself = self; //ARCを使用している場合
    timeObserver = [player addPeriodicTimeObserverForInterval:time
                                                        queue:dispatch_get_main_queue()
                                                   usingBlock:^(CMTime time) {
                                                       Float64 sec = CMTimeGetSeconds(time);
                                                       [blockself upDateTimeSlider:sec];
												//ARC不使用時は[self upDateTimeSlider:sec];
                                                   }];
}

-(void)upDateTimeSlider:(Float64)sec
{
    timeSlider.value = sec;
}

//オブサーバは任意のタイミングでリムーブする
-(void)viewDidDisappear:(BOOL)animated
{
    if(timeObserver){
        [player removeTimeObserver:timeObserver];
    }

}
        
```

**スライダーからの再生時間情報を動画に反映する**

```objectivec:

#pragma mark - スライダーの値が変更されたときに呼ばれるメソッド
- (void)slider_ValueChanged:(id)sender
{
    UISlider *slider = sender;
    CMTime time = CMTimeMakeWithSeconds(slider.value, NSEC_PER_SEC);
    [player seekToTime:time];

}

```