DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Windowsspezifisches Forum , API ,..
Beiträge, die plattformübergreifend sind, gehören ins 'Allgemein'-Forum.
Benutzeravatar
Hoto
Beiträge: 294
Registriert: 01.09.2004 22:51

DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von Hoto »

Hat diese API noch nie Jemand hier benutzt? Leider finde ich keinen lauffähigen Beispielcode, nur das hier:

https://www.purebasic.fr/english/viewto ... 13&t=59425

Das ist sicherlich schon sehr hilfreich ist, leider stehe ich da mal wieder wie der Ochs vor dem Berg, ist über dem was ich sonst programmiere. Langsam muss ich einsehen, dass ich nicht mehr der Jüngte bin. :cry: Vielleicht hab ich aber auch nur seit Tagen ein Brett vor dem Kopf. :roll:

Vielleicht hat ja doch Jemand einen Code Schnipsel dazu rum liegen? Oder wenigstens einen hilfreichen Anhaltspunkt für mich?

Werde derweil mal weiter suchen, vielleicht geht mir ja doch noch ein Licht auf.

Edit: Lösung über die Open Source DLL DXGCap.dll: viewtopic.php?p=347617#p347617
Zuletzt geändert von Hoto am 22.06.2018 09:52, insgesamt 2-mal geändert.
Benutzeravatar
Hoto
Beiträge: 294
Registriert: 01.09.2004 22:51

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von Hoto »

Ich poste es auch noch mal hier rein, weil im anderen Thread geht es um das ganze Projekt an sich, hier nur um eben genau jene Funktion.

Ich hab mal etwas rumgesucht und dabei diesen VS C++ DDL/Lib Source gefunden, den ich nun versucht habe zu verwenden:
https://github.com/bryal/DXGCap

Das kompilieren des C++ Codes hat auf Anhieb Fehlerfrei funktioniert.

In PB sieht mein Code nun so aus, der leider nicht richtig funktioniert.

Code: Alles auswählen

UsePNGImageEncoder()

Define cs = 0, Width.i, Height.i, buf_size.i, *buf = #Null, o_size.i, *o_bytes

Import "DXGCap.lib"
  create_dxgi_manager()
  delete_dxgi_manager(*dxgi_manager)
  get_capture_source(*dxgi_manager)
  get_frame_bytes(*dxgi_manager, o_size, *o_bytes)
  get_output_dimensions(*dxgi_manager, Width, Height)
  refresh_output(*dxgi_manager)
  set_capture_source(*dxgi_manager,cs)
  set_timeout(*dxgi_manager,timeout)
EndImport

*dxgi_manager = create_dxgi_manager()
Debug *dxgi_manager ; sollte größer 0 sein
get_output_dimensions(*dxgi_manager,@Width,@Height)
Debug "w:"+Str(Width) + " h:" + Str(Height) ; wird korrekt angezeigt
refresh_output(*dxgi_manager)
Debug get_frame_bytes(*dxgi_manager,@buf_size,@*buf) ; sollte größer 0 sein
Debug get_capture_source(*dxgi_manager) ; gibt 0 aus

CreateImage(0,Width,Height,24,RGB(255,255,255))
x = 0 : y = 0 : z = 0
Debug PeekB(*buf) ; sollte nicht 0 sein, außer der erste SubPixel links oben ist tatsächlich 0 (bei Blau)
StartDrawing(ImageOutput(0))
  DrawingMode(#PB_2DDrawing_Default)
  For y = 0 To Height-1
    For x = 0 To Width-1
      Plot(x,y,RGB(PeekB(*buf+z+2),PeekB(*buf+z+1),PeekB(*buf+z))) ; BGRA8 Format
      z + 4
    Next
  Next
StopDrawing()
SaveImage(0,"testdxgi.png",#PB_ImagePlugin_PNG)
delete_dxgi_manager(*dxgi_manager)
Vielleicht sieht ja Jemand direkt wo das Problem liegen könnte. Ich schau mir das später noch mal an.

Nur quick und dirty zum testen.

Das Problem ist nun, dass er zwar die Bildschirm Auflösung korrekt ausließt und auch der Puffer mit den Bilddaten die korrekt Größe zu haben scheint (H * B * 4 inkl. Alpha), aber ich krieg als Farbwerte nur lauter 0er zurück und damit ein komplett schwarzes Bild.

Edit: merkwürdig ist auch, dass wenn ich den Code kompiliere und per Exe ausführe, er am Ende kein Bild erstellt, mit Debugger aber schon.
Zuletzt geändert von Hoto am 04.07.2018 05:46, insgesamt 1-mal geändert.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von NicTheQuick »

Letzteres liegt daran, dass du da solche Zeilen drin hast

Code: Alles auswählen

Debug get_frame_bytes(*dxgi_manager,@buf_size,@*buf) ; sollte größer 0 sein
Ohne Debugger bzw. als EXE werden die einfach gar nicht mehr ausgeführt. Mach das Debug davor weg und schon klappt es auch mit der EXE.
Beim Rest kann ich dir nicht gut weiterhelfen mangels Windows. ;-)

Edit:
Ach Moment. Ich sehe den Fehler schon.
get_frame_bytes() erwartet einen vorhandenen Puffer. Es erstellt dir keinen.

Du hast ja einfach nur geschrieben

Code: Alles auswählen

*buf = #Null
Du solltest *buf auch mit der richtigen Größe (width * height * 4) initialiseren. Entweder mit AllocateMemory(width * height * 4) oder einfach ein Dim buf.l(width - 1, height - 1) und dann als @buf() übergeben.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von NicTheQuick »

Hast du diese Lib auch irgendwo für 64-Bit? Ein 32-Bittiges Windows hat doch heute kaum noch jemand.
Bild
Benutzeravatar
Hoto
Beiträge: 294
Registriert: 01.09.2004 22:51

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von Hoto »

Tja, die Idee war gut, aber weder AllocMemory oder Dim ändern was am Endergebnis, überall steht 0 drin.

Auf das "Debug" am Anfang bin ich eben selbst noch gekommen... dummer Fehler. :lol:

Kann es denn sein das die 32Bit DLL nicht unter Win 64Bit funktioniert? 64Bit hab ich nämlich noch nicht ausprobiert, werd ich gleich mal machen.

Edit: keine Änderung mit 64Bit und das gespeicherte Bild (nach wie vor komplett schwarz). Langsam glaube ich es liegt an der DLL?
Zuletzt geändert von Hoto am 21.06.2018 17:25, insgesamt 1-mal geändert.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von NicTheQuick »

Oder hast du es mal versucht mit ImportC statt Import? Im Github-Code steht ja überall "__declspec", d.h. die Aufrufkonvetion ist cdecl und nicht stdcall. Für cdecl sollte man ImportC nutzen.

Der Code müsste dann glaube ich so aussehen:

Code: Alles auswählen

ImportC "DXGCap.lib"
	_create_dxgi_manager()
	_delete_dxgi_manager(*dxgi_manager)
	_get_capture_source(*dxgi_manager)
	_get_frame_bytes(*dxgi_manager, o_size, *o_bytes)
	_get_output_dimensions(*dxgi_manager, Width, Height)
	_refresh_output(*dxgi_manager)
	_set_capture_source(*dxgi_manager,cs)
	_set_timeout(*dxgi_manager,timeout)
EndImport
Bild
Benutzeravatar
Hoto
Beiträge: 294
Registriert: 01.09.2004 22:51

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von Hoto »

Sicher? Die Funktionen der DLL haben ja eigentlich funktioniert, bis auf das Bild auslesen.

Wenn ich das so ändere wie du angegeben hast, bekomme ich lauter "Unresolved external symbol" POLINK Fehler angezeigt.

64 Bit hatte ich oben schon das dazu editiert, keine Änderung. Eine Idee hab ich noch.

Edit: Hm, interessant. Ich hab jetzt von der Debug Routine im C++ Source übernommen, dass er die get_frame_bytes Funktion 60000x aufruft bevor er die Daten dann wirklich nutzt. Es scheint die Api braucht wohl einen Moment bis sie Daten liefert. Jetzt hab ich zwar ein Bild, aber irgendwas stimmt mit den Farben noch nicht.

Sehe gerade, dass bei den Farbwerten teils auch Minuszahlen dabei sind, woher kann das denn kommen?

Edit2: Ok, mit PeekA statt PeekB geht es, nun passen die Farben und es funktioniert. Werd den Code mal aufräumen und dann noch mal hier posten.

Allerdings muss man die Daten wohl jedes mal prüfen, weil ab und zu kommen immer noch lauter 0er bei raus, aber ich hab da langsam so ein Verdacht... muss ich testen.
Benutzeravatar
_JON_
Beiträge: 389
Registriert: 30.03.2010 15:24

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von _JON_ »

Code: Alles auswählen

Debug get_frame_bytes(*dxgi_manager,@buf_size,@*buf) ; sollte größer 0 sein
Ohm, nee 0 ist CR_OK und somit das gewünschte Ergebnis.

Code: Alles auswählen

size_t buf_size;
size_t buf_size;
	uint8_t* buf = NULL;
	for (size_t i = 0; i < 60000; i++) {
		switch (get_frame_bytes(dxgi_manager, &buf_size, &buf)) {
			case CR_OK:
				break;
			case CR_ACCESS_DENIED:
				printf("Access denied\n");
				break;
			case CR_ACCESS_LOST:
				printf("Access lost\n");
				break;
			case CR_TIMEOUT:
				printf("Timeout\n");
				break;
			case CR_FAIL:
				printf("General failure\n");
				break;
		}
	}


get_frame_bytes(dxgi_manager, &buf_size, &buf);
Mit dem Bild stimmt aber trotzdem was nicht.
PureBasic 5.46 LTS (Windows x86/x64) | windows 10 x64 Oktober failure
Benutzeravatar
Hoto
Beiträge: 294
Registriert: 01.09.2004 22:51

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von Hoto »

Ja, mein Fehler, kommt davon wenn man noch schnell Kommentare hinzufügt bevor man den Code hier postet. ;)

Genau das im Quote ist nun auch im Code halbwegs, aber nicht perfekt, drin. So sollte man es definitiv nicht 1:1 verwenden, rein zum testen in der IDE gedacht:

Code: Alles auswählen

EnableExplicit
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  #ImportLib$ = "DXGCapx64.lib"
CompilerElse
  #ImportLib$ = "DXGCapx86.lib" 
CompilerEndIf

Define cs = 0, Width.i, Height.i, buf_size.i, *buf, o_size.i, *o_bytes, *dxgi_manager
Define x = 0, y = 0, z = 0

#CR_OK = 0
#CR_ACCESS_DENIED = 1
#CR_ACCESS_LOST = 2
#CR_TIMEOUT = 3
#CR_FAIL = 4

Import #ImportLib$
  create_dxgi_manager()
  delete_dxgi_manager(*dxgi_manager)
  get_capture_source(*dxgi_manager)
  get_frame_bytes(*dxgi_manager, o_size, *o_bytes)
  get_output_dimensions(*dxgi_manager, Width, Height)
  refresh_output(*dxgi_manager)
  set_capture_source(*dxgi_manager,cs)
  set_timeout(*dxgi_manager,timeout)
EndImport

*dxgi_manager = create_dxgi_manager()

get_output_dimensions(*dxgi_manager,@Width,@Height)

Debug "w:"+Str(Width) + " h:" + Str(Height)
Debug get_capture_source(*dxgi_manager)

*buf = AllocateMemory(Width*Height*4)

Repeat
  Select get_frame_bytes(*dxgi_manager, @buf_size, @*buf)
    Case #CR_OK
      ; all ok
    Case #CR_ACCESS_DENIED
      Debug "Access Denied"
      Break
    Case #CR_ACCESS_LOST
      Debug "Access lost"
      Break
    Case #CR_TIMEOUT
      Debug "Timeout"
      Break
    Case #CR_FAIL
      Debug "General failure"
      Break
  EndSelect
Until PeekS(*buf)

CreateImage(0,Width,Height,32,RGBA(255,255,255,255))
StartDrawing(ImageOutput(0))
  DrawingMode(#PB_2DDrawing_Default)
  For y = 0 To Height-10
    For x = 0 To Width-1 
      Plot(x,y,RGBA(PeekA(*buf+z+2),PeekA(*buf+z+1),PeekA(*buf+z),PeekA(*buf+z+3))) ; *buf content is in BGRA 0-255 Subpixel order 
      z + 4
    Next
    Debug PeekA(*buf+z)
  Next
StopDrawing()

SaveImage(0,"DXGCap_Test_Screenshot.bmp",#PB_ImagePlugin_BMP)

delete_dxgi_manager(*dxgi_manager)
http://www.stepload.de/uploads/f1mOg_MC ... 6dYYilldF/

Die Zip Datei mit nun Dateien für 32 und 64 Bit und entsprechend die DLLs benannt, sind also neu kompiliert, wie im Code zu sehen wird automatisch die richtige Version gewählt.
Zuletzt geändert von Hoto am 04.07.2018 05:51, insgesamt 1-mal geändert.
Benutzeravatar
Hoto
Beiträge: 294
Registriert: 01.09.2004 22:51

Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht

Beitrag von Hoto »

Nun tut sich doch noch ein kleines Problem auf:

Problem Beschreibung:

Da ich die Funktion für eine sehr Zeitkritische Sache brauche und vor der eigentlichen Verarbeitung erst mal die Daten reduzieren muss, was bei einer 4K Auflösung (also 3840x2160 * 4) stolze 31 Megabyte sind, ist nun die Frage auf welche Weise ich diese Daten am schnellsten klein kriege, also das Bild verkleinert kriege.

Da ich nur einige wenige zusammengerechnete Farben brauche, tendiere ich aktuell zu einer Auflösung von ~240x180 (könnte je nach dem ein wenig mehr oder weniger sein) zur Weiterverarbeitung der Daten, die aber nicht einfach so aus dem Bild entnommen sind sondern per #PB_Image_Smooth (oder einer ähnlich Funktion) reduziert wurden.

Die Frage ist nun welche Möglichkeiten es gäbe die Daten reduziert zu kriegen und das so schnell wie möglich, ohne Kompromisse.

Die Bilddaten bestehen einzig und allein aus den Farbinformationen in einem Speicherbereich, fangen oben links an und gehen dann Zeile für Zeile von links nach recht in der Anordnung: Blau, Grün, Rot, Alpha (also BGRA).

Bisherige Lösungsansätze

1. dem Speicherbereich einen BMP Header voran stellen, so dass das Bild direkt mit CatchImage() geladen und mit ResizeImage() verkleinert werden kann.

2. die Bilddaten direkt in den Speicherbereich eines PB Images speichern. Ob das aber besser oder gar schnell ist ohne die Daten erst umordnen zu müssen damit die Subpixel Reihenfolge passt?

3. die Daten direkt auszulesen und per Formeln verkleinern, ist da ein ResizeImage() aber nicht eindeutig schneller?

4. mir noch mal die Desktop Duplication API anzuschauen, ob die Daten nicht zuerst im Grafikkartenspeicher landen und es möglich wäre sie dort zu verkleinern. Eine Grafikkarte kann das nun mal am schnellsten.

Aktuell letzte Gedanken dazu

Mit 1. hatte ich bereits angefangen, bevor mir die restlichen Ideen kamen als ich schon im Halbschlaf war, daher muss ich mich in die Punkte noch einlesen. Vor allem 4. klingt für mich nach der eigentlich besten Lösung, allerdings müsste ich mich dann mit C++ erst mal rumschlagen, das ich gerade so halbwegs lesen kann, aber wenn ich schon mal VS C++ 2013 installiert habe... die MIT Lizenz der DXGCap.dll ließe das jedenfalls zu.

Wie würdet ihr es machen? Hab ich noch eine Methode übersehen?
Antworten