読者です 読者をやめる 読者になる 読者になる

UnityでまともなMovieTextureを作りたい

この記事は、調べものをした途中の過程を記録する物で、成果物がある訳ではありません。

概要

Unity上での動画再生は、歴史的な経緯によりデスクトップ版ではQuickTime Playerを用いた再生を行っています。
つまり、大雑把に言うと*.movファイルをムービーテクスチャとして使用できます。
しかしQuickTime Playerはイマドキの主流であるGPUデコードには消極的で、CPUデコードを行っています(調査不足の可能性有り、何らかの最適なエンコードを行えば可能?)

その為、例えば4k2kの60FPS動画を再生すると、いまどきのCPUが1コアフル占有してコマが落ちる、と言う状況です。

多くの場合は、動画解像度を下げたり、30FPSにすることで対処出来ますが、例えばOculusRift DK2(75Hz)で全周動画を再生する、と言うシチュエーションでは、非常に困ります。

これを何とかする為の定番の方法と、現在調査中の方法をまとめます。

定番の手法

UE4+Windowsの例

Windows Media Foundationを用いた動画のGPUデコードが実装されています。

Unity+モバイル端末の例

例えばAndroidならSoCに動画のGPUデコード機能が入っており、android.mediaplayerクラスを利用することで再生が行えます。
Unity用のandroidのネイティブプラグインを書いて、このmediaplayerクラスの再生中のバッファをGLのテクスチャにバインドする。という事を行えば、Exsonys7xxx番代やSnapdragon810などで4k2kの動画がコマ落ちなくUnity上で再生出来ます。
こういった処理は、UnityのアセットであるEasyMovieTexture(30ドル)を買うと、ネイティブプラグイン部分のソースコードも同梱されているので改造し放題です。

うーん、Androidって凄い…

Unity+Windowsの例

http://www.renderheads.com/portfolio/UnityAVProWindowsMedia/ というアセットを使うことで、GPUデコード機能付きの再生が行えます。また、このアセットは外部の動画ファイルの動的読み込みにも対応しているため、Unity製の動画プレーヤーを作るような用途にも使えます。素晴らしい!

ただし、このアセットが200ドルします。うーん…お高い… そして全然Unity標準のMovieTextureと作法が異なるので、例えばAndroidWindows両対応みたいな事をする時に、結構大変そうです。

今回の提案手法

NVIDIAのCUDA実装の動画のGPUデコードを利用して、直接DX11のテクスチャバッファに動画の絵を毎フレーム書き込むネイティブプラグインを作成したいです。

これは、上記UnityAVProの機能限定(そしてNVIDIA GPU限定)版になる代わりに、再生負荷が低く出来る予感がします。

OpenCV 3.0.0rc1 のソースやサンプルを見てみると (@dandelion1124 さん 超助かりました!教えてくれてありがとうございます) BUILD_opencv_cudacodecとWITH_NVCUVIDをONにしてOpenCVをビルドして

Cudaを使った動画再生 https://github.com/Itseez/opencv/blob/master/samples/gpu/video_reader.cpp DX11テクスチャへの書き込み https://github.com/Itseez/opencv/blob/master/samples/directx/d3d11_interop.cpp を組み合わせたネイティブプラグインを作成して

Unity側で TextureのGetNativeTexturePtrをプラグインに受け渡してやる http://docs.unity3d.com/ScriptReference/Texture.GetNativeTexturePtr.html

という感じで 、望む物が出来そうな気がします。

OpenCVを使っているのは、単純に全部入りで楽そうだなあ、と思っただけなので、CUDAとDX11を生で叩いても同じ事が出来ると思います。(ウーン、UnityがOpenGLモードだと、もっと簡単な気がします。OpenCVやCudaとOpenGL仲良いですしね。でもOculusRiftのSDKはDirectX11ネイティブ対応なので、今回はDX11ですねえ)

残念ながら直近でまとまった時間が取れ無さそうなので、ここまで調べた時点で力尽きてしまいました。

しかし、UnityのMovieTextureは、大いに改善の余地がありそうなので、例えばCUDAじゃなくてOpenCLを使って汎用的な動画のGPUデコードなどが出来るアセットとかが50ドルくらいで売ってたら、人気になりそうですね。

どなたか、作りませんか!と提案してこの記事は終わります。

追記:MP4デコーダをCUDAのSDK提供のまま使って、アセット作って売るぞ!と言う場合は、一度NVIDIAの人にお伺いを立てたほうが良さそうです。うーん、知財周りは大変・・・