it-swarm.com.de

Schnellste Methode zur Bildschirmaufnahme unter Windows

Ich möchte ein Screencasting-Programm für die Windows-Plattform schreiben, bin mir jedoch nicht sicher, wie ich den Bildschirm erfassen soll. Die einzige Methode, die mir bekannt ist, ist die Verwendung von GDI, aber ich bin neugierig, ob es andere Möglichkeiten gibt, dies zu tun, und wenn ja, welche verursachen den geringsten Overhead? Geschwindigkeit ist eine Priorität.

Das Screencasting-Programm ist für die Aufnahme von Spielmaterial vorgesehen. Sollte dies jedoch die Auswahl einschränken, bin ich für weitere Vorschläge offen, die nicht in diesen Bereich fallen. Wissen ist schließlich nicht schlecht.

Bearbeiten : Ich bin auf diesen Artikel gestoßen: Verschiedene Methoden zum Erfassen des Bildschirms . Es hat mich mit der Windows Media API-Methode und der DirectX-Methode vertraut gemacht. In der Schlussfolgerung wird erwähnt, dass das Deaktivieren der Hardwarebeschleunigung die Leistung der Erfassungsanwendung drastisch verbessern kann. Ich bin gespannt, warum das so ist. Könnte jemand die fehlenden Lücken für mich ausfüllen?

Bearbeiten : Ich habe gelesen, dass Screencasting-Programme wie Camtasia ihren eigenen Capture-Treiber verwenden. Könnte mir jemand eine ausführliche Erklärung geben, wie es funktioniert und warum es schneller ist? Möglicherweise benötige ich auch Anleitungen zur Implementierung, aber ich bin mir sicher, dass es sowieso eine vorhandene Dokumentation gibt.

Außerdem weiß ich jetzt, wie FRAPS den Bildschirm aufzeichnet. Es bindet die zugrunde liegende Grafik-API ein, um aus dem Rückpuffer zu lesen. Soweit ich weiß, ist dies schneller als das Lesen aus dem Front-Buffer, da Sie eher aus dem System-RAM als aus dem Video-RAM lesen. Sie können den Artikel lesen hier .

147
someguy

Dies ist, was ich verwende, um einzelne Frames zu sammeln, aber wenn Sie dies ändern und die beiden Ziele die ganze Zeit geöffnet lassen, können Sie es unter Verwendung eines statischen Zählers für den Dateinamen auf die Festplatte "streamen". - Ich kann mich nicht erinnern, wo ich das gefunden habe, aber es wurde geändert, danke an wen auch immer!

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

BEARBEITEN: Ich kann sehen, dass dies unter Ihrem ersten Bearbeitungslink als "the GDI way" aufgeführt ist. Dies ist immer noch ein anständiger Weg, selbst mit der Leistungsempfehlung auf dieser Site, die Sie erhalten können zu 30fps leicht würde ich denken.

Von dies Kommentar (Ich habe keine Erfahrung damit, ich beziehe mich nur auf jemanden, der dies tut):

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

// ..delete the bitmap you were using to capture frames..
DeleteObject(hbDesktop);

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

Ich sage nicht, dass dies die schnellste ist, aber die Operation BitBlt ist im Allgemeinen sehr schnell, wenn Sie zwischen kompatiblen Gerätekontexten kopieren.

Als Referenz implementiert Open Broadcaster Software so etwas als Teil ihrer "dc_capture" -Methode, anstatt den Zielkontext hDest mit CreateCompatibleDC Sie verwenden ein IDXGISurface1 , das mit DirectX 10+ funktioniert. Wenn dies nicht unterstützt wird, wird auf CreateCompatibleDC zurückgegriffen.

Um es für die Verwendung einer bestimmten Anwendung zu ändern, müssen Sie die erste Zeile in GetDC(game) ändern, wobei game das Handle des Spielfensters ist, und dann das richtige height festlegen. und width des Spielfensters auch.

Sobald Sie die Pixel in hDest/hbDesktop haben, müssen Sie sie noch in einer Datei speichern. Wenn Sie jedoch eine Bildschirmaufnahme machen, sollten Sie eine bestimmte Anzahl davon im Speicher puffern und in der Videodatei speichern Ich werde also nicht auf Code verweisen, um ein statisches Image auf der Festplatte zu speichern.

28
darvids0n

Ich habe eine Videoerfassungssoftware geschrieben, die FRAPS für DirectX-Anwendungen ähnelt. Der Quellcode ist verfügbar und mein Artikel erklärt die allgemeine Technik. Schauen Sie sich http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/ an

Respektieren Sie Ihre Fragen zur Leistung,

  • DirectX sollte schneller sein als GDI außer wenn Sie vom Frontbuffer lesen, der sehr langsam ist. Mein Ansatz ist ähnlich wie bei FRAPS (Lesen vom Backbuffer). Ich fange eine Reihe von Methoden von Direct3D-Schnittstellen ab.

  • Für die Videoaufnahme in Echtzeit (mit minimalen Auswirkungen auf die Anwendung) ist ein schneller Codec unerlässlich. FRAPS verwendet einen eigenen verlustfreien Video-Codec. Lagarith und HUFFYUV sind generische verlustfreie Videocodecs, die für Echtzeitanwendungen entwickelt wurden. Sie sollten sie sich ansehen, wenn Sie Videodateien ausgeben möchten.

  • Ein anderer Ansatz zum Aufzeichnen von Screencasts könnte darin bestehen, einen Spiegeltreiber zu schreiben. Laut Wikipedia: Wenn die Videospiegelung aktiv ist, wird jedes Mal, wenn das System an einer Stelle innerhalb des gespiegelten Bereichs auf das primäre Videogerät zeichnet, eine Kopie des Zeichenvorgangs auf dem gespiegelten Videogerät ausgeführt in Echtzeit. Siehe Spiegeltreiber bei MSDN: http://msdn.Microsoft.com/en-us/library/windows/hardware/ff568315 (v = vs. 85) .aspx .

17
Hernán

Ich benutze d3d9, um den Backbuffer zu erhalten und speichere diesen in einer PNG-Datei mit der d3dx-Bibliothek:

 IDirect3DSurface9 * surface; 
 
 //  GetBackBuffer  
 Idirect3ddevice9-> GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, & surface); 
 
 // Oberfläche speichern 
 D3DXSaveSurfaceToFileA ("filename.png", D3DXIFF_PNG, Oberfläche, NULL, NULL); 
 
 SAFE_RELEASE (Oberfläche); 

Dazu sollten Sie Ihren Swapbuffer mit erstellen

d3dpps.SwapEffect = D3DSWAPEFFECT_COPY ; // for screenshots.

(So ​​stellen Sie sicher, dass der Backbuffer nicht beschädigt ist, bevor Sie den Screenshot aufnehmen.).

15
bobobobo

In meiner Impression unterscheiden sich der GDI -Ansatz und der DX-Ansatz in seiner Natur. Das Malen mit GDI wendet die FLUSH-Methode an, der FLUSH-Ansatz zeichnet dann den Rahmen Löschen Sie es und zeichnen Sie ein weiteres Bild im selben Puffer neu. Dies führt dazu, dass das Flackern in Spielen eine hohe Bildrate erfordert.

  1. WARUM DX schneller? In DX (oder der Grafikwelt) wird eine ausgereiftere Methode namens Doppelpuffer-Rendering angewendet, bei der zwei Puffer vorhanden sind. Wenn der vordere Puffer für die Hardware vorhanden ist, können Sie ihn auch in den anderen Puffer rendern, und zwar nach dem Frame 1 Wenn das Rendern beendet ist, wechselt das System in den anderen Puffer (sperrt ihn, um ihn der Hardware zu präsentieren, und gibt den vorherigen Puffer frei). Auf diese Weise wird die Ineffizienz des Renderns erheblich verbessert.
  2. WARUM die Hardwarebeschleunigung schneller herunterdrehen? Beim Rendern mit doppeltem Puffer wird zwar die FPS verbessert, aber die Zeit für das Rendern ist immer noch begrenzt. Moderne Grafikhardware erfordert normalerweise eine Menge Optimierung beim Rendern, wie z. B. Anti-Aliasing. Dies ist sehr rechenintensiv. Wenn Sie keine qualitativ hochwertigen Grafiken benötigen, können Sie diese Option natürlich einfach deaktivieren. und das spart dir zeit.

Ich denke, was Sie wirklich brauchen, ist ein Wiedergabesystem, dem ich absolut zustimme, was die Leute besprochen haben.

10
zinking

Ich habe eine Klasse geschrieben, die die GDI) -Methode für die Bildschirmaufnahme implementiert hat. Auch ich wollte zusätzliche Geschwindigkeit. Nachdem ich die DirectX-Methode (über GetFrontBuffer) entdeckt hatte, habe ich versucht, diese zu beschleunigen.

Ich war bestürzt, als ich feststellte, dass GDI= ca. 2,5-mal schneller ist. Nach 100 Versuchen, mein Dual-Monitor-Display zu erfassen, betrug die durchschnittliche Geschwindigkeit der GDI=== 0,65 Sekunden pro Bildschirmaufnahme, Während die DirectX-Methode im Durchschnitt 1,72 Sekunden betrug, ist GDI laut meinen Tests definitiv schneller als GetFrontBuffer.

Ich konnte Brandrews Code nicht zum Testen von DirectX über GetRenderTargetData bringen. Die Bildschirmkopie kam rein schwarz heraus. Allerdings könnte es diesen leeren Bildschirm superschnell kopieren! Ich werde weiter daran basteln und hoffe, eine funktionierende Version zu bekommen, um echte Ergebnisse daraus zu sehen.

9
rotanimod

Ein paar Dinge, die ich herausfinden konnte: Anscheinend ist die Verwendung eines "Spiegeltreibers" schnell, obwohl ich keinen OSS-Treiber kenne.

Warum ist RDP im Vergleich zu anderen Fernbedienungsprogrammen so schnell?

Außerdem sind anscheinend einige Windungen von StretchRect schneller als BitBlt

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

Und die, die Sie erwähnt haben (Fraps, die sich in die D3D-DLL einbinden), ist wahrscheinlich die einzige Möglichkeit für D3D-Anwendungen, funktioniert aber nicht mit Windows XP= Desktop-Aufnahme. Ich wünschte, es gäbe eine fraps äquivalent geschwindigkeitsmäßig für normale desktop windows ... jemand?

(Ich denke, mit Aero können Sie möglicherweise fraps-ähnliche Hooks verwenden, aber XP Benutzer hätten Pech).

Offenbar ändern sich auch die Bittiefen des Bildschirms und/oder die Hardwarebeschleunigung wird deaktiviert. könnte helfen (und/oder Aero deaktivieren).

https://github.com/rdp/screen-capture-recorder-program enthält ein relativ schnelles BitBlt-basiertes Erfassungsdienstprogramm und einen Benchmarker als Teil der Installation, mit dem Sie die BitBlt-Geschwindigkeiten für Benchmarks festlegen können optimieren sie.

VirtualDub hat auch ein "opengl" -Screen-Capture-Modul, das angeblich schnell ist und Dinge wie Änderungserkennung erledigt http://www.virtualdub.org/blog/pivot/entry.php?id=29

8
rogerdpack

Für C++ können Sie Folgendes verwenden: http://www.pinvoke.net/default.aspx/gdi32/BitBlt.html
Dies funktioniert möglicherweise nicht bei allen Arten von 3D-Anwendungen/Video-Apps. Dann ist dieser Link möglicherweise nützlicher, da 3 verschiedene Methoden beschrieben werden, die Sie verwenden können.

Alte Antwort (C #):
Sie können System.Drawing.Graphics.Copy verwenden, aber es ist nicht sehr schnell.

Ein Beispielprojekt, das ich genau dazu geschrieben habe: http://blog.tedd.no/index.php/2010/08/16/c-image-analysis-auto-gaming-with-source/

Ich plane, dieses Beispiel mit einer schnelleren Methode wie Direct3D zu aktualisieren: http://spazzarama.com/2009/02/07/screencapture-with-direct3d/

Und hier ist ein Link zum Aufnehmen von Videos: Wie wird ein Bildschirm aufgenommen, um ein Video mit C # .Net zu erstellen?

8
Tedd Hansen

Sie können das Open-Source-Projekt c ++ ausprobieren WinRobot @git , ein leistungsstarker Bildschirmfotograf

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;

Unterstützung :

  • UAC-Fenster
  • Winlogon
  • DirectShowOverlay
5
Cayman

Mir ist klar, dass der folgende Vorschlag Ihre Frage nicht beantwortet, aber die einfachste Methode, die ich gefunden habe, um eine sich schnell ändernde DirectX-Ansicht zu erfassen, ist das Einstecken einer Videokamera in den S-Video-Anschluss des Videos und zeichnen Sie die Bilder als Film auf. Übertragen Sie dann das Video von der Kamera zurück in eine MPG-, WMV-, AVI-Datei usw. auf dem Computer.

3
Pierre

ich selbst mache es mit DirectX und denke, es ist so schnell, wie du es gerne hättest. Ich habe kein Beispiel für einen schnellen Code, aber ich habe this gefunden, was nützlich sein sollte. die directx11 version sollte sich nicht wesentlich unterscheiden, directx9 vielleicht etwas mehr, aber das ist der richtige weg

3
cppanda

Mit Windows 8 hat Microsoft die Windows Desktop Duplication-API eingeführt. Das ist die offiziell empfohlene Vorgehensweise. Eine nette Funktion für Screencasts ist, dass sie Fensterbewegungen erkennt, sodass Sie Blockdeltas übertragen können, wenn Fenster verschoben werden, anstatt rohe Pixel. Außerdem erfahren Sie, welche Rechtecke sich von einem Frame zum nächsten geändert haben.

Der Microsoft-Beispielcode ist ziemlich komplex, aber die API ist tatsächlich einfach und benutzerfreundlich. Ich habe ein Beispielprojekt zusammengestellt, das viel einfacher ist als das offizielle Beispiel:

https://github.com/bmharper/WindowsDesktopDuplicationSample

Dokumente: https://docs.Microsoft.com/en-gb/windows/desktop/direct3ddxgi/desktop-dup-api

Offizieller Microsoft-Beispielcode: https://code.msdn.Microsoft.com/windowsdesktop/Desktop-Duplication-Sample-da4c696a

2
Ben Harper