2012-03-09 12 views
13

po całym dniu testów wpadłem z tym kodem, który przechwytuje bieżącego ekranu przy użyciu DirectX (SlimDX) i zapisuje go do pliku:Saving Surface do bitmap i optymalizacji DirectX przechwytywania ekranu w 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; 
} 

potem wykonaj następujące czynności:

DxScreenCapture sc = new DxScreenCapture(); 

..code tutaj

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

wyniki:

0. kiedy nie zapisuję powierzchni: śr. upłynął czas: 80-90ms

1. kiedy również zapiszę plik Surface to BMP: format: ImageFileFormat.Bmp, śr. czas trwania: 120ms, rozmiar pliku: 7mb

2. Kiedy również zapiszę plik Surface to PNG: format: ImageFileFormat.Png, śr. Upływający czas: 800ms, rozmiar pliku: 300 KB

Pytania są:

1. Czy to możliwe, aby zoptymalizować bieżące przechwytywanie obrazu? Zgodnie z tym artykułem - przechwytywanie ekranu DirectX powinno być szybsze niż GDI. Dla mnie GDI zwykle zajmuje 20 ms, aby uzyskać "Bitmapę", podczas gdy uzyskanie "Surfare" za pomocą DX (bez zapisywania) zajmuje 80 ms.

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

2a. Jak szybciej zapisać format powierzchni Surface na PNG? Kiedy zachowuję powierzchnię do pliku BMP 7mb, zajmuje to prawie 6 razy mniej czasu niż wtedy, gdy zapisuję tę samą powierzchnię na pliku PNG 300kb.

2b. Czy można zapisać Surface bezpośrednio w Bitmapie, więc nie muszę tworzyć plików tymczasowych?

Nie muszę więc wykonywać następujących czynności: Powierzchnia -> plik obrazu; plik obrazu otwarty -> bitmap;, ale zamiast tego: Powierzchnia -> mapa bitowa

to wszystko na teraz. Chętnie przyjmę wszelkie wskazówki, dzięki!

Edit:

Wystarczy rozwiązać 2b wykonując:

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

jest szybszy niż:

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

przez 100 ms !!!Tak, nie mogłem uwierzyć własnym oczom;) Nie podoba mi się pomysł tworzenia plików tymczasowych, ale 50% wzrost wydajności (100-200 ms zamiast 200-300 +) jest bardzo dobrą rzeczą.

+0

Myślę, że png może kompresować szybciej niż 800 ms. Spróbuj, czy jest to szybsze, jeśli po raz pierwszy napiszesz do memorystream. –

Odpowiedz

0

jeśli nie chcesz korzystać z biblioteki SlimDX można także spróbować

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

i spróbuj to samo dla .png - Nie testowane wydajność ale musiał szybciej niż przy użyciu dysk tymczasowy złożyć :)

i jak na 1 pytanie - spróbuj utworzyć powierzchnię tylko raz i nie na każdym zrzucie wprowadzane do bufora danych To urządzenie i stworzyć bitmapy

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

powinno to zaoszczędzić trochę czasu :)

+0

SlimDX nie działa w ten sposób .. Dostaję mnóstwo błędów z "SurfaceLoader" (Nazwa "SurfaceLoader" nie istnieje w bieżącym kontekście). Myślę, że mam coś wspólnego z biblioteką "Managed DirectX", która nie jest obsługiwana w .net 4, więc nie mogę dodać odniesienia. To jest jak C# VisualStudion nie wie, czym są "SurfaceLoader" i "GraphicsStream" .. – Alex

+0

P.S. Zainstalowałem już DX SDK, ale niestety w VS2010 nie ma odniesienia "Managed DX". Po pewnym wykopaniu dowiedziałem się, że nie jesteśmy dłużsi (SDK + z czerwca 2010) możemy używać DX, wszystko, co pozostało, to SlimDX (opakowanie) lub XNA (używane głównie do gry). – Alex

+1

SurfaceLoader nie jest w SlimDX, ale w natywnym DirectX (Microsoft.DirectX.Direct3D.SurfaceLoader) i działa na .NET4 ... A jeśli nie możesz znaleźć biblioteki dll dla zarządzanego kodu, spójrz na "C: \ Windows \ Microsoft.NET \" DirectX for Managed Code ". – Runaurufu

Powiązane problemy