Unityで動画を再生する様々な方法

# 概要
この記事は[Unity Advent Calendar 2022](https://qiita.com/advent-calendar/2022/unity)の4日目の記事です


Unity内で動画を扱いたいシチュエーションは数多くあると思います。
この記事は主にUnityの標準Video Playerの使い方について解説します
補足としてYoutube動画とHLS形式のストリーミング動画を再生する方法にも触れます

今回のサンプルは下記のGitHubにアップロードされています
https://github.com/tkada/videoplayer-sample

# Unity標準のVideo Playerを使った再生方法
Unityには標準で動画を再生するためのコンポーネントが用意されています
[VideoPlayerコンポーネント](https://docs.unity3d.com/ja/2021.2/Manual/class-VideoPlayer.html)
[VideoPlayerスクリプトリファレンス](https://docs.unity3d.com/ja/2021.2/ScriptReference/Video.VideoPlayer.html)

こちらを使うとアプリに埋め込んだ動画やサーバに置いた動画を再生することができます

## メッシュに動画を流し込む(Render Mode=Material Override)
![video1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/291825d0-96a0-76ba-f616-36a7e185fcd1.gif)

動画を流し込みたいメッシュを作成し、そこに`Video Player`コンポーネントをアタッチします
そしてVideo Clipに流したい動画の参照を持たせるだけでメッシュに動画を流し込むことができます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/8b8bc8cc-c3e1-707a-6959-cbb9aada399a.png)

`Video Player`には豊富なオプションがあるので順にオプションを説明していきます

|項目名|意味|
|--|--|
|Play On Awake|Video PlayerがActiveになった時に自動的に再生します<br>スクリプトから再生タイミングを制御したい時などはOFFにすることが多いです|
|Wait For First Frame|動画の再生準備が完了するまで待機してから再生を開始します。<br>基本的にONでいいと思います|
|Loop|動画をループ再生させたい時にONにします|
|Skip On Drop|再生中に再生が間に合わない場合にフレームをスキップして時間を合わせます<br>こちらも基本的にONでいいと思います|
|Playback Speed|動画の再生速度|

この再生方法の時には`Auto-Select Property`のオプションが表示され
これをOFFにすると`Material Property`が変更できるようになり、任意のプロパティへ動画を流し込むことができます

## Render Textureに動画を流し込む(Render Mode=Render Texture)
動画を再生する用途としてはこの方法が最も頻度が高いと思われます
Render Textureに動画を流すので、そのRender TextureをUIとして使用したり、MaterialのTextureとして使ったりと用途が豊富です

まず右クリックメニューからCreate->Render Textureを選択し、Render Textureを作成します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/9114a8c1-0864-5fd5-9894-95a826171e37.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/51085e99-d8cd-6c08-1c02-8ce04ed892ad.png)

次に任意のGameObjectにVideo Playerをアタッチし、`Render Mode`を`Render Texture`に変更します
`Target Texture`に先ほど作成したRender Textureを参照させます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/f475c524-5561-dedc-135e-0d19b1c786eb.png)

あとはRender TextureをUGUIのRawImageとして表示させればUI内で動画が再生できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/6e1ce3a8-7e06-f220-ff77-fe0af41b8fc7.png)

なおVideo Player内の`Aspect Ratio`のオプションで動画とRender Textureのアスペクト比が異なっていても自動で補正してくれます

## カメラに対して動画を再生する(Render Mode=Camera Near/Far Plane)
![alpha.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/3eb46d77-2d13-ea21-0a2a-190e90c654c1.gif)![far.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/caeea4a3-b5ea-5ee7-7d5d-4428ba1ff999.gif)

カメラのNear ClipまたはFar Clipに対して動画を描画します
Near Clipの場合は全画面動画として、Far Clipの場合は背景として動画を扱うことができます
また、Alphaの値を設定できるので、重ね合わせるような表現も可能です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/58b7548d-05c4-659f-1c3f-2f92437f7d80.png)
Render Modeを`Camera Far Plane`または`Camera Near Plane`に設定します
Cameraに動画を描画したいカメラの参照を持たせます
`Alpha`は動画の透明度を設定します。1なら非透明になります

3D Layoutのパラメータはパノラマ動画の際に使うようです
https://docs.unity3d.com/ja/2021.3/Manual/VideoPanoramic.html

なお、`Camera Near Plane`を設定した場合でもOverlayのUIは動画の上に描画されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/c0584ea5-a4d0-d04e-6864-805ce1b5246a.png)

## Unity外部に置いた動画を再生する
サーバ上に置いた動画ファイルやローカルに置いたファイルを再生することができます

Video Playerの`Source`を`URL`に切り替えます
URLに流したい動画のURLを設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/37ef3675-3972-f3d0-5f38-c35195b6c2ae.png)

また、下記のようにローカルファイルを指定することもできます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/fc8fbbe8-e8b9-9ab9-7487-7a5ca504af3b.png)

## 音声の制御をする
これまでAudio Output ModeはDirectを使ってきました
Directの場合、動画の音声は直接出力されるのでVolumeくらいしか制御できません
Audio Output Modeを`Audio Source`にすることでAudio Sourceを使った音声の制御ができるようになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/9cb3e08d-714f-dda2-a3b1-452afccce988.png)
例えば、上の画像のようにSpatial Blendを3Dにして、3D Audioを効かせることができるようになります
他にもリバーブをかけたり、左右片方のチャンネルだけ出力したりといったことが可能になります
詳しくはAudio Sourceのドキュメントをご覧ください
https://docs.unity3d.com/ja/2020.3/Manual/class-AudioSource.html

## スクリプトから制御する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/4680d8d3-6c05-8862-6c34-d61a51e1188c.png)

スクリプトからの制御例を解説します
今回は単純なUIを作成し、再生・停止・一時停止・指定時間へのシークに対応させました

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

public class VideoControl : MonoBehaviour
{
    [SerializeField] VideoPlayer videoPlayer;

    [SerializeField] Button playButton;
    [SerializeField] Button stopButton;
    [SerializeField] Button pauseButton;

    [SerializeField] Slider slider;
    [SerializeField] Text timeText;

    void Start()
    {
        this.playButton.onClick.AddListener(() =>
        {
            //再生する
            //一時停止中の場合は再開する
            this.videoPlayer.Play();
        });

        this.stopButton.onClick.AddListener(() =>
        {
            //停止する
            this.videoPlayer.Stop();
        });

        this.pauseButton.onClick.AddListener(() =>
        {
            //一時停止する
            this.videoPlayer.Pause();
        });

        this.slider.onValueChanged.AddListener(value =>
        {
            //スライダーの場所に合わせて再生する場所を変える
            this.videoPlayer.time = this.videoPlayer.length * value;
        });
    }

    void Update()
    {
        //スライダーを再生時間に合わせて進行させる
        //SetValueWithoutNotifyを使うとonValueChangedのコールバックが呼ばれない
        //→UIで操作したイベントだけを取得することができる
        this.slider.SetValueWithoutNotify((float)(this.videoPlayer.time / this.videoPlayer.length));

        //現在再生時間を表示
        this.timeText.text = $"{(int)this.videoPlayer.time / 60:D2}:{(int)this.videoPlayer.time % 60:D2}";
    }
}
```

VideoPlayerから取得できる変数は数多くあります
再生状態が`isPlaying`や`isPause`で表現されているため、状態を制御する場合には多少癖がありますが
それ以外は使いやすくAPIにまとめられていると思います
https://docs.unity3d.com/ja/2021.2/ScriptReference/Video.VideoPlayer.html


# Youtube動画を再生する方法
Youtube動画を再生するために下記のアセットを使用します
https://github.com/iBicha/UnityYoutubePlayer
このアセットはYoutubeの動画を自動的にUniryで流せる形式に変換してくれます
ただし、Youtube Liveには対応してませんのでご注意ください

まずEdit->Project Settings->Package Manager->Scoped Registriesに下記の内容を入力しApplyします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/c9227fc8-7c8f-3c0e-fea0-96df7945038a.png)
|項目|値|
|--|--|
|Name|iBicha|
|URL|https://registry.npmjs.com|
|Scope(s)|com.ibicha|

次にWindow->Packaga Managerを開き、`Packages: My Registries`を選択します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/67a53592-46ef-aa1e-7a7d-e4856f408546.png)
上手く設定ができていると`Youtube Player`の項目があるので、これをインストールします
これで準備完了です

任意のGameObjectに`Youtube Player`をアタッチして`Youtube Url`に流したいYoutube動画のURLを設定します。
このときVideo Playerの`Source`は`URL`に設定しておきましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105021/fb45d355-cc22-2ed6-1ded-64e85d81f383.png)

あとはこれまでのVideo Playerと使い方は同じです

# HLS形式のストリーミング動画を再生する方法
2022年12月現在、UnityでHLS形式のストリーミング動画を再生するには有料アセットを使うしかありません


UMP (Android, iOS)
https://assetstore.unity.com/packages/tools/video/ump-android-ios-56044?locale=ja-JP
このアセットはプラットフォームごとに分割されて販売されているので、ご自身で必要なプラットフォームを購入する必要があります


AVPro Video
https://assetstore.unity.com/packages/tools/video/avpro-video-core-edition-181844
こちらのアセットもプラットフォームごとに分かれています

NexPlayer
https://github.com/NexPlayer/NexPlayer_Unity_Plugin

NexPlayerはUnity公式のソリューションパートナーになった発表がありましたので、将来Unityの標準Video Playerになるのかもしれません
[ネクストリーミング、NexPlayerがUnityの公認ソリューションパートナーになると発表](https://www.businesswire.com/news/home/20201210006266/ja/)

# まとめ
Unityで動画を再生する方法を解説しました
動画を使うと低い負荷でリッチな表現が可能になります
是非深堀ってみてください