Schnellste Methode zur Bildschirmaufnahme unter Windows

159

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

Das Screencasting-Programm dient zur Aufnahme von Spielmaterial. Wenn dies jedoch die Optionen einschränkt, bin ich immer noch offen für andere Vorschläge, 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 in die Windows Media API-Methode und die DirectX-Methode eingeführt. 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 von so etwas, aber ich bin mir sicher, dass ohnehin bereits Dokumentation vorhanden ist.

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

irgendein Typ
quelle
Haben Sie darüber nachgedacht, den Inhalt des Bildschirms mithilfe eines Wiedergabesystems grafisch aufzuzeichnen, anstatt ihn grafisch aufzuzeichnen ?
Benjamin Lindley
2
Sie müssen nichts einhaken. Sie müssen nur Ihre Eingabeereignisse schreiben, damit sie das Spiel nicht direkt steuern, sondern andere Funktionen aufrufen. Wenn der Spieler beispielsweise die linke Taste drückt, verringern Sie nicht einfach die x-Position des Spielers. Stattdessen rufen Sie eine Funktion auf, wie z MovePlayerLeft(). Außerdem zeichnen Sie die Zeit und Dauer von Tastendrücken und anderen Eingaben auf. Wenn Sie sich dann im Wiedergabemodus befinden, ignorieren Sie einfach die Eingabe und lesen stattdessen die aufgezeichneten Daten. Wenn Sie in den Daten einen linken Tastendruck sehen, rufen Sie an MovePlayerLeft().
Benjamin Lindley
1
@PigBen Dies ist eine generische Anwendung zum Aufzeichnen von Spielmaterial. Es ist nicht für ein bestimmtes Spiel. Jemand, der die linke Taste drückt, könnte nach allem, was ich weiß, bedeuten, sich nach rechts zu bewegen. Außerdem haben Sie keine Ereignisse berücksichtigt, die nicht vom Benutzer beeinflusst werden. 'Und was ist mit dem Rendern?
Irgendwann
1
@someguy Ok, ich denke, Sie machen etwas viel Intensiveres. Ich hatte eine Routine hinzugefügt, die die oben genannten Methoden verwendet, um Wiederholungs-AVIs in einem Spiel mit etwa 30 fps ohne Probleme zu sparen. Ich habe einen Bildschirmrekorder mit mehreren Monitoren unter Verwendung der Windows-API für die "Personaloptimierung" erstellt, der jedoch selbst bei gezielten 4 Bildern pro Sekunde eine schlechte Leistung erbrachte.
AJG85
1
Es ist ein Open - Source - Spiegeltreiber für Windows auf UltraVNC des Endlagers hier ultravnc.svn.sourceforge.net/viewvc/ultravnc/...
Beached

Antworten:

62

Dies ist, was ich verwende, um einzelne Frames zu sammeln, aber wenn Sie dies ändern und die beiden Ziele die ganze Zeit offen halten, können Sie es mit einem statischen Zähler 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();
}
Brandrew
quelle
Vielen Dank. Ich habe vor einiger Zeit von dieser Methode gehört, die angeblich schneller ist als das Lesen aus dem Frontpuffer. Machst du es ehrlich so und funktioniert es richtig?
Irgendwann
Das Problem mit dem Frontpuffer ist der Zugriff, dh der Versuch, eine Ebene zu kopieren, die gerade gerendert wird, um die Kopie zu "unterbrechen". Es funktioniert gut genug für mich und frisst meine Festplatte!
Brandrew
@bobobobo Ich weiß nicht, wie es genau funktionieren würde, aber ich dachte darüber nach, so etwas wie Huffyuv zu verwenden. Bearbeiten: Oder lassen Sie den Benutzer aus verfügbaren Directshow-Filtern auswählen.
Irgendwann
1
Ich kann es einfach nicht schaffen, dass das funktioniert ... DirectX spuckt einen ungültigen Aufruf des GetRenderTargetData-Teils aus. Natürlich muss die Art und Weise, wie Sie Ihr Gerät erstellen, eine große Bedeutung haben.
LightStriker
12
Downvote, es funktioniert nur für Ihre eigene Anwendung, kann also nicht zum Aufzeichnen generischer Programme verwendet werden
user3125280
32

BEARBEITEN: Ich kann sehen, dass dies unter Ihrem ersten Bearbeitungslink als "GDI-Weg" aufgeführt ist. Dies ist immer noch ein anständiger Weg, auch wenn Sie die Leistungsempfehlung auf dieser Website verwenden. Ich denke, Sie können problemlos 30 fps erreichen.

Aus diesem Kommentar (ich habe keine Erfahrung damit, ich verweise 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 der schnellste ist, aber der BitBltVorgang ist im Allgemeinen sehr schnell, wenn Sie zwischen kompatiblen Gerätekontexten kopieren.

Als Referenz öffnen Broadcaster Software implementiert etwas wie dies im Rahmen ihrer „dc_capture“ Methode, obwohl anstatt den Zielkontext zu schaffen hDestindem CreateCompatibleDCsie verwenden ein IDXGISurface1, die mit DirectX 10+ arbeitet. Wenn es dafür keine Unterstützung gibt, greifen sie zurück CreateCompatibleDC.

Um es zu ändern eine bestimmte Anwendung zu verwenden, müssen Sie die erste Zeile ändern , GetDC(game)wo gameist der Griff des Fensters des Spiels, und dann die richtige Setup heightund widthauch des Fensters des Spiels.

Sobald Sie die Pixel in hDest / hbDesktop haben, müssen Sie sie noch in einer Datei speichern. Wenn Sie jedoch eine Bildschirmaufnahme durchführen, sollten Sie eine bestimmte Anzahl davon im Speicher puffern und in der Videodatei speichern in Chunks, daher werde ich nicht auf Code zum Speichern eines statischen Images auf der Festplatte verweisen.


quelle
3
msdn.microsoft.com/en-us/library/dd183370%28VS.85%29.aspx Auszug: Wenn die Farbformate der Quell- und Zielgerätekontexte nicht übereinstimmen, konvertiert die BitBlt-Funktion das Quellfarbformat so, dass es mit dem Ziel übereinstimmt Format.
2
Einige Beweise, um dies zu belegen, wären gut. Haben Sie irgendwo einen Leistungsvergleich veröffentlicht oder einen genauen gesehen?
2
Versuchen Sie es mit einem Profil. Wie ich in der Post sagte, beziehe ich mich auf jemanden, der Erfahrung mit GDI hat. Wenn der Speicher verloren geht und Sie wissen, wie Sie ihn beheben können, bearbeiten Sie den Beitrag, um das Leck zu beseitigen.
1
Ich habe ungefähr 5 fps mit dieser Methode. Dies war auf einem Laptop mit integrierter Grafik, daher würde ich von einem Desktop mit einer echten Grafikkarte etwas Besseres erwarten, aber es ist immer noch sehr langsam.
Timmmm
1
@Timmmm Ich habe einen Verweis auf die Art und Weise hinzugefügt, wie OBS dies implementiert. Hoffentlich könnte das die Dinge für Sie etwas beschleunigen.
19

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 als GDI sein, außer wenn Sie aus dem Frontpuffer lesen, der sehr langsam ist. Mein Ansatz ähnelt FRAPS (Lesen aus dem 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 Videocodec. Lagarith und HUFFYUV sind generische verlustfreie Video-Codecs für Echtzeitanwendungen. 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 in Echtzeit auf dem gespiegelten Videogerät ausgeführt. Siehe Spiegeltreiber bei MSDN: http://msdn.microsoft.com/en-us/library/windows/hardware/ff568315(v=vs.85).aspx .

Hernán
quelle
16

Ich verwende d3d9, um den Backbuffer abzurufen, und speichere ihn mithilfe der d3dx-Bibliothek in einer PNG-Datei:

    IDirect3DSurface9 * Oberfläche;

    // GetBackBuffer
    idirect3ddevice9-> GetBackBuffer (0, 0, D3DBACKBUFFER_TYPE_MONO, & Oberfläche);

    // speichere die Oberfläche
    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.

(Sie garantieren also, dass der Backbuffer nicht beschädigt wird, bevor Sie den Screenshot machen).

Bobobobo
quelle
Sinnvoll, danke. Wissen Sie, was der Unterschied zwischen diesem und GetRenderTargetist?
Irgendwann
Dadurch wird nur das aktuelle Renderziel abgerufen (könnte eine andere Offscreen-Oberfläche sein, wenn jemand zum Zeitpunkt des Aufrufs eine Textur rendert).
Bobobobo
13

In meinem Eindruck unterscheiden sich der GDI-Ansatz und der DX-Ansatz in seiner Natur. Beim Malen mit GDI wird die FLUSH-Methode angewendet. Beim FLUSH-Ansatz wird der Frame gezeichnet, dann gelöscht und ein weiterer Frame im selben Puffer neu gezeichnet. Dies führt zu Flackern in Spielen, die eine hohe Framerate erfordern.

  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 der Hardware vorhanden ist, können Sie ihn auch in den anderen Puffer rendern, nachdem der Frame 1 ist Nach dem Rendern wechselt das System in den anderen Puffer (sperrt ihn für die Präsentation auf der Hardware und gibt den vorherigen Puffer frei). Auf diese Weise wird die Ineffizienz des Renderns erheblich verbessert.
  2. WARUM die Hardwarebeschleunigung schneller verringern? Obwohl beim Rendern mit doppeltem Puffer die FPS verbessert wird, ist die Zeit für das Rendern immer noch begrenzt. Moderne Grafikhardware erfordert normalerweise viel Optimierung beim Rendern, normalerweise wie 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 Ihnen Zeit.

Ich denke, was Sie wirklich brauchen, ist ein Wiederholungssystem, dem ich voll und ganz zustimme.

Zicken
quelle
1
In der Diskussion erfahren Sie, warum ein Wiedergabesystem nicht möglich ist. Das Screencasting-Programm ist nicht für ein bestimmtes Spiel geeignet.
Irgendwann am
10

Ich habe eine Klasse geschrieben, die die GDI-Methode für die Bildschirmaufnahme implementiert hat. Ich wollte auch zusätzliche Geschwindigkeit, also habe ich das versucht, nachdem ich die DirectX-Methode (über GetFrontBuffer) entdeckt hatte, und erwartet, dass sie schneller ist.

Ich war bestürzt festzustellen, dass GDI etwa 2,5-mal schneller arbeitet. Nach 100 Versuchen, mein Dual-Monitor-Display zu erfassen, betrug die GDI-Implementierung durchschnittlich 0,65 Sekunden pro Bildschirmaufnahme, während die DirectX-Methode durchschnittlich 1,72 Sekunden betrug. GDI ist also nach meinen Tests definitiv schneller als GetFrontBuffer.

Ich konnte Brandrews Code nicht zum Testen von DirectX über GetRenderTargetData verwenden. Die Bildschirmkopie war rein schwarz. Es könnte jedoch diesen leeren Bildschirm sehr schnell kopieren! Ich werde weiter daran basteln und hoffe, eine funktionierende Version zu bekommen, um echte Ergebnisse daraus zu sehen.

Rotanimod
quelle
Danke für die Information. Ich habe Brandrews Code nicht getestet, aber ich weiß, dass der GetRenderTargetDataAnsatz funktioniert. Vielleicht schreibe ich meine eigene Antwort, wenn ich meine Bewerbung abgeschlossen habe. Oder Sie können Ihre aktualisieren, sobald alles funktioniert.
Irgendwann am
0,65 pro Screencapture?! Eine gute GDI-Implementierung (Geräte in der Nähe halten usw.) sollte auf einem modernen Computer problemlos 30 fps in 1920 x 1200 erreichen.
Christopher Oezbek
Ich
gehe
Ich habe diesen Test in C # mit SlimDX durchgeführt und überraschenderweise die gleichen Ergebnisse gefunden. Möglicherweise hat dies damit zu tun, dass mit SlimDX für jedes Frame-Update ein neuer Stream und eine neue Bitmap erstellt werden müssen, anstatt sie einmal zu erstellen, zurückzuspulen und denselben Speicherort immer wieder zu überschreiben.
Cesar
Nur eine Klarstellung: Tatsächlich bezogen sich die "gleichen Ergebnisse" darauf, dass GDI schneller ist - wie @Christopher erwähnte, waren 30 fps + sehr machbar und ließen immer noch viel freie CPU übrig.
Cesar
8

Ein paar Dinge, die ich herausfinden konnte: Anscheinend ist die Verwendung eines "Spiegeltreibers" schnell, obwohl mir kein OSS bekannt ist.

Warum ist RDP im Vergleich zu anderen Fernbedienungssoftware so schnell?

Auch anscheinend sind einige Faltungen von StretchRect schneller als BitBlt

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

Und die von Ihnen erwähnte (Fraps, die sich in die D3D-DLLs einbinden) ist wahrscheinlich die einzige Möglichkeit für D3D-Anwendungen, funktioniert jedoch nicht mit Windows XP Desktop Capture. Jetzt wünschte ich mir nur, es gäbe ein Fraps, das hinsichtlich der Geschwindigkeit für normale Desktop-Fenster gleichwertig ist ... irgendjemand?

(Ich denke, mit Aero können Sie möglicherweise fraps-ähnliche Haken verwenden, aber XP-Benutzer hätten kein Glück).

Anscheinend auch Ändern der Bildschirmbittiefe und / oder Deaktivieren der Hardwarebeschleunigung. 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 seiner Installation, mit dem Sie BitBlt-Geschwindigkeiten messen können, um sie zu optimieren.

VirtualDub verfügt außerdem über ein "opengl" -Bildschirmerfassungsmodul, das angeblich schnell ist und beispielsweise Änderungen erkennt ( http://www.virtualdub.org/blog/pivot/entry.php?id=290)

Rogerdpack
quelle
Ich frage mich, ob es schneller sein wird, Ihren "Screen-Capture-Recorder" zu verwenden oder BitBlt selbst zu verwenden. Gibt es eine Optimierung in Ihrem Projekt?
Blez
Wenn Sie Bitblt selbst verwenden, vermeiden Sie möglicherweise ein zusätzliches Memcpy (Memcpy ist normalerweise nicht der größte Engpass, obwohl es einige Zeit in Anspruch nimmt - ich habe es hier nur wegen seines Benchmark-Dienstprogramms erwähnt, aber wenn Sie etwas oder eine Direktshow benötigen, ist es nett )
Rogerdpack
8

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 kann dieser Link nützlicher sein, da er 3 verschiedene Methoden beschreibt, 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 der Bildschirm mit C # .Net als Video aufgenommen?

Tedd Hansen
quelle
2
Ah, ich habe vergessen zu erwähnen, dass ich in C programmiere (möglicherweise in C ++) und nicht vorhabe, .NET zu verwenden. Schrecklich leid :/.
Irgendwann
BitBlt (GDI) war mir bereits bekannt. Ich werde mich jedoch mit Direct3D befassen. Vielen Dank!
Irgendwann
Ich habe mich vor ein paar Wochen damit befasst, bin aber noch nicht dazu gekommen, es umzusetzen. Direct3D ist !! Weg !! schneller als die in C # integrierte Methode, die GDI + verwendet.
Tedd Hansen
Ich habe meinen ursprünglichen Beitrag aktualisiert. Laut dem Link ist DirectX langsam, wenn GetFrontBufferData () aufgerufen werden muss. Ist dies bei der Aufnahme von Spielmaterial zu beachten? Könnten Sie das für mich kontextualisieren?
Irgendwann
1
GDI ist langsam, daher ist es nicht für die Problemdomäne geeignet. DirectX oder OpenGL wären die einzig sinnvolle Empfehlung.
6

Mit Windows 8 führte Microsoft die Windows Desktop Duplication API ein. 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 Rohpixel. Außerdem erfahren Sie, welche Rechtecke sich von einem Bild 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

Ben Harper
quelle
Das Github-Projekt funktioniert perfekt unter Windows 10, getestet mit Webvideo und Resident Evil 7. Das Beste ist, dass die CPU-Auslastung mit der Grafik-Upgrade-Rate skaliert.
jw_
Sobald Sie GPU-Z starten, greift dieses Programm nicht mehr auf den Bildschirm.
Marino Šimić
5

Sie können das Open-Source-Projekt WinRobot @git von c ++ ausprobieren , einen leistungsstarken Screen Capturer

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
Cayman
quelle
1
Das sind ... viele niedrige Haken. Die Aufnahmegeschwindigkeit ist erstaunlich, wenn Sie über Administratorrechte verfügen.
Toster-CX
Ich fand den Winrobot sehr kraftvoll und geschmeidig.
ashishgupta_mca
Ich habe WinRobot-Code studiert und nichts bahnbrechendes für die Bildschirmaufnahme gesehen: Es wird dasselbe CreateCompatibleDC..BitBlt verwendet. Es sei denn, es gibt etwas Magisches, wenn dies im Servicekontext ausgeführt wird?
Shekh
@ Shekh: Dein Studium war zu oberflächlich. Der Code verwendet IDirectDrawSurface7-> BltFast (), um den Bildschirm von der Bildschirmzeichnungsoberfläche auf eine Kopier-DD-Oberfläche zu kopieren, und verwendet dann eine Dateizuordnung, um das Bild zu kopieren. Es ist ziemlich komplex, da der Code in einem Dienst ausgeführt wird, bei dem Sie nicht einfach auf die Desktops zugreifen können.
Elmue
2

Ich selbst mache es mit DirectX und denke, es ist so schnell, wie Sie es sich wünschen würden. Ich habe kein schnelles Codebeispiel, aber ich fand das, was nützlich sein sollte. Die DirectX11-Version sollte sich nicht sehr unterscheiden, DirectX9 vielleicht ein bisschen mehr, aber das ist der richtige Weg

cppanda
quelle
2

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, besteht darin, eine Videokamera an den S-Video-Anschluss der Grafikkarte anzuschließen und die Bilder als aufzunehmen ein Film. Übertragen Sie dann das Video von der Kamera zurück in eine MPG-, WMV-, AVI- usw. Datei auf dem Computer.

Pierre
quelle
2

Die Bildschirmaufzeichnung kann in C # mithilfe der VLC-API erfolgen . Ich habe ein Beispielprogramm erstellt, um dies zu demonstrieren. Es verwendet die Bibliotheken LibVLCSharp und VideoLAN.LibVLC.Windows . Mit dieser plattformübergreifenden API können Sie viele weitere Funktionen im Zusammenhang mit dem Rendern von Videos erzielen.

API-Dokumentation finden Sie unter: LibVLCSharp API Github

using System;
using System.IO;
using System.Reflection;
using System.Threading;
using LibVLCSharp.Shared;

namespace ScreenRecorderNetApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Core.Initialize();

            using (var libVlc = new LibVLC())
            using (var mediaPlayer = new MediaPlayer(libVlc))
            {
                var media = new Media(libVlc, "screen://", FromType.FromLocation);
                media.AddOption(":screen-fps=24");
                media.AddOption(":sout=#transcode{vcodec=h264,vb=0,scale=0,acodec=mp4a,ab=128,channels=2,samplerate=44100}:file{dst=testvlc.mp4}");
                media.AddOption(":sout-keep");

                mediaPlayer.Play(media);
                Thread.Sleep(10*1000);
                mediaPlayer.Stop();
            }
        }
    }
}
Karthick
quelle
1
Wen es betrifft: Bitte beachten Sie, dass libvlc unter GPL veröffentlicht wird. Wenn Sie nicht beabsichtigen, Ihren Code unter der GPL freizugeben, verwenden Sie libvlc nicht.
Sebastian Cabot
Das ist nicht ganz richtig, LibVLC ist LGPL - es wurde 2011 neu lizenziert. Die VLC-Anwendung selbst bleibt GPL: videolan.org/press/lgpl-libvlc.html
Andrew
0

DXGI Desktop Capture

Projekt, das das Desktop-Image mit DXGI-Duplizierung erfasst. Speichert das aufgenommene Bild in verschiedenen Bildformaten (* .bmp; * .jpg; * .tif) in der Datei.

Dieses Beispiel ist in C ++ geschrieben. Sie benötigen auch Erfahrung mit DirectX (D3D11, D2D1).

Was die Anwendung kann

  • Wenn Sie mehr als einen Desktop-Monitor haben, können Sie auswählen.
  • Ändern Sie die Größe des aufgenommenen Desktop-Images.
  • Wählen Sie verschiedene Skalierungsmodi.
  • Sie können das Maussymbol im Ausgabebild ein- oder ausblenden.
  • Sie können das Bild für das Ausgabebild drehen oder als Standard beibehalten.
gerdogdu
quelle