UnityのWebRTCのHWエンコードで使われるNvidia VideoCodecを更新してH264のレベル6.2に対応してみる
概要
UnityのRenderStreamingを使う際、ハードウェアエンコードを有効時、内部的に使われるNvidiaのVideo Codec SDKが古く、高解像度のコーデックレベルに対応していない問題があったので、自分で差し替えを試す。その方法がうまくいったので、備忘録としてまとめる。
※1以下の内容は将来的に公式側で対応されるか、仕様変更で動かなくなる可能性がある
※2高解像度といっても現実的に動くレベルは3840x2160まで、UnityのWebRTCの制約上では4096x4096までは可能だが、明らかに動作が遅くなる
事前準備
ビルドをする前に以下のページに書かれているSDKやアプリケーションをインストールする。CUDAやVulkanSDK、cmakeのバージョンは下記ページ中のものと合わせなくても動いたので、今後仕様変更や破壊的変更がない限りは新しいバージョンでも大丈夫そう
以下に順序を追ってインストールなどの方法を解説する
依存するSDKやライブラリをインストール
ソースコードからのビルドには、ビルド時に依存するSDKやライブラリをインストールする必要がある。作業にはターミナルやVisualStudioが必要になる
上のリンク中のWindowsでのライブラリインストール方法のように管理者権限でPowerShellを立ち上げ、Chocolateyを使ってインストールするのがおすすめするが、セキュリティの都合からChocolatey入れられない環境では、以下のリンクからダウンロードできる。Chocolateyのパッケージ名に合わせてリンクを置いている
※Windows 10 64bit版前提で進めているので、他の環境を使う場合は多少リンクが変わるかも
cuda: https://developer.nvidia.com/cuda-downloads
(アーカイブ: https://developer.nvidia.com/cuda-toolkit-archive)
vcredist2010: https://www.microsoft.com/ja-jp/download/details.aspx?id=26999
vcredist2013: https://www.microsoft.com/ja-jp/download/details.aspx?id=40784
vcredist140: https://support.microsoft.com/ja-jp/topic/the-latest-supported-visual-c-downloads-2647da03-1eea-4433-9aff-95f26a218cc0
(使用しているOS環境に合わせる、ここでは x64
をダウンロードする)
windows-sdk-10-version-1809-all: https://developer.microsoft.com/ja-jp/windows/downloads/sdk-archive/
(Windows 10 SDK バージョン 1809
の SDKのインストール
のほうを選ぶ。Visual Studio Installerからでもインストールできる(下図のように個別のコンポーネントから、 Windows 10 SDK (10.0.17763.0)
にチェックしてインストール)
VulkanSDK: https://vulkan.lunarg.com/sdk/home
(下図のように Windows
の SDK Installer
を選ぶ。図は1.2.162.1のものだけど、最新版で大丈夫そう)
cmake: https://cmake.org/download/
(Platform
のうち、Windows x64 Installer
(ファイル末尾が.msi)を選ぶ)
Visual Studio 2019のインストール
githubのページには書かれていないけど、Visual Studioも必要なのでDLする
Visual Studio 2019: https://visualstudio.microsoft.com/ja/downloads/
Nvidia Video Codec SDKをインストール
今回の差し替え元になるVideoCodec SDKもダウンロードしてインストールする
NVIDIA VIDEO CODEC SDK: https://developer.nvidia.com/nvidia-video-codec-sdk/download
環境変数を確認する
今回使用するcmakeは依存ライブラリを探す際に特定の環境変数を使用するので、事前に確認する
特にChocolateyを使わずにライブラリをインストールした場合、環境変数が通っていない場合が多いので必ず確認しておく
以下はPowerShellでの確認方法になる。bashで確認したいときは echo $CUDA_PATH
とすればできる
$env:CUDA_PATH
$env:VULKAN_SDK
通っていない場合はシステム環境変数から CUDA_PATH
と VULKAN_SDK
の変数を追加し、上の図のように、ライブラリのバージョンが書かれているフォルダまでのパス(そのフォルダ以下に bin
や include
フォルダが含まれるまでのファイルパス)を値の箇所に記述する
システム環境変数 PATH
にcmake.exeのバイナリが置いてあるディレクトリが含まれているか確認する。cmake --version
のコマンドからcmakeのバージョンを見れるか確認するとパス通っているか確認できる
cmake --version
通っていない場合はシステム環境変数から Path
の末尾にcmake.exeが含まれているファイルパスを追加する(例: C:\Program Files\CMake\bin
)
システム環境変数を操作した場合、WindowsをOSごと再起動するか、PowerShellの再起動が必要になるので注意
※VideoCodec SDKのファイルは直接差し替えることになるので、環境変数にパスを通しておく必要はなし
ソースコードダウンロードからビルドまで
com.unity.webrtcのパッケージをGitHubからダウンロードしてビルドするのだけど、注意点がいくつかあったので、そこを気を付けながらビルドをしていく
バージョン指定してwebrtcリポジトリをクローン
https://github.com/Unity-Technologies/com.unity.webrtc/releases からリポジトリをダウンロードする
gitのCLIからリポジトリをクローンする場合、ブランチ指定しない限りデフォルトブランチの develop
を引っ張るので、念のためリリース版のブランチを指定する(以下の例では release/2.4.0-exp.3
を指定)
git clone -b release/2.4.0-exp.3 https://github.com/Unity-Technologies/com.unity.webrtc.git
カスタマイズされたwebrtcのソースコードをダウンロード
BuildScripts~
フォルダ内にある、 build_plugin_win.cmd
をテキストエディタで開き LIBWEBRTC_DOWNLOAD_URL
の後ろのURLをコピーする。記事と同じバージョン(2.4.0-exp.3なら、おそらくhttps://github.com/Unity-Technologies/com.unity.webrtc/releases/download/M89/webrtc-win.zip のアドレスになっているかと思う(2.3.3あたりの古いバージョンならURL中の M89
が M85
になっている)
ダウンロード後、zipファイルをwebrtc.zipにリネームし、右クリックからすべて展開(T)
で解凍し、できた webrtc
フォルダごと Plugin~
フォルダ内にコピーする
以下のようになっていれば大丈夫
VideoCodec関連のファイルを置き換える
既存ファイルを待避する
Plugin~/NvCodec
内にあるフォルダをすべて別の場所に移動させるか、末尾に_bakなどを追加して待避する
VideoCodecのSDKからファイルをコピーする
Video Codec SDKのフォルダ直下にある Interface
と Lib
フォルダを Plugin~/NvCodec
フォルダ内にコピーする
それぞれのフォルダを Interface > include
、 Lib > lib
にリネームする
(補足:Interface
フォルダは ***.h
が入っている。 Lib
フォルダは linux
、Win32
、x64
フォルダが入っており、それらのフォルダ内には ***.lib
や ***.so
が入っている)
Video Codec SDKの Samples
フォルダ内にある NvCodec
と Utils
フォルダを同様に Plugin~/NvCodec
フォルダ内にコピーする
コピー後 Plugin~/NvCodec
以下のファイルがこのようになっていればOK
コピー後の一部ファイルを削除する
コピー後の Plugin~/NvCodec/NvCodec/NvEncoder
フォルダ内にある、NvEncoder.cpp
、NvEncoder.h
、NvEncoderCuda.cpp
、NvEncoderCuda.h
以外のファイルを削除する
インクルードファイル指定の一部を変更する
Plugin~/NvCodec/NvCodec/NvDecoder
内の NvDecoder.cpp
と NvDecoder.h
をテキストエディタで開き、 #include "../../../Interface/nvcuvid.h"
の箇所を #include "nvcuvid.h"
に置き換える
//#include "../../../Interface/nvcuvid.h" //元のコード
#include "nvcuvid.h" //変更後のコード
//#include "../../../Interface/nvcuvid.h" //元のコード
#include "nvcuvid.h" //変更後のコード
エンコード時に使用されるH264コーデックのレベルを変更する
現行バージョン(2.3.3や2.4.0あたりの話)UnityのWebRTCライブラリではHWエンコード時に動作するコードをNvidiaのVideoCodecのサンプルコードから流用しているが、 このサンプルコードはH264コーデックを使用するようにハードコードされており、またコーデックレベルも固定化されているため、直接書き替えない限りはコーデックを変更することができない。 今回はここを変更してH264コーデックのレベルを6.2に変更してみる
Plugin~/WebRTCPlugin/Codec/NvCodec
フォルダ内の NvEncoder.cpp
をテキストエディタで開く。おそらく110行目あたりの nvEncConfig.encodeCodecConfig.h264Config.level = NV_ENC_LEVEL_H264_51;
を書き換える
//nvEncConfig.encodeCodecConfig.h264Config.level = NV_ENC_LEVEL_H264_51; //元のコード
nvEncConfig.encodeCodecConfig.h264Config.level = NV_ENC_LEVEL_H264_62;
他、 NV_ENC_LEVEL_H264_60
(レベル6.0相当)や NV_ENC_LEVEL_H264_61
(レベル6.1相当)までの定義は差し替え後の nvEncodeAPI.h
で定義されているので、自分の用途に合わせて書き換える
※ Plugin~/WebRTCPlugin/Codec/NvCodec
配下のファイルはVideoCodec SDKの Samples/NvCodec/NvEncoder
配下と同名のファイルが並んでいるが、中身は別物なので置き換えないように注意する
ビルドする
ターミナル(PowerShell、bashなど)で Plugin~
フォルダ(CMakeLists.txt
がある一番上のフォルダ)までカレントディレクトリを変更する。カレントディレクトリ変更後、以下の cmake
コマンドを実行する(ConfigureとGenerateが実行される)
cmake . -G "Visual Studio 16 2019" -A x64 -B "build64"
cmake
コマンド実行後、 Plugin~
フォルダ内に build64
というフォルダが作られているので、そのフォルダ内にある webrtc.sln
ファイルをダブルクリックして実行する。Visual Studioがインストールされていれば、自動的にVisual Studioが起動する
Visual Studio起動後、構成が Debug
になっているので、 Release
を選択する
ソリューションエクスプローラーから ALL_BUILD
の箇所で右クリックし、 ビルド(U)
を選択し、ビルドを実行する
実行完了後、エラーが無ければ出力タブで以下のように表示される。エラーがある場合はファイルの置き換えやソースコードの書き換えを飛ばしていないか確認する
※上の内容を再確認してもエラーが出る場合は、CUDAやVideoCodecに破壊的変更があるのかもしれないので、少しずつ前のバージョンに戻して試してみる
ビルド後、Runtime/Plugins/x86_64
フォルダ内の webrtc.dll
ファイルがビルドしたものに上書きされているので、エクスプローラーから更新日時を確認する
ビルドしたWebRTCライブラリを利用してみる
実際にカスタマイズしたWebRTCライブラリをUnityRenderStreamingを通して使ってみる。これ以降は確認するだけなので、純粋にWebRTCの更新をしたいだけなら上記まででよい
Unity側のセットアップ
UnityRenderStreamingで使われるWebRTCプラグインとしてパッケージマネージャに登録する
Unity2020.3以降のバージョンで適当なプロジェクトを作成する
Package Managerの画面から、Add package from disk
を選択する
ダイアログが開くので、ソースコード(com.unity.webrtc
フォルダの直下)の package.json
を選択し、 開く
ボタンをクリックする
Custom
の箇所にWebRTCのライブラリが追加されていればOK
Package Managerの画面から、Add package from git URL
を選択する
テキストボックスが表示されるので com.unity.renderstreaming
を入力する
ダイアログが表示されるので、 OK
を押す、押した後Unityが再起動するのを待つ。開かない場合は自分でUnityを起動する
再起動後、追加したUnityRenderStreamingのパッケージで今回カスタマイズしたWebRTCのライブラリが使われているかを確認するため、Package Manager 右上にある歯車マークをクリックし、 Advanced Project Settings
を選択する
Project Settingsのウィンドウが表示される。右側画面の下の方にある Advanced Settings
項目の中にある、 Show Dependencies
の箇所のチェックボックスをONにする
Project Settingsのウィンドウを閉じ、再度Package Managerの画面から、 Unity Render Streaming
を選択し、 Dependencies
の箇所をクリックして開き、 Is using
の箇所を確認する。バージョン一致、末尾が(local)になっていればカスタマイズしたWebRTCのライブラリが使われている
※UnityRenderStreamingのバージョンごとに依存するWebRTCのバージョンは違うので注意
ついでにサンプルも実行するので、 Samples
の箇所をクリックして開き、 Example
横の Import
をクリックしてサンプルプロジェクトをダウンロードする
サンプルがダウンロードできたら Assets
配下の Samples/Unity Render Streaming/3.1.0-exp.1/Example/WebBrowserInput
の中にある WebBrowserInput
のシーンを開く
Hierarchyから Render Streaming Camera 1
を選択、Inspectorの Camera Streamer (Script)
の解像度をベンチマークとして4Kサイズに変更してみる
ハードウェアエンコードを有効にするため、Hierarchyから Render Streaming
を選択し、Render Streaming (Script)
の Hardware Encoder Support
にチェック、 Run On Awake
にもチェックを入れる(入れないとHWエンコードが有効にならない?)
また、バージョン 3.1.0-exp.1
でのバグなのか、デフォルトではHttpSignalingが設定されているが、Unity実行時なぜかWebSocketSignalingに変更されるようで、URL設定がおかしくなるので、初めから以下のように WebSocketSignaling
にしておき、 Signaling URL
を ws://localhost
に変更する
WebApp側の実行
Unityのメニューから Edit > Render Streaming > Download web app
を選択する
ダイアログが開くので、ターミナルで開きやすい箇所にダウンロードする。(例: ユーザーのホームディレクトリとか)
ダウンロードしたファイル webserver.exe
をターミナルから実行する。以下の例はPowerShellだが、bashの場合は ./webserver.exe --websocket
で実行できる。なお日本語環境のPowerShellだとバックスラッシュ()は¥に置き換わる
.\webserver.exe --websocket
実行後、ターミナルの画面は開きっぱなしにしておく
上のコマンドでWebApp用のサーバーと接続用のWebSocketサーバーが起動されるので、この状態でブラウザ(Chrome)を開く、URLは localhost/videoplayer/index.html
← コピーしてURLバーにペーストして開く
この画面が出たら待機する
Unityの実行、WebAppの実行
Unityを実行する
Unity実行後、ブラウザ画面に表示されている再生ボタンをクリックして接続する
再生後、Unity側の画面がブラウザにも表示される
他
Unity公式のWebRTCライブラリはリリース版でも結構な頻度で破壊的変更に関する議論がされているようなので、将来的にこの方法は使えなくなるかも
Discussion