El método más rápido de captura de pantalla

Quiero escribir un progtwig de screencasting para la plataforma de Windows, pero no estoy seguro de cómo capturar la pantalla. El único método que conozco es el uso de GDI, pero tengo curiosidad de saber si hay otras maneras de hacerlo y, si las hay, ¿cuál es el que menos gastos genera? La velocidad es una prioridad.

El progtwig de screencasting será para grabar metraje del juego, aunque, si esto reduce las opciones, todavía estoy abierto para cualquier otra sugerencia que caiga fuera de este scope. El conocimiento no es malo, después de todo.

Editar : me encontré con este artículo: varios métodos para capturar la pantalla . Me ha presentado la manera de hacerlo de la API de Windows Media y la forma de hacerlo de DirectX. Menciona en la Conclusión que la aceleración del hardware de deshabilitación podría mejorar drásticamente el rendimiento de la aplicación de captura. Tengo curiosidad de por qué esto es. ¿Podría alguien completar los espacios en blanco que falta para mí?

Editar : Leí que los progtwigs de screencasting como Camtasia usan su propio controlador de captura. ¿Podría alguien darme una explicación detallada sobre cómo funciona y por qué es más rápido? También puedo necesitar orientación para implementar algo así, pero estoy seguro de que hay documentación existente de todos modos.

Además, ahora sé cómo FRAPS graba la pantalla. Engancha la API gráfica subyacente para leer desde el buffer posterior. Por lo que entiendo, esto es más rápido que leer desde el buffer frontal, porque estás leyendo desde la RAM del sistema, en lugar de la RAM de video. Puedes leer el artículo aquí .

Esto es lo que uso para recostackr marcos individuales, pero si modifica esto y mantiene los dos objectives abiertos todo el tiempo, entonces podría “transmitirlos” al disco utilizando un contador estático para el nombre del archivo. – No recuerdo dónde encontré esto, pero ha sido modificado, ¡gracias a quien sea!

 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(); } 

EDIT: puedo ver que esto se encuentra debajo de su primer enlace de edición como “el modo GDI”. Esta sigue siendo una buena forma de ir incluso con el asesoramiento de rendimiento en ese sitio, puede llegar a 30 fps fácilmente, creo.

A partir de este comentario (no tengo experiencia haciendo esto, solo estoy haciendo referencia a alguien que lo haga):

 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); 

No digo que este sea el más rápido, pero la operación de BitBlt generalmente es muy rápida si está copiando entre contextos de dispositivos compatibles.

Como referencia, Open Broadcaster Software implementa algo como esto como parte de su método “dc_capture” , aunque en lugar de crear el contexto de destino hDest utilizando CreateCompatibleDC utilizan una IDXGISurface1 , que funciona con DirectX 10+. Si no hay soporte para esto, CreateCompatibleDC a CreateCompatibleDC .

Para cambiarlo y usar una aplicación específica, debes cambiar la primera línea a GetDC(game) donde el game es el control de la ventana del juego, y luego establecer el height y el width correctos de la ventana del juego también.

Una vez que tenga los píxeles en hDest / hbDesktop, aún necesita guardarlos en un archivo, pero si está haciendo una captura de pantalla, entonces creo que querría almacenar un cierto número de ellos en la memoria y guardarlos en el archivo de video. en trozos, así que no apuntaré al código para guardar una imagen estática en el disco.

Escribí un software de captura de video, similar a FRAPS para aplicaciones DirectX. El código fuente está disponible y mi artículo explica la técnica general. Mira http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/

Respeto a sus preguntas relacionadas con el rendimiento,

  • DirectX debe ser más rápido que GDI, excepto cuando está leyendo desde el FrontBuffer, que es muy lento. Mi enfoque es similar a FRAPS (leyendo de backbuffer). Yo intercepto un conjunto de métodos de las interfaces Direct3D.

  • Para la grabación de video en tiempo real (con un impacto mínimo en la aplicación), un códec rápido es esencial. FRAPS usa su propio códec de video sin pérdida. Lagarith y HUFFYUV son códecs de video sin pérdida generics diseñados para aplicaciones en tiempo real. Debería verlos si quiere generar archivos de video.

  • Otro enfoque para grabar screencasts podría ser escribir un controlador Mirror. Según Wikipedia: cuando la duplicación de video está activa, cada vez que el sistema se acerca al dispositivo de video principal en una ubicación dentro del área duplicada, se ejecuta una copia de la operación de dibujar en el dispositivo de video duplicado en tiempo real. Consulte los controladores espejo en MSDN: http://msdn.microsoft.com/en-us/library/windows/hardware/ff568315(v=vs.85).aspx .

Utilizo d3d9 para obtener el backbuffer y lo guardo en un archivo png usando la biblioteca d3dx:

     IDirect3DSurface9 * superficie;

     // GetBackBuffer
     idirect3ddevice9-> GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, y superficie);

     // guarda la superficie
     D3DXSaveSurfaceToFileA ("filename.png", D3DXIFF_PNG, surface, NULL, NULL);

     SAFE_RELEASE (superficie);

Para hacer esto, debe crear su swapbuffer con

 d3dpps.SwapEffect = D3DSWAPEFFECT_COPY ; // for screenshots. 

(Entonces, usted garantiza que el backbuffer no está destrozado antes de tomar la captura de pantalla).

Escribí una clase que implementó el método GDI para la captura de pantalla. Yo también quería velocidad extra así que, después de descubrir el método de DirectX (a través de GetFrontBuffer) lo intenté, esperando que fuera más rápido.

Me consternó descubrir que GDI tiene un rendimiento de 2.5 veces más rápido. Después de 100 pruebas que capturaron mi monitor dual, la implementación de GDI promedió 0.65s por captura de pantalla, mientras que el método de DirectX promedió 1.72s. Entonces, GDI es definitivamente más rápido que GetFrontBuffer, según mis pruebas.

No pude obtener el código de Brandrew funcionando para probar DirectX a través de GetRenderTargetData. La copia de la pantalla salió puramente negra. Sin embargo, ¡podría copiar esa pantalla en blanco súper rápido! Voy a seguir jugando con eso y espero obtener una versión de trabajo para ver resultados reales de la misma.

En mi impresión, el enfoque GDI y el enfoque DX son diferentes en su naturaleza. pintar usando GDI aplica el método FLUSH, el enfoque FLUSH dibuja el marco, luego lo borra y vuelve a dibujar otro marco en el mismo buffer, esto dará como resultado que el parpadeo en los juegos requiera una alta velocidad de cuadro.

  1. ¿POR QUÉ DX más rápido? en DX (o mundo de gráficos), se aplica un método más maduro denominado doble buffer, donde están presentes dos búferes, cuando se presenta el búfer frontal al hardware, también se puede procesar en el otro búfer, luego, después de que el fotogtwig 1 esté finalizado, el sistema cambia al otro buffer (lo bloquea para presentarlo al hardware, y libera el buffer anterior), de esta forma la ineficiencia del renderizado se mejora enormemente.
  2. ¿POR QUÉ bajar la aceleración de hardware más rápido? aunque con la representación de doble buffer, se mejora el FPS, pero el tiempo de renderización sigue siendo limitado. El hardware gráfico moderno por lo general implica una gran optimización durante la renderización, por lo general, como anti-aliasing, esto es muy intensivo en computación, si no se requieren gráficos de alta calidad, por supuesto, puede desactivar esta opción. y esto te ahorrará tiempo.

Creo que lo que realmente necesitas es un sistema de reproducción, que estoy totalmente de acuerdo con lo que la gente discutió.

Para C ++ puede usar: http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html
Esto puede no funcionar en todos los tipos de aplicaciones / aplicaciones de video 3D. Entonces este enlace puede ser más útil ya que describe 3 métodos diferentes que puede usar.

Respuesta anterior (C #):
Puede usar System.Drawing.Graphics.Copy , pero no es muy rápido.

Un proyecto de muestra que escribí haciendo exactamente esto: http://blog.tedd.no/index.php/2010/08/16/c-image-analysis-auto-gaming-with-source/

Planeo actualizar esta muestra usando un método más rápido como Direct3D: http://spazzatwig.com/2009/02/07/screencapture-with-direct3d/

Y aquí hay un enlace para capturar video: ¿Cómo capturar pantalla para ser video usando C # .Net?

Algunas cosas que pude ver: aparentemente usar un “controlador de espejo” es rápido, aunque no conozco un OSS.

¿Por qué el RDP es tan rápido comparado con otro software de control remoto?

También aparentemente usar algunas circunvoluciones de StretchRect es más rápido que BitBlt

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

Y el que mencionaste (los fraps conectados a los dll de D3D) es probablemente la única forma para las aplicaciones D3D, pero no funcionará con la captura de escritorio de Windows XP. Así que ahora solo desearía que hubiera un fraps equivalente en velocidad para las ventanas normales de escritorio … ¿Alguien?

(Creo que con la tecnología aeronáutica es posible que puedas utilizar anzuelos tipo fraps, pero los usuarios de XP no tendrán suerte).

También parece que se cambian las profundidades de bits de la pantalla y / o se desactiva la aceleración de hardware. podría ayudar (y / o desactivar aero).

https://github.com/rdp/screen-capture-recorder-program incluye una utilidad de captura basada en BitBlt razonablemente rápida y un benchmarker como parte de su instalación, que puede permitirle comparar las velocidades de BitBlt para optimizarlas.

VirtualDub también tiene un módulo de captura de pantalla “abierto” que se dice que es rápido y hace cosas como detección de cambios http://www.virtualdub.org/blog/pivot/entry.php?id=290

Puede probar el proyecto de código abierto de c ++ WinRobot @git , un potente captor de pantalla

 CComPtr pService; hr = pService.CoCreateInstance(__uuidof(ServiceHost) ); //get active console session CComPtr pUnk; hr = pService->GetActiveConsoleSession(&pUnk); CComQIPtr pSession = pUnk; // capture screen pUnk = 0; hr = pSession->CreateScreenCapture(0,0,1280,800,&pUnk); // get screen image data(with file mapping) CComQIPtr pBuffer = pUnk; 

Soporte:

  • Ventana UAC
  • Winlogon
  • DirectShowOverlay

Yo mismo lo hago con DirectX y creo que es tan rápido como quisieras que fuera. No tengo una muestra de código rápido, pero encontré esto que debería ser útil. la versión de DirectX11 no debería diferir mucho, directx9 quizás un poco más, pero ese es el camino a seguir

Me doy cuenta de que la siguiente sugerencia no responde su pregunta, pero el método más simple que he encontrado para capturar una vista de DirectX que cambia rápidamente es conectar una cámara de video en el puerto de S-video de la tarjeta de video y grabar las imágenes como una película. Luego, transfiera el video de la cámara a un archivo MPG, WMV, AVI, etc. en la computadora.