UnityのVideo PlayerでRender Textureを使用して動画を再生する

## はじめに
最近はUnityを使用する事が多く、C#スクリプトによるRender Textureを使用したVideo Playerの再生で手こずったので、その時のメモです。
なお、Video Playerの詳細は、[Unityの公式ドキュメント](https://docs.unity3d.com/ScriptReference/Video.VideoPlayer.html)を参照願います。

## 環境
確認環境は以下です。
Unity 5.6.4p4
Mac High Sierra（Ver 10.13.2）

## 再生仕様
- Canvasに貼られたボタンによって、ボタンに割り当たっている動画を再生します。
- 再生画面はプレハブ化し、再生時にプレハブから生成されるようにします。
- 再生する動画は、"Resources/Movie" の下に保存していることとします。
（まずは再生のみの実装とします）

##Project構成
以下のようなUnityプロジェクトの構成イメージです。
###Hierarchyビューのツリー
Scene
  ├Canvas
  │　└Button
  └Video Player
###Projectのツリー
Assets
  ├Resources
  │　├Movie
  │　│　└再生動画
  │　└Prefabs
  │　　　└Raw Image
  └Scripts
　　└Sample.cs


##Hierarchyビューでの操作
Hierarchyビューで以下の操作を行います

1. Canvasを準備します
    - スマホでの再生を前提にしているので、UI Scale Modeは、”Scale With Screen Size” に設定しました。
2. Canvasの下に再生用のボタンを準備します
3. Canvasの下にRaw Imageを準備します
4. Raw ImageのInspector画面で、適切な大きさにサイズを調整し、プレハブ化します
    - プレハブは、"Resources/Prefabs" の下に保存します
    - Raw Imageは、動画の再生画面になるので、あらかじめ位置と大きさを決めておきま
5. Video Playerを準備します
6. Video PlayerのInspector画面の、Add Componentで、Audio Sourceを追加します
7. ボタンと再生処理を行うスクリプトを作成し、上記２.で作成したボタンにスクリプトを登録し、OnClickイベントに登録します。（以下のサンプルコードでは、VideoStart()）

##スクリプト
以下サンプルコード
（ボタンの処理と動画の再生処理はコードを分けた方が良いと思いますが、サンプルなので、、、）

```c#:Sample.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
using UnityEngine.UI;

public class VideoPlayController : MonoBehaviour {

	// とりあえず特定のファイル名を指定
	string videoclipfile = "Movie/動画ファイル名";

	// 再生画面用のRaw Imageは「MovieRawImage」という名称でプレハブ化されている前提
	string rawImage = "Prefabs/MovieRawImage";

	public void VideoStart(){
		// ボタンクリック処理
		StartCoroutine (VideoPlayStart ());
	}

	private IEnumerator VideoPlayStart()
	{
		// あらかじめVideo PlayerがSceneに登録されている前提
		var obj = GameObject.Find ("Video Player");
		VideoPlayer videoPlayer = obj.GetComponent<VideoPlayer> ();

		Application.runInBackground = true;
		// あらかじめVideo PlayerにAudio Sourceが登録されている前提
		var audioSource = videoPlayer.GetComponent<AudioSource>();

		// ファイルをロードし、再生する動画のサイズに合わせてRender Textureを準備する
		VideoClip vclip = (VideoClip)Resources.Load (videoclipfile);
		RenderTexture _renderTexture = new RenderTexture ((int)vclip.width, (int)vclip.height, 24);

		// Video Playerの設定を行う
		videoPlayer.playOnAwake = false;
		audioSource.playOnAwake = false;
		videoPlayer.source = VideoSource.VideoClip;
		videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
		videoPlayer.renderMode = VideoRenderMode.RenderTexture;
		videoPlayer.EnableAudioTrack(0, true);
		// Audio SourceにあらかじめVideo Playerに追加したAudio Sourceを設定する
		videoPlayer.SetTargetAudioSource(0, audioSource);
		videoPlayer.clip = vclip;
		videoPlayer.targetTexture = _renderTexture;

		// Video Playerの準備（完了まで待つ）
		videoPlayer.Prepare();
		while (!videoPlayer.isPrepared)
			yield return null;

		// Video Playerの準備が完了した後
		// プレハブから動画再生用のRawImageをロードする
		var _prefab = Resources.Load(rawImage);
		GameObject _rawImg = Instantiate(_prefab) as GameObject;
		// Canvasが親になるようにtransformを代入する
		GameObject cvs = GameObject.Find("Canvas");
		_rawImg.transform.parent = cvs.transform;
		_rawImg.transform.localPosition = Vector3.zero;
		_rawImg.transform.localScale = new Vector3 (1, 1, 1);

		// RawImageに動画再生用のRenderTextureを設定する
		RawImage screen = _rawImg.GetComponent<RawImage>();
		screen.texture = _renderTexture;

		// 動画の再生開始（再生完了まで待つ）
		videoPlayer.Play();
		while (videoPlayer.isPlaying)
			yield return null;

		// 動画の再生完了
		videoPlayer.clip = null;
		videoPlayer.targetTexture = null;
		GameObject.Destroy (_rawImg.gameObject);
	}
}

```


##注意点
- Video PlayerのTarget Textureに登録するRender Textureについては、再生する動画の縦横サイズを設定する必要があるようです。スクリプト例では再生コンテンツのサイズを設定しています
- Video Playerの設定を行なった後、Prepare()によって準備を行う必要があるようです。
    - 設定が抜けると、正しく再生できません。私はtargetTextureの設定がPrepare()の後になっていて正しく再生できませんでした
- Raw Imageには、Video Playerに登録したTarget Textureと同じRender Textureを登録します
- Video Playerの再生完了後、Video Clipを初期化しないと2回目以降の再生が正しく表示できないようです。
    - スクリプト例では、念のためにTarget Textureも初期化しています。
 


以上、ご参考まで。