2012-03-09 21 views
13

después de todo un día de pruebas me ocurrió con este código, que captura la pantalla actual usando DirectX (SlimDX) y lo guarda en un archivo:Ahorro de superficie de mapa de bits y la optimización de la captura de pantalla de DirectX en C#

Device d; 

public DxScreenCapture() 
{ 
    PresentParameters present_params = new PresentParameters(); 
    present_params.Windowed = true; 
    present_params.SwapEffect = SwapEffect.Discard; 
    d = new Device(new Direct3D(), 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.SoftwareVertexProcessing, present_params); 
} 

public Surface CaptureScreen() 
{ 
    Surface s = Surface.CreateOffscreenPlain(d, Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, Format.A8R8G8B8, Pool.Scratch); 
    d.GetFrontBufferData(0, s); 
    return s; 
} 

entonces hago lo siguiente:

DxScreenCapture sc = new DxScreenCapture(); 

..code aquí

private void button1_Click(object sender, EventArgs e) 
    { 

     Stopwatch stopwatch = new Stopwatch(); 

     // Begin timing 
     stopwatch.Start(); 

     Surface s = sc.CaptureScreen(); 
     Surface.ToFile(s, @"c:\temp\test.png", ImageFileFormat.Png); 

     s.Dispose(); 

     stopwatch.Stop(); 

     textBox1.Text = ("Elapsed:" + stopwatch.Elapsed.TotalMilliseconds); 
    } 

el los resultados son:

0. cuando no guardo la superficie: avg. tiempo transcurrido: 80-90ms

1. cuando también guardo el archivo Surface to BMP: formato: ImageFileFormat.Bmp, avg. tiempo transcurrido: 120ms, tamaño de archivo: 7mb

2. cuando también guardo el archivo Surface to PNG: format: ImageFileFormat.Png, avg. Tiempo transcurrido: 800ms, tamaño de archivo: 300 KB

Las preguntas son:

1. ¿Es posible optimizar la captura de la imagen actual? Según este artículo, la captura de pantalla de Directx debe ser más rápida que GDI. Para mí, GDI usualmente toma 20 ms para obtener un "Bitmap", mientras que toma 80ms para obtener "Surfare" usando DX (ambos sin guardar).

http://www.codeproject.com/Articles/274461/Very-fast-screen-capture-using-DirectX-in-Csharp

2a. ¿Cómo guardar formato de imagen de Superficie a PNG más rápido? Cuando guardo la superficie en un archivo BMP de 7mb, me lleva casi 6 veces menos tiempo que cuando guardo la misma superficie en un archivo PNG de 300 kb ..

2b. ¿Es posible guardar Surface directamente en Bitmap para que no tenga que crear archivos temporales?

Así que no tengo que hacer lo siguiente: Superficie -> archivo de imagen; archivo de imagen abierto -> mapa de bits;, pero en su lugar: Superficie -> mapa de bits

eso es todo por ahora. Acepto gustosamente cualquier consejo, ¡gracias!

Editar:

Sólo resuelto 2b haciendo:

Bitmap bitmap = new Bitmap(SlimDX.Direct3D9.Surface.ToStream(s, SlimDX.Direct3D9.ImageFileFormat.Bmp)); 

Edit2:

Surface.ToFile(s, @"C:\temp\test.bmp", ImageFileFormat.Bmp); 
Bitmap bitmap = new Bitmap(@"C:\temp\test.bmp"); 

es más rápido que:

Bitmap bitmap = new Bitmap(SlimDX.Direct3D9.Surface.ToStream(s, SlimDX.Direct3D9.ImageFileFormat.Bmp)); 

por 100 ms !!!Sí, no podía creer lo que veía también;) No me gusta la idea de creación temporal de archivos, pero un 50% de aumento en el rendimiento (100-200 ms en vez de 200-300 +) es algo muy bueno.

+0

Creo que png puede comprimir más rápido que 800 ms. Pruebe si es más rápido si primero escribe en un flujo de memoria. –

Respuesta

0

si no desea utilizar la biblioteca SlimDX también puede probar

public Bitmap GimmeBitmap(Surface s) 
{ 
    GraphicsStream gs = SurfaceLoader.SaveToStream(ImageFileFormat.Bmp, s); 
    return new Bitmap(gs); 
} 

y tratar de la misma para .png - yo no probado rendimiento, sino que tiene que ser más rápido que el uso de disco temporal :) presentar

y en cuanto a primera pregunta - tratar de una sola vez y crear una superficie que en cada pantalla sólo se puso en datos del buffer de dispositivos y crear mapa de bits

d.GetFrontBufferData(0, s); 
return new Bitmap(SurfaceLoader.SaveToStream(ImageFileFormat.Bmp, s)); 

esto debería ahorrarle algo de tiempo :)

+0

SlimDX no funciona de esa manera ... Recibo toneladas de errores con "SurfaceLoader" (El nombre "SurfaceLoader" no existe en el contexto actual). Creo que tengo algo que ver con la biblioteca "Managed DirectX", que no es compatible con .net 4, así que no puedo agregar la referencia. Es como C# VisualStudion no sabe lo que son "SurfaceLoader" y "GraphicsStream" .. – Alex

+0

P.S. Ya instalé DX SDK pero desafortunadamente no hay referencia de "Managed DX" en VS2010. Después de algunas excavaciones descubrí que ya no tenemos más (junio de 2010 SDK +) podemos usar DX, todo lo que queda es SlimDX (wrapper) o XNA (utilizado principalmente para el desarrollo de juegos). – Alex

+1

SurfaceLoader no está en SlimDX, sino en DirectX nativo (Microsoft.DirectX.Direct3D.SurfaceLoader) y funciona en .NET4 ... Y si no puede encontrar dll para el código administrado, vaya a "C: \ Windows \ Microsoft.NET \". DirectX para código administrado ". – Runaurufu

Cuestiones relacionadas