全画面で実行されている OpenGL ゲームがあるとします (Left 4 Dead 2)。プログラムで画面を取得して、ビデオ ファイルに書き込みたいと思います。
GDI、D3D、および OpenGL メソッド (glReadPixels など) を試しましたが、空白の画面が表示されるか、キャプチャ ストリームでちらつきます。
何か案は?
価値があるのは、私が達成しようとしているものに似たものの標準的な例がFrapsです.
全画面で実行されている OpenGL ゲームがあるとします (Left 4 Dead 2)。プログラムで画面を取得して、ビデオ ファイルに書き込みたいと思います。
GDI、D3D、および OpenGL メソッド (glReadPixels など) を試しましたが、空白の画面が表示されるか、キャプチャ ストリームでちらつきます。
何か案は?
価値があるのは、私が達成しようとしているものに似たものの標準的な例がFrapsです.
この問題にはいくつかのアプローチがあります。それらのほとんどは厄介で、対象とするグラフィックス API の種類と、対象アプリケーションが使用する機能に完全に依存します。ほとんどの DirectX、GDI+、および OpenGL アプリケーションは、ダブルまたはトリプル バッファリングされるため、すべて以下を呼び出します。
void SwapBuffers(HDC hdc)
ある時点で。また、ウィンドウを描画する必要があるときはいつでも、メッセージ キューに WM_PAINT メッセージを生成します。これにより、2 つのオプションが提供されます。
グローバル フックまたはスレッド ローカル フックをターゲット プロセスにインストールして、WM_PAINT メッセージをキャプチャできます。これにより、描画が行われる直前にデバイス コンテキストからコンテンツをコピーできます。プロセスは、システム上のすべてのプロセスを列挙し、既知のウィンドウ名または既知のモジュール ハンドルを探すことで見つけることができます。
SwapBuffers のターゲット プロセスのローカル コピーにコードを挿入できます。Linux では、これは LD_PRELOAD 環境変数を介して、または ld-linux.so.2 を明示的に呼び出すことで簡単に実行できますが、Windows には同等のものはありません。幸いなことに、これを行うことができるDetoursという Microsoft Research のフレームワークがあります。これはここにあります: link。
デモシーン グループの Farbrausch は、Detours ライブラリを利用する kkapture という名前のデモ キャプチャ ツールを作成しました。ただし、彼らのツールはユーザー入力を必要としないアプリケーションを対象としているため、timeGetTime()、GetTickCount()、QueryPerformanceCounter() などの可能なすべての時間関数にフックすることで、基本的に固定フレームレートでデモを実行します。それは完全にラッドです。kcapture の内部構造に関する ryg (だと思いますか?) によって書かれたプレゼンテーションは、ここにあります。それはあなたにとって興味深いことだと思います。
Windows フックの詳細については、こちらとこちらを参照してください。
このアイデアに興味をそそられたので、Detours を使用して OpenGL アプリケーションにフックし、グラフィックをいじりました。緑の霧が追加された Quake 2 は次のとおりです。
迂回路は 2 つのレベルで機能します。実際のフックは、ターゲット プロセスと同じプロセス空間でのみ機能します。そのため、Detours には、プロセスに DLL を挿入し、その DLLMain も強制的に実行する機能と、その DLL で使用されるはずの機能があります。DLLMain が実行されると、DLL は DetourAttach() を呼び出して、フックする関数と、オーバーライドするコードである「迂回」関数を指定する必要があります。
したがって、基本的には次のように機能します。
ただし、いくつかの注意事項があります。DllMain を実行すると、後で LoadLibrary() でインポートされるライブラリはまだ表示されません。そのため、DLL アタッチメント イベント中に必ずしもすべてをセットアップできるとは限りません。回避策は、これまでにオーバーライドされたすべての関数を追跡し、これらの関数内で既に呼び出すことができる他の関数を初期化することです。このようにして、LoadLibrary が新しい関数をプロセスのメモリ空間にマップするとすぐに新しい関数を発見できます。ただし、これが wglGetProcAddress に対してどの程度うまく機能するかはよくわかりません。(おそらく、ここにいる他の誰かがこれに関するアイデアを持っていますか?)
一部の LoadLibrary() 呼び出しが失敗するようです。Quake 2 でテストしたところ、DirectSound と waveOut API が何らかの理由で初期化に失敗しました。私はまだこれを調査しています。
過去にスクリーン グラバーを作成したことがあります (DirectX7-9 時代)。古き良きDirectDrawが非常にうまく機能し、他の方法 (D3D、GDI、OpenGL) では空白のままかスクランブルされているように見えるハードウェア アクセラレーション/ビデオ画面コンテンツのビットを確実に取得できることがわかりました。それもとても速かった。
私は taksi と呼ばれる sourceforge されたプロジェクトを見つけました:
ただし、Taksi はオーディオ キャプチャを提供しません。