iosの動画再生周りの基礎を調べた 

# 概要

iosの動画再生周りが面倒で初心者向けのまとまった記事が無かったので調べた。
詳細はドキュメントを見れば大体分かる。

[AVFoundation | Apple Developer Documentation](https://developer.apple.com/documentation/avfoundation)

※ 2018年8月7日(火) 時点での内容、ios11 + Swift4 で動作確認済み。

# AVFoundationとAVKit

> AVFoundationは、時間ベースのオーディオビジュアルメディアの再生と作成に使用できるフレームワークで、時間ベースのオーディオビジュアルデータに関する作業を細かいレベルで行うためのObjective-Cのインターフェイスを提供します。たとえば、メディアファイルの検査、作成、編集、再エンコードなどができます。デバイスから入力ストリームを取得して、リアルタイムでキャプチャ中および再生中のビデオを操作することもできます。図 I-1にiOSのアーキテクチャを示します。 
※ [AVFoundation プログラミングガイド](https://developer.apple.com/jp/documentation/AVFoundationPG.pdf) より引用

<img width="674" alt="スクリーンショット 2018-08-07 22.31.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/44388/bf67e317-ce74-8550-b667-fce33bc5ee06.png">


Objective-C とあるが、Swiftも同じ。
AVFoundation が低レイヤーで動画再生周りを支え、それを扱いやすくしたのが UIKit よりも高いレイヤーに位置している AVKit という解釈であっていると思う。(実際自分が調べた動画再生関連のクラスを利用する時は AVKit しか import していない)

詳細は [AVPlayer | Apple Developer Documentation](https://developer.apple.com/documentation/avfoundation/avplayer) に書いてあった。

## AVKit

> AVKit：ビデオコンテンツを表示する最も良い方法は、iOSとtvOS のAVKitフレームワークのクラスまたはmacOS のクラスを使用することです。これらのクラスは、再生コントロールやその他のメディア機能とともに、フルビデオ再生の体験を提供するビデオコンテンツを提供します。

## AVFoundation

> AVPlayerLayer：プレーヤ用のカスタムインターフェイスを構築する場合CALayerは、AVFoundationによって提供されるCore Animation サブクラスを使用します。プレーヤーレイヤーは、ビューのバッキングレイヤーとして設定することも、レイヤー階層に直接追加することもできます。異なりと、プレイヤー層は、任意の再生コントロールを提示し、単に画面上で視覚的なコンテンツを提供していません。メディアの再生、一時停止、検索を行うために、再生トランスポートコントロールを構築するのはあなた次第です。AVPlayerLayerAVPlayerViewAVPlayerViewController


# 単純な動画再生

UIView に PlayVideo という名前のボタンを設置し、下記の IBAction を定義。

```swift
@IBAction func playVideo(_ sender: AnyObject) {

    guard let url = URL(string: "https://devimages.apple.com.edgekey.net/samplecode/avfoundationMedia/AVFoundationQueuePlayer_HLS2/master.m3u8") else {
        return
    }

    // Create an AVPlayer, passing it the HTTP Live Streaming URL.
    let player = AVPlayer(url: url)

    // Create a new AVPlayerViewController and pass it a reference to the player.
    let controller = AVPlayerViewController()
    controller.player = player

    // Modally present the player and call the player's play() method when complete.
    present(controller, animated: true) {
        player.play()
    }
}
```

詳細は下記リンクを参照。
[Creating a Basic Video Player (iOS and tvOS) | Apple Developer Documentation](https://developer.apple.com/documentation/avfoundation/media_assets_playback_and_editing/creating_a_basic_video_player_ios_and_tvos)

また、下記の記事のサンプルも参考になると思う。
[iOSで動画を再生する - Qiita](https://qiita.com/kei4eva4/items/6023489ee86f84bd6d53)

# 構成

AVFoundationは下記の4つの技術を統合している。

- 再生と編集
- メディアキャプチャ
- オーディオ
- スピーチ (音声合成)

今回は動画再生周りについてなので「再生と編集」に焦点を当てていく。

# 再生と編集

[Media Assets, Playback, and Editing | Apple Developer Documentation](https://developer.apple.com/documentation/avfoundation/media_assets_playback_and_editing)

下記の分野に分かれる。

- メディア資産
- メディア再生
- メタデータ操作
- メディアアイテムの転送
- HTTPライブストリーミング
- サンプルバッファ操作
- メディアの構成と編集
- テキストフォーマット
- メディア選択
- コンテンツキー解読
- エラー
- サポートタイプ

今回は「メディア資産」と「メディア再生」を見て、動画再生周りの基礎を理解する。

## メディア資産

[About the Asset Model | Apple Developer Documentation](https://developer.apple.com/documentation/avfoundation/media_assets_playback_and_editing/about_the_asset_model)

分野は下記の通り、今回は資産モデルについてのみ見ていく。

- 資産モデルについて
- 資産操作
- アセットファイルのインポートとエクスポート

AVPlayerで利用されるメディア資産はAVAssetクラスを使用してモデル化される。
AVAssetクラスはメディア形式に依存しない。
また、メディアの場所 (ローカル, ネットワーク) に依存しない。

AVAssetクラスはAVAssetTrackと呼ばれるメディアストリームをモデル化したインスタンスを1つまたは複数持つコンテナオブジェクトであり、AVAssetTrackは下記のタイプが存在する。

- Video
- Audio
- Subtitles
- etc...

AVAssetTrackは `AVAsset#tracks` プロパティからコレクションを取得可能。

## メディア再生

[Asset Playback | Apple Developer Documentation ](https://developer.apple.com/documentation/avfoundation/media_assets_playback_and_editing/asset_playback)

分野は下記の通り、今回はアセット再生を見る。

- 再生状態の変化に対する応答
- 再生時間を観察する
- メディアを求めて
- アセット再生
- クイックタイムとISO関連メディア

アセット再生は AVPlayerItem でモデル化されたメディア資産を再生するメディアプレイヤーを作成して行う。

### プレイヤー

プレイヤーは基本的に下記の2種類っぽい。

|クラス名|解説|
|---|---|
|[AVPlayer](https://developer.apple.com/documentation/avfoundation/avplayer)|メディアの再生管理を行う|
|[AVQueuePlayer](https://developer.apple.com/documentation/avfoundation/avqueueplayer)|複数のメディアを順次再生するプレイヤー, AVPlayerを継承している|

### プレイヤービュー

[AVPlayerLayer | Apple Developer Documentation](https://developer.apple.com/documentation/avfoundation/avplayerlayer)

動画再生領域を作成するには AVPlayerLayer を利用して PlayerView を作る。
PlayerView は UIView を継承しているので、UIView に PlayerView を関連付けて利用可能。

```swift
class PlayerView: UIView {
    var player: AVPlayer? {
        get {
            return playerLayer.player
        }
        set {
            playerLayer.player = newValue
        }
    }
    
    var playerLayer: AVPlayerLayer {
        return layer as! AVPlayerLayer
    }
    
    // Override UIView property
    override static var layerClass: AnyClass {
        return AVPlayerLayer.self
    }
}
```

### プレイヤーアイテム

[AVPlayerItem | Apple Developer Documentation](https://developer.apple.com/documentation/avfoundation/avplayeritem)

プレイヤーによって再生されるメディア資産のタイミング及びプレゼンテーション状態をモデル化する。
AVPlayerItem は動画 URL か AVAsset から生成される動的オブジェクトである。
内部状態はアイテム準備中と再生中の２つに分かれ、Key-value observing にて観測可能である。

プロパティとメソッドの種類は下記の通り。

- プレイヤーアイテムの生成
- プレイヤーアイテムの検査
- 再生ヘッドの移動
- 再生に関する情報の取得
- タイミング情報の取得
- ネットワーク動作の設定
- アイテム設定の構成
- アクセスログ
- 承認の管理
- メディアオプションの選択
- etc...

# まとめ

## iosで動画再生を行うには？

AVPlayerViewController を利用するとすぐに動画再生が可能。
カスタマイズしたい場合は PlayerView を自作する。

動画再生を行うには AVPlayer を生成して AVPlayerViewController か PlayerView に渡す。
AVPlayer にメディアを渡す方法には下記の方法がある。

- AVPlayer にメディアのURLを渡す
- AVPlayerItem にメディアのURLを渡し、AVPlayer に渡す
- AVPlayerAsset にメディアのURLを渡し、AVPlayerItem に渡して AVPlayer に渡す

良くわからないが AVPlayerItem にURLを渡す方式が手軽かつパフォーマンスが良さそう。
(AVPlayer に URL を渡すと毎回読み込み処理が走るっぽい気がする)

## 各クラスの役割

|クラス名|役割|
|---|---|
|AVPlayerViewController|動画再生が簡単に出来る|
|AVPlayerLayer|動画再生Viewを作るのに利用する|
|AVPlayer|動画再生を行うメディアプレイヤー|
|AVQueuePlayer|順次再生を行う AVPlayer|
|AVPlayerItem|メディア資産のプレゼンテーション状態を管理|
|AVAsset|メディア資産をモデル化したもの、形式や場所に依存しない|

## 動画再生アプリを作る際の懸念

やはり一番はパフォーマンスだと思う。
動画を一度読み込んでからローカルに保存し、次回以降はローカルから取得とか。
再生するまではサムネイルを表示しておくとか。
動画再生アプリのパフォーマンスについてはまた別途まとめようと思う。

## さいごに

メディア周りは調べても良くわからないことばかりで、TikTok とか Youtube の ios アプリは凄いなーと思った。
今回は動画再生の基礎について初心者なりにまとめただけなので、これをキッカケにもう少ししっかりまとめた記事が出てくると良いと思う。

## 参考になりそうなURL

- [iOSで動画を再生する - Qiita](https://qiita.com/kei4eva4/items/6023489ee86f84bd6d53)
- [AVFoundationとRxを組み合わせる - Qiita](https://qiita.com/to4iki/items/44b87aba9eea5d7cbe9e)