DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
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. Vielleicht hab ich aber auch nur seit Tagen ein Brett vor dem Kopf.
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
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. Vielleicht hab ich aber auch nur seit Tagen ein Brett vor dem Kopf.
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.
Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
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.
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.
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)
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.
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- 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
Letzteres liegt daran, dass du da solche Zeilen drin hast
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
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.
Code: Alles auswählen
Debug get_frame_bytes(*dxgi_manager,@buf_size,@*buf) ; sollte größer 0 sein
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
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- 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
Hast du diese Lib auch irgendwo für 64-Bit? Ein 32-Bittiges Windows hat doch heute kaum noch jemand.
Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
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.
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?
Auf das "Debug" am Anfang bin ich eben selbst noch gekommen... dummer Fehler.
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.
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- 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
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:
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
Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
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.
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.
Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
Code: Alles auswählen
Debug get_frame_bytes(*dxgi_manager,@buf_size,@*buf) ; sollte größer 0 sein
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);
PureBasic 5.46 LTS (Windows x86/x64) | windows 10 x64 Oktober failure
Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
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:
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.
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)
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.
Re: DXGI Desktop Duplication API (DX11 Win8+) Hilfe gesucht
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?
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?