凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

uDesktopDuplication でキャプチャしたデスクトップ画像をリモートに転送してみた

はじめに

主要な VR 向けのデスクトップ表示アプリ(Virtual Desktop や Bigscreen など)では、PC だけでなくモバイル VR もサポートしています。これを実現するには、キャプチャしたデスクトップ画面をリモートへ低遅延で転送しなければなりません。また、より広いユースケースを考えるのであれば、2 台(または N 台)の PC 間で、それぞれお互いのデスクトップ画面を送り合う、みたいなことも実現したいです(Bigscreen が出来ているかも?)。

そこで、これまで作成してきた以下のアセットを組み合わせて、今回は取り敢えず動くところまで作成してみました。

tips.hecomi.com

tips.hecomi.com

tips.hecomi.com

tips.hecomi.com

ちなみにタイトルは嘘で、NVIDIA 製の GPU を積んだ PC が 1 台しかないため、送り手も受け手も同じ PC でローカルで完結しかテストできていません。。

デモ

下が Desktop Duplication API のキャプチャ、上がそれをエンコード・転送・デコードしたものです。4K のデスクトップ画を送っていますがちょっと遅延はありますが問題なく動いています。遅延はおそらく uOSC のせいでプロファイラのスパイクは uOscServer.Update() のせいで起こっています。。

サンプルダウンロード

github.com

環境

仕組み

図で書くと、以下のような流れになっています。

f:id:hecomi:20190927233031p:plain

  1. uDesktopDuplication でデスクトップのテクスチャ(ID3D11Texture2D)を Desktop Duplication API で直接取ってくる
  2. uNvEncoder で ID3D11Texture2D を直接 NVENC に渡して非同期エンコード
  3. uPacketFragmentation(今回追加したヤツ)でエンコードのバッファを UDP に乗るように分割
  4. UDP で送信(uOSC を使って手抜きしてます)
  5. UDP で受信(上に同じ)
  6. uPacketFragmentation でパケットを結合・順序保証
  7. uNvPipe で NVDEC に渡してデコード
  8. CustomTextureUpdate でデコードしたバッファをテクスチャにする(uNvPipe 内)

現在の uNvPipe の非同期コードは間違っていた(デバイスに非同期アクセスしてしまっていた)ので、修正します。執筆現在は同期にして使っています。

おわりに

前回の記事で、次はリモートレンダリングを...と書いていましたが、先日 Unity 公式が以下のような記事を公開されていました。

blogs.unity3d.com

NVENC でエンコードした画面を WebRTC でブラウザに低遅延で転送、ブラウザから逆に操作もできる、との内容です。

(╯°□°)╯︵ ┻━┻。

ということで、こちらの内容はやるのをやめて今回の記事をしたためた次第です。もともとは Oculus Quest などの機器へ転送することを目標にやっていたので、今回の内容が最終目標ではあったのですが、これが俗に言う民主化の(嬉しい)脅威というやつですね。こういったものを GitHub で公開してくれているのは本当に素晴らしいです。しかしながら公開サンプルではデスクトップイメージのエンコードは(ちょっと改造しないと)出来ないので、まだ今回の制作物に意味はあるかな、と思っています。

本記事の内容では、とりあえず転送まで、という形ですので、今後はパケロス検知や任意のタイミングでの IDR フレーム再送要求、ディスプレイ解像度検知、複数ディスプレイ同時転送、また余力があれば uWindowCapture 連携や機器発見もやっていきたいと思います。また簡単だったので uOSC を使っていますがオーバーヘッドがかなり大きいので、受け取ったバッファを直接デコードに突っ込めるように修正もしようと思います。

実験のために RTX を積んだノートパソコンが欲しい...