Предположим, что у меня есть игра OpenGL, выполняющая полный экран (Оставленный 4 Мертвых 2). Я хотел бы программно получить экранный захват его и затем записать его в видеофайл.
Я попробовал GDI, D3D и методы OpenGL (например, glReadPixels) и или получаю пустой экран или мерцающий в потоке получения.
Какие-либо идеи?
Если это имеет значение канонический пример чего-то подобного тому, чего я пытаюсь достигнуть, Связывает.
Я нашел исходный проект под названием taksi:
Однако Taksi не обеспечивает захват звука.
Есть несколько подходов к этой проблеме. Большинство из них неприятны, и это полностью зависит от того, на какой графический 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 с добавленным зеленым туманом:
Detours работает на двух уровнях. Фактическое подключение работает только в том же пространстве процесса, что и целевой процесс. Итак, в Detours есть функция для внедрения DLL в процесс и принудительного запуска его DLLMain, а также функций, которые предполагается использовать в этой DLL. Когда DLLMain запущен, DLL должна вызвать DetourAttach (), чтобы указать функции для перехвата, а также функцию «обхода», которая является кодом, который вы хотите переопределить.
В основном это работает так:
Однако есть некоторые предостережения. При запуске DllMain библиотеки, импортированные позже с помощью LoadLibrary (), еще не отображаются.Таким образом, вы не можете обязательно настроить все во время события прикрепления DLL. Обходной путь - отслеживать все функции, которые на данный момент переопределены, и пытаться инициализировать другие внутри этих функций, которые вы уже можете вызвать. Таким образом, вы обнаружите новые функции, как только LoadLibrary отобразит их в пространстве памяти процесса. Я не совсем уверен, насколько хорошо это будет работать для wglGetProcAddress. (Возможно, у кого-то еще есть идеи по этому поводу?)
Некоторые вызовы LoadLibrary (), похоже, не работают. Я тестировал Quake 2, и DirectSound и waveOut API по какой-то причине не смогли инициализировать. Я все еще расследую это.
Раньше я писал захватчики экрана (эпоха DirectX7-9). Я обнаружил, что старый добрый DirectDraw работал на удивление хорошо и надежно захватывал биты контента с аппаратным ускорением/видеоэкраном, которые другие методы (D3D, GDI, OpenGL) оставляли пустыми или зашифрованными. Это было очень быстро.