WebGL環境でHLS形式の動画を再生する方法を探しているの。
HLS対応ブラウザならVideoPlayerでそのまま再生できるわ。それ以外ではhls.jsなどのライブラリが必要になるわ。
WebGLのビルド環境でHLS(HTTP Live Streaming)形式の動画を再生する方法の解説記事です。
Safariなどの一部のブラウザではHLS形式が標準でサポートされており、Unity標準のVideoPlayerコンポーネントでそのまま再生可能です。
しかし、執筆時点では非対応ブラウザが多数存在し、再生には別途対策が必要です。
参考:“hls” | Can I use… Support tables for HTML5, CSS3, etc
WebGL環境限定となりますが、hls.jsというライブラリを使用することでHLS非対応ブラウザでのHLS動画の再生に対応できます。
hls.jsはJavaScriptライブラリであるため、Unityから使用するためにはjslibプラグインによるネイティブ実装が必須です。
本記事では、jslibプラグインを通じてからhls.jsを用いてあらゆるブラウザでHLS動画を再生する方法を解説します。以下2種類の方法を解説します。
- Unity標準のVideoPlayerの内部処理を一部上書きする(モバイル非対応)
- 再生機能を独自実装する
- Unity 2023.2.20f1
目次 非表示
前提条件
以下のようなQuadなメッシュに対してHLS形式動画をレンダリングするものとします。
また、本記事で解説するHLS動画再生は、WebGLビルド環境でのみ機能し、エディタ環境は対象外なのでご注意ください。
HLS動画再生の実現方法
本題に入る前に、HLSおよびその再生方法について軽く触れます。
HLS(HTTP Live Streaming)とは
HLS(HTTP Live Streaming)とは、Apple Inc. によって開発された動画の規格です。長時間の動画をインターネットを介して配信するのに適した形式になっています。
参考:HTTP Live Streaming 2nd Edition
通常の動画ファイルとは異なり、複数のセグメントファイル(拡張子が.ts)と、これらの情報が記されたプレイリストファイル(拡張子が.m3u8)から成ります。
セグメントファイルは時間で区切られた動画を格納する動画ファイルの実体で、H.264でエンコードされます。
複数のセグメントで分割することにより、動画再生時は該当する時刻が属するセグメントをダウンロードして再生すれば良いことになります。
また、セグメント分割することにより、動画を途中から再生したり、シークしたりする操作が比較的スムーズに実現できるといった恩恵も得られます。
インターネット経由でストリーミング再生する場合、これらのファイルはWebサーバーなどに配置し、HTTP経由で配信します。
また、HLSは通信環境などに応じて品質を段階的に可変にするアダプティブビットレートストリーミング(ABR)にも対応しています。
ABRに対応するには、各品質毎のHLS動画ファイル群とそれらを管理する上位のプレイリストファイルとして管理します。
HLS動画の再生
HLS動画を再生する際は、まずプレイリストとなる.m3u8ファイルをダウンロードしてセグメント情報等を解釈します。
HLS動画のURLを指定する際は、このプレイリストファイルへのパスを指定します。
URLの例
解釈した後、再生したい時刻に該当するセグメントファイルをダウンロードし、それをデコードして再生します。
hls.jsでHLS動画を再生する方法
Unity標準のVideoPlayerでは、内部的にvideo要素を作成して動画再生を実現しています。
Safari等のHLS形式対応ブラウザでは、そのままHLS動画のURLをvideo要素に指定すれば良いです。
しかし、HLS非対応ブラウザでは再生出来ません。そのため、非対応ブラウザにも対応させるために本記事ではhls.jsを用います。
hls.jsによりHLS形式動画再生に対応させるためには、まずhls.jsの外部JSをロードさせます。実際には以下のようなscriptタグをDOMに追加すれば良いです。
JavaScriptから動的に追加するには、以下のようにdocument.createElementメソッドを使います。
参考:Document: createElement() メソッド – Web API | MDN
作成したvideo要素に対してHLS動画再生できるようにするため、次のような処理でHlsインスタンスを生成して適用します。
VideoPlayerのネイティブコードを書き換えて実現する
一つ目の方法は、Unity標準のVideoPlayerの内部挙動を一部書き換えて実現する方法です。
メリットとデメリットは以下の通りです。
- メリット
- 実装が比較的手軽
- VideoPlayerをそのまま扱える
- デメリット
- 内部コードを書き換えるハック的な手段であるためリスクが伴う
- 非同期な初期化が必要
- モバイル環境では動作しない(Unity 2023)
手軽な分、ハック的な方法でモバイル非対応の問題を抱えるため、可能なら2つ目の方法として紹介する独自実装が安全でしょう。
参考:Video Player コンポーネント – Unity マニュアル
VideoPlayerでのHLS動画再生は、モバイルブラウザ環境では正しく機能しない事を確認しています。
モバイル環境にも完全対応させるためには、本記事で後述する再生機能を独自実装する方法を実践する必要があります。
実装例
以下、VideoPlayerをHLSに対応させるための.jslibスクリプトです。
サンプルスクリプト(クリックで開きます)
上記をVideoPlayerOverride.jslibなどという名前でPluginsフォルダ配下に保存します。
本記事では以下パスに配置するこことしました。
また、上記.jslibを機能させるためには、Unity C#側から初期化関数を呼ぶ必要があります。
以下、hls.jsを初期化してからVideoPlayerの動画を再生するスクリプトの実装例です。
サンプルスクリプト(クリックで開きます)
上記をVideoPlayerExample.csという名前でUnityプロジェクトに保存しておきます。
本記事では以下パスに配置するものとします。
シーンのセットアップ
本記事では、Quadなメッシュに対してVideoPlayerの動画をレンダリングするものとします。
参考:Video Player コンポーネント – Unity マニュアル
空のシーンにQuadなメッシュを配置し、適当にスケールを調整します。
適当なゲームオブジェクトにVideo Playerコンポーネントを追加します。例では前述のQuadメッシュに直接追加するものとします。
この時、Video PlayerコンポーネントのSourceは必ずURLにしてください。
WebGLビルドではURL経由での再生しかできません。ビデオクリップの再生はWebGL環境ではサポートされていないためご注意ください。
前述のサンプルスクリプトVideoPlayerExample.csをコンポーネントとして追加します。
このままでは、Quadメッシュに何も表示されないため、表示用のマテリアルを作成して適用するものとします。例ではUnlit/Textureなるマテリアルを作成してRendererに適用することとしました。
最後に、Video PlayerコンポーネントのURLに再生対象のHLS動画ファイルのパスを指定して完了です。
また、Rendererのマテリアルのテクスチャに動画をレンダリングする場合、Video Playerコンポーネントの以下項目の通り設定されていることを確認してください。
- Render Mode – Material Override
- Renderer – Rendererコンポーネント
実行結果
ここまでの手順を正しく実施すると、以下のようにHLS形式動画がレンダリングされるようになります。
スクリプトの説明
.jslibファイル側では、次のようにhls.jsを初期化するための関数を用意します。関数内では、hls.jsスクリプトをロードする処理を行っています。
そして、Unity C#側から初期化終了かどうか判断するため、以下のように初期化状態を返す関数を定義します。
Unity標準のVideoPlayerでは、初期化時に内部的にJS_Video_Create関数が呼ばれるようです。この関数処理を以下のように再定義して上書きします。
JS_Video_Create関数内では、video要素を作成した後に、次の処理でHLS動画だったらhls.jsを適用する処理が追加されています。
.jslibファイルの最後では、依存関係や関数をマージするための処理を行っています。
Unity C#側のスクリプトでは、上記jslibネイティブプラグイン側の関数を実行できるように関数宣言します。
JS_Video_CanPlayFormat関数はUnity側で定義されている関数です。本記事では、ブラウザがHLS形式に対応しているかどうかを判断するために使います。
hls.jsによるHLS動画再生を適用するためには、hls.jsが初期化されてからVideoPlayerの動画再生を実行する必要があります。
これを行うために、例では非同期処理でhls.jsの初期化が完了するまではVideoPlayerを無効にし、初期化完了したら有効にして再生するようにしています。
ブラウザ側でHLSに対応しているかどうかは、「application/vnd.apple.mpegurl」なるフォーマットが対応しているかで確認できます。対応している場合は処理をスキップします。
例ではスクリプトの中で単体のVideoPlayerに対して初期化していますが、実際にアプリケーションを開発する際は初期化シーンなどでhls.jsの初期化を実施するのが良いでしょう。
動画再生を独自実装して実現する
当環境では、1つ目のUnity標準のVideoPlayerを使う方法では、モバイル環境で再生出来ない問題を確認しています。
これらの問題は、VideoPlayerに相当する動画再生機能を独自実装することで解決できます。
2つ目の例では、以下記事の実装例に基づいて動画再生機能を独自実装して適用するものとします。
- メリット
- モバイル環境でも問題なく再生できる
- デメリット
- 独自再生機能を実装することにより、実装コストが高くなる
実装例
以下、VideoPlayerに相当する動画再生機能を独自実装してHLS形式動画にも対応した例です。スクリプトが複数あるのでご注意ください。
サンプルスクリプト(クリックで開きます)
.jslibファイル
動画操作用インタフェース
WebGLの動画再生操作クラス
VideoPlayerによる動画操作クラス(主にエディタやWebGL意外のプラットフォームで使用)
動画再生用コンポーネント
上記を全てUnityプロジェクトに保存します。.jslibファイルはPluginsフォルダ配下に置く必要があることにご注意ください。
例では以下パスに配置するものとします。
また、動画再生機能を独自実装する際は、リニアワークフロー時に色味が正しく出力されない問題が発生します。これは動画から転送されたテクスチャの色空間がガンマ空間であり、それをシェーダー側がリニア空間として処理してしまうことが原因です。
そこで、ガンマからリニアに色空間を変換するシェーダーも必要になります。以下はその実装例です。
シェーダー(クリックで開きます)
これもUnityプロジェクトに保存します。例では以下パスに保存するものとします。
シーンのセットアップ
シーン構成は1つ目の例と一緒とします。例では、前述の例でセットアップしたシーンを引き継ぎ、追加したVideo PlayerとVideo Player Exampleコンポーネントを削除するものとします。
そして、Custom Video Playerコンポーネント(本記事のサンプルスクリプト)を追加します。
そして、インスペクターより各種項目を設定してください。
- Url – 動画ファイルのURL(.m3u8ファイルのパス等)
- Is Muted – 音声をミュートするかどうか
- Play On Awake – Awakeイベントで自動再生するかどうか
- Target Renderer – レンダリング対象のRendererコンポーネント
- SRGB To Linear Shader – 色空間変換シェーダー(sRGBToLinear.shaderを指定)
実行結果
1つ目の例と同様にHLS形式にも対応した動画再生が行えます。
また、iPhone版ChromeやSafariなど、モバイル環境でも動作するようになるはずです。
スクリプトの説明
大部分の実装に関しては、以下記事で解説しています。動画再生の独自実装方法については以下説明をご覧ください。
.jslibプラグイン側では、hls.jsのロードが開始していない場合のみ、初期化処理を行います。
webGLVideoControlPendingHlsInstances変数に、hls.jsの初期化のために再生を保留されているvideo要素リストを格納するようにしました。
動画再生の初期化では、hls.jsが未初期化なら、保留リストに動画を追加して初期化を遅らせています。その後、前述のWebGLVideoControl_InitializeHlsJs関数を実行するようにしています。
サーバーにHLS動画をアップロードする時の注意点
ストレージサーバーなどにご自身でHLS動画ファイルをアップロードする際は、サーバー側でMIMEとCORSが適切に設定されている必要があります。
MIMEでは、.m3u8と.ts拡張子のファイルに以下のようなMIME Typeがサーバー側で設定されている必要があります。
ファイル拡張子 | MIME Type |
.M3U8 | application/x-mpegURL または vnd.apple.mpegURL |
.ts | video/MP2T |
参考:Deploying HTTP Live Streaming
また、異なるドメインの動画URLを指定する場合、配置先のサーバー側でCORS(オリジン間リソース共有)によるドメイン許可が必要です。動画ファイルはGETメソッドでダウンロードする形になるので、GETメソッドを許可していれば良いことになります。
さいごに
hls.jsによるHLS動画再生への対応では、基本的にJavaScriptによる対応が必要なため、Unityで扱うためには.jslibプラグインを実装する必要があります。
Safari等一部のブラウザではHLSに対応しているため、そのままVideoPlayerによる再生が可能ですが、モバイル環境など正常に機能しない場合もあります。
そのため、モバイル環境も含め、全ての環境に対応させるためには動画再生機能を独自実装する手段を取るのが確実です。