# 映像の描画


## 映像を描画する

ストリームが扱う映像は、ロールに関わらず `VideoView` (もしくは `VideoRenderer` プロトコルを実装したオブジェクト) で描画可能です。

サンプルコードを次に示します:

```
@IBOutlet weak var videoView: VideoView!

// 接続する
Sora.shared.connect(configuration: config) {
    chan, error in
    // エラー処理は省略
    ...

    // VideoView をセットする
    chan!.mainStream.videoRenderer = self.videoView
}
```

1 つのストリームにセットできる `VideoView` は 1 つです。
マルチストリーム機能ではストリームごとに異なる `VideoView` をセットする必要があります。

## Interface Builder で `VideoView` を配置する

Interface Builder で `VideoView` をウィンドウに配置する場合は、次の手順で設定します。

1. ウィンドウに UIView を配置する
2. インスペクタを開き、 "Custom Class" の次の設定を変更する

> - "Class": "VideoView" を指定する
> - "Module": "Sora" を指定する
>
> ![image](images/quickstart/videoview_customclass.png)

## 独自の映像レンダラーを実装する

`VideoView` 以外の映像レンダラーを独自に実装したい場合は、 `VideoRenderer` プロトコルを実装したクラスを用意します。


## 映像フレームを加工・編集する

映像フレーム (`VideoFrame`) は映像レンダラーに渡される前のタイミングで加工・編集が可能です。
加工・編集を行うには `VideoFilter` プロトコルを実装したクラスのオブジェクトを、ストリームの `videoFilter` プロパティにセットして使用します。

映像フレームは `CMSampleBuffer` から生成可能です (音声データを含む `CMSampleBuffer` は非対応です) 。
詳しくは API リファレンスをご確認ください。

## 任意の映像を送信する

任意の映像を送信するには、映像フレームを生成して配信ストリームの `send(videoFrame:)` メソッドの引数に渡します。

## 映像の送受信の停止時の描画について

ストリームによる映像の送受信が停止したときの `VideoView` の挙動は **未定義** です。

現在、弊社の SDK ではプラットフォームによって映像ビューの挙動が異なることを確認しています。
iOS では映像が止まったように見え、 Android とブラウザでは黒い画面が表示されます。
これらの現象は WebRTC ライブラリの実装に依存しており、各種 Sora SDK では特に手を加えていません。

Sora iOS SDK で仕様を定めない理由は次の通りです。

- WebRTC は映像の送受信の停止時の描画について定義していません。
- 映像の送受信の停止時に描画コンポーネントがすべき挙動はアプリケーションによって異なります。あるアプリケーションでは黒い画面を表示したいかもしれませんし、他のアプリケーションでは最後に描画した映像を表示し続けたいかもしれません。

以上の理由から、 SDK は特定の挙動を保証していません。
映像の送受信の停止時の処理はユーザー側で実装して頂く必要があります。

最も単純な方法は、停止時の描画を行うビューを用意することです。
`VideoView` とは別にビューを用意しておき、停止時に切り替えます。
参考として切替の方法の例を次に挙げておきます。

- 停止時に `VideoView` を隠し、用意したビューを表示します。基本的にこの方法を推奨します。


  ```
  // VideoView を隠す
  videoView.isHidden = true

  // 代わりのビューを表示する
  anotherView.isHidden = false
  ```
- 停止時に表示するビューを `VideoView` のサブビューに追加します。黒い画面や画像などの単純な映像を表示したり、 `VideoView` の回転やリサイズに追従したりする場合に向きます。


  ```
  // 黒い画面を表示するビューを VideoView に追加する
  blackView = UIView(frame: videoView.bounds)
  blackView.backgroundColor = UIColor.black
  videoView.addSubview(blackView)

  // Auto Layout の設定
  blackView.translatesAutoresizingMaskIntoConstraints = false
  blackView.leadingAnchor.constraint(equalTo: videoView.leadingAnchor).isActive = true
  blackView.trailingAnchor.constraint(equalTo: videoView.trailingAnchor).isActive = true
  blackView.topAnchor.constraint(equalTo: videoView.topAnchor).isActive = true
  blackView.bottomAnchor.constraint(equalTo: videoView.bottomAnchor).isActive = true

  // 再開時はサブビューから取り除く
  blackView.removeFromSuperview()
  ```

## 端末の回転の検出について

Sora iOS SDK は、カメラの起動時に `UIDevice` の `beginGeneratingDeviceOrientationNotifications()` を、停止時に `endGeneratingDeviceOrientationNotifications` を実行します。これは libwebrtc のカメラ操作の仕様です。
アプリケーションで同メソッドを実行する際は、 `beginGeneratingDeviceOrientationNotifications()` と `endGeneratingDeviceOrientationNotifications()` を必ず対に実行するように注意してください。
