Самый быстрый способ захвата экрана

Я хочу написать программу screencasting для платформы Windows, но я не уверен, как захватить экран. Единственный метод, который я знаю, - использовать GDI, но мне любопытно, есть ли другие способы обойти это, и если есть, что несет наименьшие издержки? Скорость - приоритет.

Программа screencasting будет предназначена для записи видеозаписей, хотя, если это сужает возможности, я по-прежнему открыт для любых других предложений, которые выпадают из этой области. Знание не плохо, в конце концов.

Изменить. Я наткнулся на эту статью: Различные способы захвата экрана. Он познакомил меня с этим способом Windows Media API и способом DirectX. В Заключении упоминается, что отключение аппаратного ускорения может значительно повысить производительность приложения захвата. Мне любопытно, почему это так. Может ли кто-нибудь заполнить пробелы для меня?

Изменить. Я читал, что программы screencasting, такие как Camtasia, используют свой собственный драйвер захвата. Может ли кто-нибудь дать мне подробное объяснение того, как это работает, и почему оно быстрее? Мне также может понадобиться руководство по реализации чего-то подобного, но я уверен, что в любом случае существует документация.

Кроме того, теперь я знаю, как FRAPS записывает экран. Он перехватывает базовый графический API для чтения из заднего буфера. Насколько я понимаю, это быстрее, чем чтение из переднего буфера, потому что вы читаете из системной памяти, а не из видеопамяти. Вы можете прочитать статью здесь.

Ответ 1

Это то, что я использую для сбора одиночных кадров, но если вы измените это и сохраните все две цели, открытые все время, вы можете "потопить" его на диск, используя статический счетчик для имени файла. - Я не могу вспомнить, где я нашел это, но он был изменен, благодаря кому!

void dump_buffer()
{
   IDirect3DSurface9* pRenderTarget=NULL;
   IDirect3DSurface9* pDestTarget=NULL;
     const char file[] = "Pickture.bmp";
   // sanity checks.
   if (Device == NULL)
      return;

   // get the render target surface.
   HRESULT hr = Device->GetRenderTarget(0, &pRenderTarget);
   // get the current adapter display mode.
   //hr = pDirect3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddisplaymode);

   // create a destination surface.
   hr = Device->CreateOffscreenPlainSurface(DisplayMde.Width,
                         DisplayMde.Height,
                         DisplayMde.Format,
                         D3DPOOL_SYSTEMMEM,
                         &pDestTarget,
                         NULL);
   //copy the render target to the destination surface.
   hr = Device->GetRenderTargetData(pRenderTarget, pDestTarget);
   //save its contents to a bitmap file.
   hr = D3DXSaveSurfaceToFile(file,
                              D3DXIFF_BMP,
                              pDestTarget,
                              NULL,
                              NULL);

   // clean up.
   pRenderTarget->Release();
   pDestTarget->Release();
}

Ответ 2

EDIT: я вижу, что это указано в вашей первой ссылке редактирования как "способ GDI". Это по-прежнему достойный способ пойти даже с рекомендациями по производительности на этом сайте, вы можете легко добраться до 30fps, я бы подумал.

Из этого комментария (у меня нет опыта в этом, я просто ссылаюсь на кого-то, кто это делает):

HDC hdc = GetDC(NULL); // get the desktop device context
HDC hDest = CreateCompatibleDC(hdc); // create a device context to use yourself

// get the height and width of the screen
int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);

// create a bitmap
HBITMAP hbDesktop = CreateCompatibleBitmap( hdc, width, height);

// use the previously created device context with the bitmap
SelectObject(hDest, hbDesktop);

// copy from the desktop device context to the bitmap device context
// call this once per 'frame'
BitBlt(hDest, 0,0, width, height, hdc, 0, 0, SRCCOPY);

// after the recording is done, release the desktop context you got..
ReleaseDC(NULL, hdc);

// ..and delete the context you created
DeleteDC(hDest);

Я не говорю, что это самый быстрый, но операция BitBlt как правило, очень быстрая, если вы копируете между совместимыми контекстами устройств.

Для справки Open Broadcaster Software реализует нечто вроде этого как часть своего метода "dc_capture", хотя вместо создания целевого контекста hDest с использованием CreateCompatibleDC они используют IDXGISurface1, который работает с DirectX 10+. Если поддержки нет, они возвращаются к CreateCompatibleDC.

Чтобы изменить его для использования определенного приложения, вам нужно изменить первую строку на GetDC(game) где game является дескриптором игрового окна, а затем установить правильную height и width игрового окна.

Когда у вас есть пиксели в hDest/hbDesktop, вам все равно нужно сохранить его в файл, но если вы делаете захват экрана, я бы подумал, что вы захотите записать определенное количество из них в память и сохранить в видеофайл в кусках, поэтому я не буду указывать на код для сохранения статического изображения на диск.

Ответ 3

Я написал программу для видеозахвата, похожую на FRAPS для приложений DirectX. Исходный код доступен, и моя статья объясняет общую технику. Посмотрите http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/

Уважайте свои вопросы, связанные с производительностью,

  • DirectX должен быть быстрее, чем GDI, за исключением того, что вы читаете из буфера, который очень медленный. Мой подход похож на FRAPS (чтение из backbuffer). Я перехватываю набор методов из Direct3D-интерфейсов.

  • Для видеозаписи в реальном времени (с минимальным воздействием приложения) необходим быстрый кодек. FRAPS использует собственный видеокодек без потерь. Lagarith и HUFFYUV - это общие видеокодеки без потерь, предназначенные для приложений реального времени. Вы должны смотреть на них, если вы хотите выводить видеофайлы.

  • Другой подход к записи скринкастов может заключаться в написании драйвера зеркального отображения. Согласно Википедии: при активном зеркальном отображении видео каждый раз, когда система обращается к основному видеоустройству в месте внутри зеркальной области, копия операции рисования выполняется на зеркальном видеоустройстве в режиме реального времени. См. Драйверы зеркал в MSDN: http://msdn.microsoft.com/en-us/library/windows/hardware/ff568315(v=vs.85).aspx.

Ответ 4

Я использую d3d9 для получения backbuffer и сохраняю его в png файле с помощью библиотеки d3dx:

<Предварительно >   IDirect3DSurface9 * поверхность;   // GetBackBuffer  idirect3ddevice9- > GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO и поверхность);   // сохранение поверхности   D3DXSaveSurfaceToFileA ( "filename.png", D3DXIFF_PNG, поверхность, NULL, NULL);   SAFE_RELEASE (поверхность);

Чтобы сделать это, вы должны создать свой swapbuffer с помощью

d3dpps.SwapEffect = D3DSWAPEFFECT_COPY ; // for screenshots.

(Таким образом, вы гарантируете, что бэкбуффер не искажен, прежде чем снимать скриншот).

Ответ 5

Я написал класс, который реализовал метод GDI для захвата экрана. Мне тоже нужна дополнительная скорость, поэтому после обнаружения метода DirectX (через GetFrontBuffer) я попробовал это, ожидая, что он будет быстрее.

Я был встревожен, обнаружив, что GDI работает примерно в 2,5 раза быстрее. После 100 пробных снимков, на которых был показан мой монитор с двумя мониторами, реализация GDI составляла в среднем 0,65 с за захват экрана, тогда как метод DirectX составлял в среднем 1,72 с. Таким образом, GDI определенно быстрее, чем GetFrontBuffer, согласно моим тестам.

Мне не удалось получить код Brandrew для тестирования DirectX через GetRenderTargetData. Экранная копия получилась чисто черной. Тем не менее, он может быстро скопировать этот пустой экран! Я продолжу заниматься этим и надеюсь получить рабочую версию, чтобы увидеть реальные результаты.

Ответ 6

В моем впечатлении подход GDI и подход DX отличаются по своей природе. при рисовании с использованием GDI применяется метод FLUSH, подход FLUSH рисует рамку, затем очищает ее и перерисовывает другой кадр в том же буфере, это приведет к мерцанию в играх, требуя высокой частоты кадров.

  • ПОЧЕМУ DX быстрее? в DX (или в мире графики) применяется более зрелый метод, называемый рендерингом двойного буфера, где присутствуют два буфера, при наличии переднего буфера для аппаратного обеспечения, вы также можете отображать другой буфер, а затем после кадра 1 готовый рендеринг, система свопирует в другой буфер (блокирует его для представления на аппаратное обеспечение и освобождает предыдущий буфер), таким образом рентабельность рендеринга значительно улучшается.
  • ПОЧЕМУ ускорить ускорение аппаратного ускорения? хотя с двойной визуализацией буфера, FPS улучшается, но время для рендеринга все еще ограничено. современное графическое оборудование обычно включает в себя большую оптимизацию во время рендеринга, как правило, как сглаживание, это очень интенсивно вычисляется, если вы не требуете высококачественной графики, конечно, вы можете просто отключить эту опцию. и это сэкономит вам некоторое время.

Я думаю, что вам действительно нужна система воспроизведения, и я полностью согласен с тем, что обсуждали люди.

Ответ 7

Для С++ вы можете использовать: http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html
Это может не работать на всех типах 3D-приложений/видео приложений. Тогда эта ссылка может быть более полезной, поскольку она описывает 3 разных метода, которые вы можете использовать.

Старый ответ (С#):
Вы можете использовать System.Drawing.Graphics.Copy, но это не очень быстро.

Образец проекта, который я написал, делает именно это: http://blog.tedd.no/index.php/2010/08/16/c-image-analysis-auto-gaming-with-source/

Я планирую обновить этот пример с помощью более быстрого метода, такого как Direct3D: http://spazzarama.com/2009/02/07/screencapture-with-direct3d/

И вот ссылка для захвата видео: Как захватить экран для видео с помощью С#.Net?

Ответ 8

Несколько вещей, которые мне удалось получить: по-видимому, использование "зеркального драйвера" выполняется быстро, хотя я не знаю OSS.

Почему RDP так быстро по сравнению с другим программным обеспечением дистанционного управления?

Также очевидно, что некоторые свертки StretchRect быстрее, чем BitBlt

http://betterlogic.com/roger/2010/07/fast-screen-capture/comment-page-1/#comment-5193

И тот, который вы упомянули (fraps, подключающийся к DLL D3D), вероятно, является единственным способом для приложений D3D, но не будет работать с настольным захватом Windows XP. Так что теперь я просто хочу, чтобы на обычных окнах для рабочего стола были одинаково быстрые фреймы... кто-нибудь?

(Я думаю, что с помощью aero вы могли бы использовать крючки, похожие на fraps, но пользователям XP было бы не повезло).

Также очевидно изменение глубины битов экрана и/или отключение аппаратного ускорения. может помочь (и/или отключить aero).

https://github.com/rdp/screen-capture-recorder-program включает в себя достаточно быструю утилиту захвата на основе BitBlt и тестовый маркер как часть его установки, что позволяет вам тестировать BitBlt чтобы оптимизировать их.

VirtualDub также имеет модуль захвата экрана "opengl", который, как говорят, работает быстро и выполняет такие функции, как обнаружение изменений http://www.virtualdub.org/blog/pivot/entry.php?id=290

Ответ 9

Вы можете попробовать проект с открытым исходным кодом С++ WinRobot @ git, мощный захват экрана

CComPtr<IWinRobotService> pService;
hr = pService.CoCreateInstance(__uuidof(ServiceHost) );

//get active console session
CComPtr<IUnknown> pUnk;
hr = pService->GetActiveConsoleSession(&pUnk);
CComQIPtr<IWinRobotSession> pSession = pUnk;

// capture screen
pUnk = 0;
hr = pSession->CreateScreenCapture(0,0,1280,800,&pUnk);

// get screen image data(with file mapping)
CComQIPtr<IScreenBufferStream> pBuffer = pUnk;

Поддержка:

  • Окно UAC
  • Winlogon
  • DirectShowOverlay

Ответ 10

Я сам делаю это с directx и думаю, что это так быстро, как вы бы хотели. У меня нет быстрого кода, но я нашел этот, который должен быть полезен. версия directx11 не должна сильно различаться, directx9 может быть немного больше, но это путь

Ответ 11

Я понимаю, что следующее предложение не отвечает на ваш вопрос, но самый простой метод, который я нашел для захвата быстро меняющегося представления DirectX, заключается в подключении видеокамеры к порту S-video видеокарты и записывать изображения в виде фильма. Затем переместите видео с камеры обратно в файл MPG, WMV, AVI и т.д. На компьютере.