SystemOverview - HexagramNM/NM_WindowCaptureVirtualCamera GitHub Wiki
システムの概要
構成
NM_WindowCaptureVirtualCameraは以下の4つから構成されており、図のようにつながっています。
- NM_WindowCaptureVirtualCamera(WPFアプリケーション)
- NM_WindowCapture(ウィンドウキャプチャやトリミングを行うDLL)
- NM_WCVCam_DS(DirectShowを使用した仮想カメラ)
- NM_WCVCam_MF(MediaFoundationを使用した仮想カメラ)
役割
それぞれのアプリケーションやDLLは以下の通りです。
-
NM_WindowCaptureVirtualCamera
- メインのGUI
- NM_WindowCaptureをロードし、GUIでの操作をもとにNM_WindowCaptureを制御する
- ウィンドウのピッカーの開始
- キャプチャされるウィンドウのプレビュー表示
- トリミングのパラメタの設定
- マウスカーソルをキャプチャするかの設定
- 仮想カメラの開始、終了操作
- 仮想カメラに送る共有テクスチャの操作(共有状態や左右反転)
-
NM_WindowCapture
- WinRTのWindowsGraphicsCapture APIを使用したウィンドウピッカー処理、ウィンドウキャプチャ処理
- キャプチャされたウィンドウの位置調整、トリミング処理(DirectXで共有テクスチャにオフスクリーンレンダリングしています。)
- DirectXの共有テクスチャとして、キャプチャされたウィンドウを仮想カメラに共有
- 解説
- 関連Qiita記事:DirectXでテクスチャを別プロセスに共有する
- NM_WCVCam_MFの開始、終了
-
NM_WCVCam_DS
- NM_WindowCaptureから共有されたDirectXの共有テクスチャを取得
- 解説
- 関連Qiita記事:共有テクスチャ取得用として適切なDirectXデバイスを検索する
- DirectShowの仮想カメラの仕組みで共有テクスチャにあるキャプチャウィンドウを映像のサンプルとして送信
- 解説
- 関連Qiita記事:DirectShowで仮想カメラを自作しよう
- 共有テクスチャから映像サンプルを取り出す際に、Compute Shaderで効率よくデータを取り出す
- 解説
- 関連Qiita記事:ComputeShaderでの最適化例: DirectShowの仮想カメラ
- NM_WindowCaptureから共有されたDirectXの共有テクスチャを取得
-
NM_WCVCam_MF
- NM_WindowCaptureから共有されたDirectXの共有テクスチャを取得
- MediaFoundationの仮想カメラの仕組みで共有テクスチャにあるキャプチャウィンドウを映像のサンプルとして送信
- 解説
- 関連Qiita記事:MediaFoundationの仮想カメラで、キャプチャしたウィンドウを映してみた
昔に書いたQiita記事の内容からの変更点
-
DirectShowのインクルードファイルのリポジトリ
こちらの記事では、DirectShow開発に必要なインクルードファイルなど含むソースコードを、ミラーリングされたリポジトリから取得しておりました。
この記事のコメントで教えていただきましたが、Microsoftさんが公式でそれらのファイルのリポジトリを出していたので、そのリポジトリにあるファイルを使用するように変更しました。
-
ウィンドウキャプチャと仮想カメラの分離
こちらの記事では、仮想カメラのコードとウィンドウキャプチャのコードをひとまとめにしており、DirectShowの仮想カメラからキャプチャ処理を呼び出していました。
WinRTのWindowsGraphicsCaptureAPIでキャプチャしたウィンドウをDirectShowで自作した仮想カメラに映そう
しかし以下の点から、ウィンドウキャプチャのコードと仮想カメラのコードは分離したほうが良いと判断しております。
-
MediaFoundationの仮想カメラの処理はセッション0上で呼び出され、そもそもユーザのデスクトップ上にあるウィンドウハンドルを取得したり、ウィンドウをキャプチャすることができない
-
DirectShowとWinRTのコードを併用しようとすると、ライブラリが競合してしまい、解決するのにひと手間かける必要がある
- 参考:コンパイル時の注意点
この分離により、結果としてピッカーの起動処理も仮想カメラから分離されることになりました。また、元々の記事ではピッカーを開く時に新たにウィンドウを作り、ピッカーと紐づけておりました。しかし、今回のNM_WindowCaptureVirtualCameraにはGUIウィンドウがあるため、新たにウィンドウを作ることはせず、このGUIウィンドウをピッカーに紐づけております。
分離とは関係ない修正ですが、元々の記事では
GraphicsCapturePicker.PickSingleItem
からの返り値を受け取り、タスクの状態確認や選択されたウィンドウの取得を仮想カメラ側のメインループ(FillBuffer
メソッド)で独自に行っていました。今回、選択されたウィンドウをco_await
で受け取るようにし、独自実装していた処理は除去しました。(当時も適切に排他処理すれば、co_await
で対応できたように思います。)co_await
が使用できるように、Visual Studioのプロジェクト側で/await
のオプションを追加しております。 -
-
オフスクリーンレンダリングと仮想カメラの分離
こちらの記事では、位置調整やトリミングのためのオフスクリーンレンダリングをMediaFoundationの仮想カメラから行っていました。
DirectXとMediaFoundation仮想カメラとの効率の良い連携
しかし、以下の理由からオフスクリーンレンダリングの処理と仮想カメラは分離し、オフスクリーンレンダリング後の画像を共有テクスチャとして渡したほうが良いと判断しております。 (オフスクリーンレンダリング処理はNM_WindowCaptureにウィンドウキャプチャ処理とまとめています。)
-
オフスクリーンレンダリングの処理をそれぞれの仮想カメラに重複して書く必要がなくなる。
-
オフスクリーンレンダリング後の画像だけ共有テクスチャで送ればよくなり、トリミング情報など仮想カメラに送る必要のあるものが減る。
- 仮想カメラ側でオフスクリーンレンダリングしてしまうと、映像の左右反転やトリミングなどの情報を仮想カメラに送る手段が別に必要になる。
-
キャプチャできるウィンドウサイズの制限がなくなる。
-
キャプチャされるウィンドウはDirectXのテクスチャとして取得できるが、大きさが変わりうる。
-
仮想カメラでオフスクリーンレンダリングする場合は、大きさ変更に対応するため、あらかじめ大きなテクスチャを作成し、そこにキャプチャされたウィンドウをコピーしていた。 しかし、この場合はキャプチャできるウィンドウの上限があらかじめ作成する大きなテクスチャのサイズに制限されてしまう。
-
ウィンドウキャプチャのタイミングでオフスクリーンレンダリングする場合は、取得されたテクスチャをそのままオフスクリーンレンダリングで使用すればよく、 あらかじめ大きなテクスチャを作成する必要はなくなった。結果として、キャプチャできるウィンドウサイズの制限を回避できるようになった。
-
-