OpenGL/D3D: Как я получаю экранный захват игры, выполняющей полный экран в Windows?

Предположим, что у меня есть игра OpenGL, выполняющая полный экран (Оставленный 4 Мертвых 2). Я хотел бы программно получить экранный захват его и затем записать его в видеофайл.

Я попробовал GDI, D3D и методы OpenGL (например, glReadPixels) и или получаю пустой экран или мерцающий в потоке получения.

Какие-либо идеи?

Если это имеет значение канонический пример чего-то подобного тому, чего я пытаюсь достигнуть, Связывает.

11
задан Theodore Baxley 15 August 2010 в 08:37
поделиться

3 ответа

Я нашел исходный проект под названием taksi:

http://taksi.sourceforge.net/

Однако Taksi не обеспечивает захват звука.

0
ответ дан 3 December 2019 в 08:28
поделиться

Есть несколько подходов к этой проблеме. Большинство из них неприятны, и это полностью зависит от того, на какой графический API вы хотите настроить таргетинг и какие функции использует целевое приложение. Большинство приложений DirectX, GDI + и OpenGL имеют двойную или тройную буферизацию, поэтому все они в какой-то момент вызывают:

void SwapBuffers(HDC hdc)

. Они также генерируют сообщения WM_PAINT в своей очереди сообщений всякий раз, когда окно должно быть нарисовано. Это дает вам два варианта.

  • Вы можете установить глобальную ловушку или локальную ловушку потока в целевой процесс и захватывать сообщения WM_PAINT. Это позволяет копировать содержимое из контекста устройства непосредственно перед рисованием. Процесс можно найти, перечислив все процессы в системе и ища известное имя окна или известный дескриптор модуля.

  • Вы можете внедрить код в локальную копию SwapBuffers целевого процесса. В Linux это было бы легко сделать с помощью переменной окружения LD_PRELOAD или явно вызвав ld-linux.so.2, но в Windows этого нет. К счастью, существует структура от Microsoft Research, которая может сделать это за вас, под названием Detours . Вы можете найти это здесь: ссылка .

Группа демосцены Farbrausch создала инструмент для записи демо под названием kkapture, который использует библиотеку Detours. Их инструмент нацелен на приложения, которые не требуют ввода данных пользователем, поэтому они в основном запускают демонстрации с фиксированной частотой кадров, подключаясь ко всем возможным функциям времени, таким как timeGetTime (), GetTickCount () и QueryPerformanceCounter (). Это совершенно круто.Презентацию, написанную ryg (я думаю?) О внутренностях kkapture, можно найти здесь . Думаю, вам это интересно.

Для получения дополнительной информации о обработчиках Windows см. здесь и здесь .

РЕДАКТИРОВАТЬ:

Эта идея меня заинтриговала, поэтому я использовал Detours, чтобы подключиться к приложениям OpenGL и возиться с графикой. Вот Quake 2 с добавленным зеленым туманом: Quake 2 Hook

Еще немного информации о том, как работает Detours, раз уж я использовал это из первых рук:

Detours работает на двух уровнях. Фактическое подключение работает только в том же пространстве процесса, что и целевой процесс. Итак, в Detours есть функция для внедрения DLL в процесс и принудительного запуска его DLLMain, а также функций, которые предполагается использовать в этой DLL. Когда DLLMain запущен, DLL должна вызвать DetourAttach (), чтобы указать функции для перехвата, а также функцию «обхода», которая является кодом, который вы хотите переопределить.

В основном это работает так:

  • У вас есть приложение запуска, единственная задача которого - вызвать DetourCreateProcessWithDll (). Он работает так же, как CreateProcessW, только с несколькими дополнительными параметрами. Это внедряет DLL в процесс и вызывает его DllMain ().
  • Вы реализуете DLL, которая вызывает функции обхода и настраивает функции трамплина. Это означает вызов DetourTransactionBegin (), DetourUpdateThread (), DetourAttach (), а затем DetourTransactionEnd ().
  • Используйте программу запуска, чтобы внедрить DLL, которую вы внедрили в процесс.

Однако есть некоторые предостережения. При запуске DllMain библиотеки, импортированные позже с помощью LoadLibrary (), еще не отображаются.Таким образом, вы не можете обязательно настроить все во время события прикрепления DLL. Обходной путь - отслеживать все функции, которые на данный момент переопределены, и пытаться инициализировать другие внутри этих функций, которые вы уже можете вызвать. Таким образом, вы обнаружите новые функции, как только LoadLibrary отобразит их в пространстве памяти процесса. Я не совсем уверен, насколько хорошо это будет работать для wglGetProcAddress. (Возможно, у кого-то еще есть идеи по этому поводу?)

Некоторые вызовы LoadLibrary (), похоже, не работают. Я тестировал Quake 2, и DirectSound и waveOut API по какой-то причине не смогли инициализировать. Я все еще расследую это.

14
ответ дан 3 December 2019 в 08:28
поделиться

Раньше я писал захватчики экрана (эпоха DirectX7-9). Я обнаружил, что старый добрый DirectDraw работал на удивление хорошо и надежно захватывал биты контента с аппаратным ускорением/видеоэкраном, которые другие методы (D3D, GDI, OpenGL) оставляли пустыми или зашифрованными. Это было очень быстро.

0
ответ дан 3 December 2019 в 08:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: