Videosignale aus der Grafikkarte zugreifen.
-
Hallo,
wer kennt, wie man die Videosignale aus der Grafikkarte ( aus dem Bufferspeicher)
zugreifen und weiter verwenden kann, das alles muss in C++ geschrieben. Oder hat jemand schon fertige Quellcode?
Also etwas konkreter:
Ich habe zwei WLAN-Kameras, die mit zwei Grabberkarten angeschlossen sind. Die Videosignale waren zuerst auf dem Monitor eines PCs (zwei Bilder), jetzt möchte ich die Signale an zwei Anzeigen des Helms übertragen.Danke.
-
Was für ein Helm?
Wie kommst du an die Daten der Kamera? Gibt es ein SDK vom Hersteller oder irgendwas in der Richtung?
Du musst irgendwie an die Daten jedes einzelnen Pixels kommen.
Dann lädst du dir die Bilddaten auf die Grafikkarte.
Im konkreten Fall könntest du Direct3D verwenden. Da erstellst du dir eine "Dynamische Textur" in die du die Bilddaten deiner Kamera lädst, und das jeden Frame.Oder du hackst den Treiber deiner Grafikkarte
Wichtiger wäre erstmal: Was kannst du? Was steht dir zur Verfügung?
-
Hallo, Blaze!
Also
Helm: Kaiser ELECTRO-OPTICS; INC.(HMD-Schnitstelle, aber habe noch einen Adapter mit der VGA-Schnittstelle).
SDK:DirectX
Software:( Quellcode in C++), die Videodaten der zwei WLAN Kameras von der Grabberkarte in RAM des PCs ablegen.
Meine Zeil: Die zwei Videodaten, die schon im RAM des PCs liegen, auf die zwei VGA Schnittstellen der Grafikkarte ausgeben.
Zur Verfügung steht alles, was ich brauchen werde...Wie ich Direct3D verwenden kann?
Leider habe ich mit DirectX noch nicht's gemacht.
Wo kann ich über Direct3D lesen?
Kann ich auch DirectShow Verwenden? ich brauche keine 3D-darstellung..
Wie initialisiert man in C die VGA Schnittstellen?Und suche noch passende (natürlich, ungefähr passende) Quellcode in C++
Danke.
-
Also mal eine kleine Einführung in dieses Gebiet.
DirectShow stellt Filter bereit, mit denen du aus z.B. einer MP3-Datei die "Wave-Daten" für die SoundBuffer holst oder die einzelnen Pixel aus einem MPEG2 codiertem Video. Wenn deine Grabber die Videodaten unkomprimiert in den RAM legen, kannst du auf DirectShow verzichten.
Dann gibt es da noch DirectDraw und Direct3D. DirectDraw ist allerdings für mich Neuland, ich kenne die Möglichkeiten da nicht. Aber was DirectDraw kann, kann Direct3D schon lange. Mit Direct3D sind nehmlich ganz normale 2D-Sachen genauso möglich.
Wenn du noch mehr zu DirecX wissen willst, schau dich mal bei Wikipedia um.Dein "Projekt" würde ich mal in 2 Teile teilen. Das erste befasst sich damit, die Video-Daten des Helms unkomprimiert in den RAM zu bekommen und der zweite Teil bringt sie dir auf die Displays.
Beim ersten Teil kann ich dir wenig helfen, denn ich habe nicht das SDK vom Helmhersteller (Dieser "Quellcode in C++). Da könntest du mal probieren einfach mal die Bilder aus dem Ram in simple Bitmaps zu speichern. Das Bitmapformat ist ziemlich einfach. Wenn du das schaffst, weist zu zumindest schonmal, wie man mit den Rohdaten umgeht.
Jetzt müssen die Rohdaten auf den Helm. Dazu benötigst du 2 Direct3DDevices. Eins für links, eins für rechts. Ich persönlich würde dir zu Direct3D9 raten. Das ist "einfacher" als 10 oder 11. Außerdem Kannst du die 9er Version auch auf XP-Rechnern benutzen, die Rechenpower von D3D10 Grakas brauchst du an dieser Stelle eh nicht.
Zum Thema Direct3D verwenden: Am besten liest du dir mal die Tutorials aus dem DirectX SDK durch. Hier ist die Online-Version:
http://msdn.microsoft.com/de-de/library/ee416755(v=VS.85).aspx
Wichtig ist erstmal "•Tutorial 1: Creating a Device".
Hier kommt der Trick für den Helm: Vorausgesetzt deinen Helm schließt du an 2 Grafikkartenausgängen an, müsste IDirect3D9::GetAdapterCount mit IDirect3D9::GetAdapterIdentifier dir deine 2 Helmdisplays auflisten.
Du benutzt die beiden AdaperIDs der Displays und erstellst dir hierfür 2 Fullscreen Devices in der Auflösung, die dir die Displays hergeben. -> IDirect3D9::EnumAdapterModesNochwas: IDirect3D9 ist dafür da, um alle Grafikkarten(/Displays), deren unterstützen Formate, Auflösungen etc. abzufragen und die IDirect3D9Device-Interfaces zu erstellen.
Wenn du dann irgendwann 2 Funktionsfähige Devices hast, erstellst du auf beiden eine Textur, die "dynamisch" ist. Diese musst du jeden Frame sperren, die rohen Bilddaten der Kameras reinladen und wieder entsperren. Achte unbedingt darauf, dass sie das gleiche Format haben. Deine Kameras könnten BGR-Daten liefern und du hast eine XRGB-Textur erstellt.
Wenn du die Texturen mit den Bilddaten hast, renderst du ein so genanntes Fullscreenquad (ein großes Viereck über den ganzen Display) mit der Textur der Bilddaten. Und das wars!
Das mit den Bilddaten in einer dynamischen Textur kann sich so vorstellen: In einem PC-Game läuft ein Fernseher der ein Video zeigt, dass auf deiner Festplatte liegt. Du lädst das Video in den RAM und dann jeden Frame das passende Bild in die Textur.Für deine weitere Vorgehensweise würde ich dir erstmal Direct3D9 Tutorials raten. Beschäftige dich erstmal mit den Grundbegriffe, aber lass den Teil mit den Effekten einfach weg - das brauchst du nicht. Dann versuch mal irgendein buntes Fullscreen-Quad zu rendern.
Interessant wären auch mal deine Programmierkenntnisse. Wie sieht es mit deinen C++ Kenntnissen aus? Polymorphie und Templates brauchst du hier nichtAber du solltest schonmal was mit Klassen anfangen können.
Wenn du Fragen hast, dan frag ruhig!
-
Hi Blaze,
du hast mir sehr geholfen, ich habe schon mein erstes FullScreen erstellt,Danke.
Aber , leider kann nur manuel (mit dem Button) Vollbildmodus erzeugt werden
Klein Stückchen von Quellcode:
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
Aus der Thorie: Windowed=TRUE if the application runs windowed;
FALSE if the application runs full-screen.
Wenn ich d3dpp.Windowed=FALSE setze, dann kommt weder keine Fehler noch kein Fenster raus.
was ich falsch mache???Über die Funktionen: IDirect3D9::EnumAdapterModes;IDirect3D9::GetAdapterIdentifier; habe ich wenig gefunden.
Kannstu mir irgendein schönes Buch epfehlen über DirectX(nur auf Deutsch!)?
Oder gibt es Muster im Internet, wie man die schöne Funktionen benutzt?
Danke im Voraus.
-
Du darfst Funktionen wie IDirect3D9::EnumAdapterModes nicht selbst deklarieren, geschweigedenn definieren. Die sind fester Bestandteil von Direct3D9.
du brauchst den Header D3D9.h und die Lib D3D9.lib.Hier ist mal ein kleines Sample, wie du alle Adapter auflistest:
//Header inkludieren #include<sstream> //Stringstreams #include<windows.h> //Standard-Windows Zeug #include<D3D9.h> //Direct3D9 //Libs linken #pragma comment(lib, "D3D9.lib") int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, char*, int) { //Direct3D9-Interface erstellen IDirect3D9 * pD3D= Direct3DCreate9(D3D_SDK_VERSION); if(!pD3D) { MessageBox(NULL, "Direct3D konnte nicht initialisiert werden!", "Fehler!", MB_OK|MB_ICONERROR); return(0); } //Anzahl der verfügbaren Adapter abfragen UINT uNumAdapters= pD3D->GetAdapterCount(); for(UINT uAdapter= 0; uAdapter < uNumAdapters; uAdapter++) { //Jeden Adapter durchgehen //Informationen des Adapters abfragen D3DADAPTER_IDENTIFIER9 AdapterInfo; pD3D->GetAdapterIdentifier(uAdapter, D3DENUM_WHQL_LEVEL, &AdapterInfo); //wichtige Informationen std::stringstream Message; Message<<"ID: "<<uAdapter<<"\n" <<"Adaptername: "<<AdapterInfo.Description<<"\n" <<"Treiber: "<<AdapterInfo.Driver; MessageBox(NULL, Message.str().c_str(), "Adapter gefunden!", MB_OK|MB_ICONINFORMATION); } //Aufräumen nicht vergessen! pD3D->Release(); return(0); }
Ein Buch direkt zum Thema Direct3D9 in Deutsch wäre eigentlich nur eine Übersetzung der Docu. Die Docu ist wirklich gut! Ein bisschen Englisch vorausgesetzt, kann man da eine ganze Menge lernen. Und das beste ist: Sie ist kostenlos! Ich rate dir zur Docu.
-
Danke dir sehr!
Ich habe vorherige Fragen geändert und gesehen, dass die schon beantworten sind, sorry
mich interrisiert Vollbildmodus wieder...(s.o)
-
Über die Funktionen: IDirect3D9::EnumAdapterModes;IDirect3D9::GetAdapterIdentifier; habe ich wenig gefunden.
Dann öffne mal die "DirectX Graphics Documentation". Die ist Teil des DirectX SDKs und du findest sie unter Start->Programm->Microsoft DirectX SDK <Version>->Windows DirectX Graphics Documentation
Dann: Direct3D 9->Reference->Direct3D Reference->Interfaces->IDirect3D9
Dort findest du eine Liste aller Methoden des IDirect3D-Interfaces, unter anderem auch IDirect3D9::EnumAdapterModes und IDirect3D9::GetAdapterIdentifierUnd zu deinem Fullscreenproblem: Versuche mal die D3DPRESENT_PARAMETERS vollständig auszufüllen.
Noch ein paar Tips dazu:
- Die BackBufferWidth und BackBufferHeight ist die Auflösung. Je höher desto besser. Was dein Adapter (Monitor/Graka) schafft kannst du mit IDirect3D9::EnumAdapterModes abzählen.
- Das BackBufferFormat gibt an, ob du 16-Bit, 24-Bit oder 32-Bit Farbtiefe nimmst. Was verfügbar ist, erfährst du mit IDirect3DDevice9::GetDisplayMode
- Den BackBufferCount setzt du einfach auf 1.
- Multisampling brauchst du nicht, da du nicht selbst Geometrie renderst. Also MultiSampleType auf D3DMULTISAMPLE_NONE und MultiSampleQuality auf 0
- Als SwapEffect nimm D3DSWAPEFFECT_DISCARD
- Für hDeviceWindow musst du ein Fenster erstellen (in deinem Fall 2) und hier das Handle übergeben. Für jedes Device ein Fenster.
- Windowed ist klar: FALSE
- EnableAutoDepthStencil brauchst du nicht. Du hast ja keine Geometrie. Also FALSE
- AutoDepthStencilFormat ist egal. Du lässt ja keinen erstellen
- Flags: von denen brauchst du keine, also 0
- FullScreen_RefreshRateInHz: Keinen großen Wind machen, einfach den Standardwert nehmen: D3DPRESENT_RATE_DEFAULT
- PresentationInterval gibt indirekt an, ob du VSync willst. Also warten bis das Bild vollständig aufgebaut ist. Ich weiß nicht, wie deine Kameras Bilder liefern, aber vorsichtshalber würde ich mich nach den Kameras richten und gleich ausgeben, sobald ein Bild kommt -> D3DPRESENT_INTERVAL_IMMEDIATEJetzt zu IDirect3D9::CreateDevice
- Die Adapter sollten klar sein. Einmal links und einmal rechts.
- Der Devicetyp sollte auf jeden Fall D3DDEVTYPE_HAL sein, alles andere wäre zu langsam, denn so nutzt du die Grafikkarte.
- Das hFocusWindow sollte dem hDeviceWindow entsprechen.
- Als BehaviorFlags würde ich folgende angeben: D3DCREATE_MULTITHREADED und D3DCREATE_HARDWARE_VERTEXPROCESSING. Damit soll die Grafikkarte rechnen und du lässt Direct3D in separaten Threads laufen. Gut für Multicore-Systeme!Und behalte unbedigt den Rückgabewert im Auge! Wenn etwas schief geht, dann gib ihn dir aus und suche per "DirectX Error Lookup" nach dem Fehler. DirectX Error Lookup ist ein Tool, das du auch unter Start->Programme->MSDXSDK->Tools findest. Alternativ kannst du auch die Fehlerüberprüfung direkt in deinem Programm machen mit DXGetErrorString und DXGetErrorDescription. Für diese Funktionen musst du allerdings DXErr.h inkludieren und DXErr.lib linken.
Versuch dich erstmal an einem ordentlichen Fullscreen auf deinem Monitor. Um zu sehen ob es geklappt hat, clear einfach den BackBuffer mit einer Farbe wie z.B. Blau. Wenn dein Montor blau ist, hast du es geschafft. Dann versuch das ganze mal nicht mit deinem Monitor, sondern mit deinen Helmdisplays. Aber denk dran. Für jeden Display ein eigenes Fenster, ein eigenes Device, ein eigener BackBuffer, ... eben alles! Du kannst nehmlich nicht eine Textur, die auf einem Device erstellt hast mit einem anderen Device benutzen. Zumindest nicht so einfach.
-
Hallo, das bin ich wieder
Hier ist mein Teil des Quelltextes. Immer noch habe ich Schwirigkeiten.
Keine Fehler und auch kein Fullscreen. Das Fenster zwar sehe ich, aber in ca. halbe Secunde schließt es sich zu.
Was fehlt hier noch? Und wie kann ich zwei Vollbilder erzeugen??? Es klappt nicht, leider. Ich habe fast ein Jahr nich programmiert, deswegen kommen die Schwirigkeiten vor#include <d3d9.h>
#include<sstream> //Stringstreams
#include<windows.h> //Standard-Windows Zeug
//#include <strsafe.h>
//#include<DXErr.h>
#pragma comment(lib, "D3D9.lib")
//#pragma comment(lib, "DXErr.lib")PDIRECT3D9 g_pD3D = NULL;
PDIRECT3DDEVICE9 g_pD3DDevice = NULL;
HWND g_hMainWindow = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch(uiMsg)
{
default: return DefWindowProc(hWnd,uiMsg,wParam,lParam);
}
return 0;
}int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow ){
//Create a Window
WNDCLASS WndClass;
ZeroMemory(&WndClass,sizeof(WNDCLASS));
WndClass.hbrBackground = (HBRUSH)BLACK_BRUSH;
WndClass.hInstance = hInstance;
WndClass.lpfnWndProc = (WNDPROC)WndProc;
WndClass.lpszClassName = L"Kamera1";
WndClass.style = CS_VREDRAW|CS_HREDRAW;
RegisterClass(&WndClass);g_hMainWindow = CreateWindowW( L"Kamera_1", L"Display_Right",
WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,640,480, NULL,NULL,hInstance,NULL);if(!g_hMainWindow) //Error -> Exit
return FALSE;
//Create the Direct3D-Interface
g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if(!g_pD3D) //Error -> Exit
return FALSE;
D3DPRESENT_PARAMETERS Window;
ZeroMemory(&Window , sizeof(D3DPRESENT_PARAMETERS) );
Window.BackBufferWidth=480;
Window.BackBufferHeight=600;
Window.Windowed=FALSE;
Window.BackBufferFormat=D3DFMT_X8R8G8B8;
Window.BackBufferCount=1;
Window.MultiSampleType=D3DMULTISAMPLE_NONE;
Window.MultiSampleQuality=0;
Window.SwapEffect=D3DSWAPEFFECT_DISCARD ;
Window.hDeviceWindow=g_hMainWindow;;
Window.EnableAutoDepthStencil=FALSE;
Window.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
Window.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
Window.Flags=0;
if(FAILED(g_pD3D->CreateDevice( 0, D3DDEVTYPE_HAL, g_hMainWindow,
D3DCREATE_MIXED_VERTEXPROCESSING,&Window, &g_pD3DDevice))){
return FALSE;
}return 1;
}Danke im Voraus!
-
Du musst wirklich Anfänger sein.
Überarbeite mal deinen Beitrag und setzt deinen Code in C++-Brackets. Also [_cpp_] Dein Code [/cpp] Ohne die Unterschriche!Der Fehler liegt darin, dass du keine MessageLoop hast. Außerdem solltest du auf WM_CREATE reagieren und 0 zurückgeben, und dazu noch bei WM_DESTROY PostQuitMessage aufrufen.
Schau dir erstmal die Grundlagen der Windows-Programmierung an. Speziell, wie man ein Fenster erstellt UND es am Laufen hält. Dazu ist ein Einblick in die "Windows Messages" sinnvoll.Hier ist mal ein Tutorial dazu:
http://pronix.linuxdelta.de/C/win32/win32_1.shtmlDazu solltest du D3DCREATE_MIXED_VERTEXPROCESSING nicht verwenden, das führt ab und zu Fehlern, bei denen man kaum vermutet, dass es davon kommt. Lass das lieber die Hardware erledigen.
Hast du mal mein Programm ausprobiert und getestet, ob deine Helmdisplays überhaupt verfügbar sind?
-
Hallo Blaze, Danke noch mal. Deine Hilfe immer wieder recht schnell!
Es ist endlich geklappt!!!(Vollbild)
Das Problemm ist nur mit der Übertragung irgendeinen Videodaten (Messages), die z.B auf dem Desktop liegen, auf das Fenster...(zum Testen erstma), leider habe ich nur über TextMessages gefunden, oder das keine Rolle in diesem Fall spielt?
Was kannst du mir weiter empfehlen?
P.S. Ja, ich habe dein Programm ausprobiert, alles läuft, Danke!
-
Jetzt könntest du anfangen, nicht den Standard-Adapter (0) zu benutzen, sondern mal einen Display deines Helms.
Aber Achtung: Hier muss alles passen! Das Format und die Auflösung solltest du nicht dem Zufall überlassen. Sieh dir dazu mal die folgenden Methoden an:
IDirect3D9::GetAdapterModeCount, IDirect3D9::EnumAdapterModes
Damit kannst du alle Auflösungen für das passende Format auflisten.
-> Probieren! Einfach mal alles verfügbare ausgeben lassen.
Als Adapter nimmst du auch hier nicht 0, sondern einen Helm-Display.Das Message-System sollte Windows-Programmierern bekannt sein. Ich versuch es dir mal kurz zu erklären.
Alles in Windows wird alles mit Messages gesteuert. Wenn du zum Beispiel auf einen Link hier im Forum klickst, was passiert da?
Erstmal wertet Windows die Eingaben der Maus aus und schickt Nachrichten an das Fenster deines Browsers. Das wären ganz viele "Maus bewegt" und dann "Linke Maustaste gedrückt". Diese Nachrichten sendet Windows an das Browserfenster und dabei wird die WindowProc des Browserfensters aufgerufen. In den Parametern steht alles nötige.
Dein Browser bemerkt also, dass du irgendwo hin geklickt hast. Darauf hin berechnet er intern, ob du einen Link getroffen hast, oder nicht.
Oder wenn ich hier die Antwort auf deinen Beitrag schreibe, drückt ich Tasten auf der Tastatur. Jeder Tastendruckt wird per Nachricht an das Textfeld in meinem Browser geschickt. Daraufhin fügt die WindowProc des Textfeldes (Ja, sogar ein Textfeld ist ein Fenster!) mein eingegebenes Teichen an den Inhalt des Textes an und schickt wiederum Nachrichten, wie: "Text setzen", "Carret an das Ende des Textes setzen", "Textfeld neu zeichnen".
Auf all diese Nachrichten muss/sollte/kann ein Fenster reagieren. Je nachdem, was das Fenster tun soll. Eine Uhr in der Sidebar z.B. wird kaum auf Tastatureingaben reagieren müssen, während Word genau das tun sollte.
-
Ich bedanke mich Blaze, und versuche weiter das Programm schreiben.
Chao und vielleicht bis bald