DirectShow



  • Da directShow ja nun in der PSDK lebt, hau ich das Thema mal hier rein.

    Ich muss erstmal eins sagen: ich versuche grad DirectShow aus einem ziemlich schlampig geschriebenem Buch zu lernen, welches dazu auch noch MFC (ihh!) benutzt und bei welchem die beigelegten Beispiele kein stück funktionieren (und auch nicht mit dem Code im Buch übereinstimmen). Versuchen tu ichs trotzdem, man soll ja froh sein, dass man überhaupt etwas hat...

    Natürlich würde ich nie im Leben das abartige Unterwesen MFC anrühren. Deshalb hatte ich mir eine Seite ergoogelt, welche die funktionsweise von DirectShow bestens erklärt, leider jedoch nicht in dem Maße, in welchem ich es benötigt hätte. Denn eine integration von DirectShow in eine (von einer Sterblichen Hand) verwendbare Klasse wird nicht erläutert.

    Ich habe versucht, eine art sound+musik+video engine zu bauen, welche man leicht in einem Computerspiel verwenden könnte. Da kein einziger Ansatz geklappt hatte, habe ich ein etwas degradiertes Programm geschrieben, welches eine einzelne Datei wiedergeben soll. Trotzdem bekomm ich auch hier nicht sinnvolleres als sinnlose Fehler. so langsam zweifele ich daran, ob DirectShow eine richtige API ist, oder nur etwas, um leute in den Wahnsinn zu treiben.

    Debuggen bringt nichts, es wird stupide eine einzelne Zeile angezeigt, welche, in all ihrer zweifelhaften Schönheit, einen Laufzeitfehler mit einer Zugriffsverletzung erzeugt, und mir gnadenlos in einem Fenster, welches passend zu dem von ihm verursachten Wahnsinn, grau ist, entgegenwirft.

    while (mMediaEvent->GetEvent(&EventCode, &Param1, &Param2, 0) != E_ABORT)
    .......
    

    der gesamte code befindet sich in nur 2 dateien:

    // MMClass.h
    #include <windows.h>
    #include <DShow.h>
    
    #pragma comment(lib, "Strmiids.lib")
    #pragma comment(lib, "Quartz.lib")
    #pragma warning (disable : 4996)
    
    #define WM_GRAPHEVENT	WM_USER		// eigene nachricht
    
    #define MRLS(x) if (x != NULL) \
                        { \
                            x->Release(); \
                            x = NULL; \
                        }
    
    class MMMUSIC
    {
    private:
    	MSG msg;
    	HWND hWnd, hWndParent;
    	WNDCLASSEX wcex;
    	IGraphBuilder*	mGraphBuilder;
    	IMediaControl*	mMediaControl;
    	IMediaEventEx*	mMediaEvent;
    	IMediaPosition*	mMediaPosition;
    
    	// WndProcs
    	LRESULT CALLBACK MusicProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    	static LRESULT CALLBACK Static_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    public:
    	MMMUSIC();
    	~MMMUSIC();
    	// MediaWindow - kein Peil, wie mans ohne macht :(
    	bool MediaWindow(HWND Parent);
    	// DirectShow Initialisieren
    	int InitDirectShow();
    	// Fensterhandle für Nachrichten festlegen
    	void SetNotifications();
    	// MessageVerteiler
    	int MusicMsgDp();
    	// Media-message Verarbeitung
    	void OnGraphEvent();
    	// Datei laden
    	int LoadFile(TCHAR* filename);
    
    	void play();
    	void stop();
    	void release();
    };
    
    MMMUSIC::MMMUSIC()
    {
    
    	// COM initialisieren
    	CoInitialize(NULL);
    }
    MMMUSIC::~MMMUSIC()
    {
    	CoUninitialize();
    }
    
    int MMMUSIC::InitDirectShow()
    {
    	HRESULT hr;
    	hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
    	IID_IGraphBuilder,(void**)&mGraphBuilder);
    
    	if (FAILED(hr))
    		return -1;
    	mGraphBuilder->QueryInterface(IID_IMediaControl, (void**)&mMediaControl);
    	mGraphBuilder->QueryInterface(IID_IMediaEvent, (void**)&mMediaEvent);
    	mGraphBuilder->QueryInterface(IID_IMediaPosition, (void**)&mMediaPosition);
    	return 0;
    }
    
    void MMMUSIC::SetNotifications()
    {
    	mMediaEvent->SetNotifyWindow((OAHWND)hWnd, WM_GRAPHEVENT, 0);
    	mMediaEvent->SetNotifyFlags(0);
    }
    
    LRESULT CALLBACK MMMUSIC::Static_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	if(uMsg == WM_CREATE)
    	{
    		SetWindowLong(hwnd, GWL_USERDATA, (LONG) lParam);
    	}
    	static MMMUSIC * mmm = NULL;
    	mmm = (MMMUSIC*) GetWindowLong(hwnd, GWL_USERDATA);
    	if(!mmm)
    		return DefWindowProc(hwnd, uMsg, wParam, lParam);
    	else
    		return mmm->MusicProc(hwnd, uMsg, wParam, lParam);
    }
    
    LRESULT CALLBACK MMMUSIC::MusicProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
    	switch (uMsg)
    	{
    	case WM_GRAPHEVENT:
    		OnGraphEvent();	
    		break;
    	default:
    		break;
    	}
    	return DefWindowProc(hwnd, uMsg, lParam, wParam);
    }
    
    int MMMUSIC::MusicMsgDp()
    {
    	if(PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
    	{
    		if(msg.message == WM_QUIT) return -1;
    
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
    	return (int) 1;
    }
    
    bool MMMUSIC::MediaWindow(HWND Parent)
    {
    	hWndParent = Parent;
    
    	FillMemory  (&wcex,sizeof(wcex),0); wcex.cbSize = sizeof (wcex);
    
    		wcex.cbClsExtra		= 0;
    		wcex.cbWndExtra		= 0;
    		wcex.hbrBackground	= (HBRUSH) GetStockObject(BLACK_BRUSH);
    		wcex.hCursor		= NULL;
    		wcex.hIcon			= NULL;
    		wcex.hIconSm		= NULL;
    		wcex.hInstance		= (HINSTANCE) GetWindowLong(Parent,GWL_HINSTANCE);
    		wcex.lpfnWndProc	= Static_Proc;
    		wcex.lpszClassName	= TEXT("Music");
    		wcex.lpszMenuName	= NULL;
    		wcex.style			= CS_HREDRAW | CS_VREDRAW;
    
    		if(!RegisterClassEx(&wcex)) return false;
    
    	hWnd = CreateWindowEx(NULL, wcex.lpszClassName,
    		TEXT("Music"), WS_CHILD | WS_CLIPSIBLINGS, 
    		0, 0, 0, 0, Parent, NULL, 
    		wcex.hInstance,(LPVOID) this);
    
    	if(!hWnd)
    	{
    		MessageBox(NULL, TEXT("MMM Fenster konnte nicht erstellt werden!"), TEXT("Fehler"), MB_OK | MB_ICONHAND);
    		return false;
    	}
    
    	SetNotifications();
    	return true;
    }
    
    void MMMUSIC::OnGraphEvent()
    {
    	long EventCode, Param1, Param2;
    	while (mMediaEvent->GetEvent(&EventCode, &Param1, &Param2, 0) != E_ABORT)
    	{
    		switch (EventCode)
    		{
    		case EC_COMPLETE:
    			mMediaControl->Stop();
                mMediaPosition->put_CurrentPosition(0);
    		default:
    			break;
    		}	
    		mMediaEvent->FreeEventParams(EventCode, Param1, Param2);
    	}
    }
    
    int MMMUSIC::LoadFile(TCHAR* filename)
    {
    #ifndef UNICODE
    	int	length;		// length of filename
    	WCHAR*	wfilename;	// where we store WCHAR version of filename
    
    	length = strlen(filename)+1;
    	wfilename = new WCHAR[length];
    	MultiByteToWideChar(CP_ACP, 0, filename, -1, wfilename, length);
    	if (FAILED(mGraphBuilder->RenderFile(wfilename, NULL))
    		return -1;
    	else
    		return 0;
    #else
    	if (FAILED(mGraphBuilder->RenderFile(filename, NULL)))
    		return -1;
    	else
    		return 0;
    #endif
    }
    
    void MMMUSIC::play()
    {
    	if(mMediaControl) mMediaControl->Run();
    	else MessageBox(NULL, TEXT("Keine Datei Geladen"), TEXT("Fehler"), MB_OK | MB_ICONHAND);
    }
    
    void MMMUSIC::stop()
    {
    	if(mMediaControl) mMediaControl->Stop();
    	else MessageBox(NULL, TEXT("Keine Datei Geladen"), TEXT("Fehler"), MB_OK | MB_ICONHAND);
    }
    
    void MMMUSIC::release()
    {
    	MRLS(mMediaPosition);
    	MRLS(mMediaEvent);
    	MRLS(mMediaControl);
    	MRLS(mGraphBuilder);
    }
    

    und

    //main.cpp
    #include "MMClass.h"
    LRESULT WINAPI WndProc(HWND, UINT, WPARAM, LPARAM);
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pszCmdLine, int nShow)
    {
    	HWND hWnd;
    	MSG msg;
    	WNDCLASSEX wcex;
    	MMMUSIC *mmm = new MMMUSIC;
    
    	wcex.cbSize			= sizeof(WNDCLASSEX);
    	wcex.cbClsExtra		= 0;
    	wcex.cbWndExtra		= 0;
    	wcex.hbrBackground	= (HBRUSH) GetStockObject(BLACK_BRUSH);
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
    	wcex.hIcon			= NULL;
    	wcex.hIconSm		= NULL;
    	wcex.hInstance		= hInstance;
    	wcex.lpfnWndProc	= WndProc;
    	wcex.lpszClassName	= TEXT("MainWindow");
    	wcex.lpszMenuName	= NULL;
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;
    
    	if(!RegisterClassEx(&wcex)) return -1;
    
    	hWnd = CreateWindowEx(NULL, wcex.lpszClassName,
    		TEXT("ASE - Main Window"), WS_OVERLAPPEDWINDOW, 
    		0, 0,800, 600, NULL, NULL, 
    		wcex.hInstance,NULL);
    
    	if(!hWnd)
    	{
    		MessageBox(NULL, TEXT("Fenster konnte nicht erstellt werden!"), TEXT("Fehler"), MB_OK | MB_ICONHAND);
    		return -2;
    	}
    
    	ShowWindow(hWnd, nShow);
    	UpdateWindow(hWnd);
    
    		mmm->InitDirectShow();
    		mmm->MediaWindow(hWnd);
    		mmm->LoadFile(TEXT("amr.mp3"));
    		mmm->play();
    	while(true)
    	{
    		if(PeekMessage(&msg,hWnd, 0,0, PM_REMOVE))
    		{
    			if(msg.message == WM_QUIT) break;
    			mmm->MusicMsgDp();
    
    			TranslateMessage(&msg);
    			DispatchMessage(&msg);
    		}
    	}
    	mmm->stop();
    		mmm->release();
    
    	return (int)msg.wParam;
    }
    
    LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch(msg)
    	{
    	case WM_CREATE:
    		break;
    	case WM_DESTROY:
    
    		PostQuitMessage(0);
    		break;
    	default:
    		break;
    	}
    	return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    

    p.s: sorry für die ausdrucksweise, ich war jedoch noch nie so nah an ausm fenster springen...



  • keiner lust, zu antworten? 😞



  • Ich kann keinen Fehler erkennen ;/



  • Ich seh ja auch keinen, aber das gibt einen zugriffsverletzungsfehler beim debuggen. 😣 Hier sind doch sicherlich welche mit mehr Hirn als ich, ist das denn so unmöglich? 😞



  • Hier sind leider recht wenige die DirectShow verwenden, vermutlich wissen die Spieleprogrammierer hier da mehr drüber. (Oder ist es schon zu lange aus dem DX-SDK verschwunden?) 😉

    Die meisten scheinen noch MCI zu nutzen.



  • Azrael, il Meraz schrieb:

    Denn eine integration von DirectShow in eine (von einer Sterblichen Hand) verwendbare Klasse wird nicht erläutert.

    Du musst Dir die Struktur der Klasse "MMMUSIC" besser überlegen.
    Ev. würde es schon reichen, wenn Du in der WinMain folgendes auskommentierst :

    // mmm->MediaWindow(hWnd);
    
    // mmm->MusicMsgDp();
    


  • Nachtrag :

    "besser überlegen" klingt blöde. Sorry.

    Das Problem ist wie folgt :

    "MMMUSIC *mmm = new MMMUSIC;" in der WinMain erzeugt eine Instanz der Klasse "MMMUSIC".

    Der Aufruf von "mmm->InitDirectShow();" initialisiert diese Instanz.

    Der Aufruf von "mmm->MediaWindow(hWnd);" erzeugt eine zweite Instanz, die nicht initialisiert wird und deshalb die Zugriffsverletzung auslöst.



  • Werd das morgen mal durchn Compiler jagen und mal sehen was der Sacht und dann deinen Code mal genauer angucken ... find längerer Code ist im Forum immer schlecht zu lesen (zumindest wenn er nicht kommentiert ist) und ich weiß nicht genau wo er warum raushaut usw...



  • merker schrieb:

    Nachtrag :

    "besser überlegen" klingt blöde. Sorry.

    Das Problem ist wie folgt :

    "MMMUSIC *mmm = new MMMUSIC;" in der WinMain erzeugt eine Instanz der Klasse "MMMUSIC".

    Der Aufruf von "mmm->InitDirectShow();" initialisiert diese Instanz.

    Der Aufruf von "mmm->MediaWindow(hWnd);" erzeugt eine zweite Instanz, die nicht initialisiert wird und deshalb die Zugriffsverletzung auslöst.

    😮 Hart, wieso erstellt MediaWindow eine zweite uninitialisierte instanz??? das macht doch nur ein Pseudo-Fenster für Messageverarbeitungen...

    (D)Evil schrieb:

    find längerer Code ist im Forum immer schlecht zu lesen (zumindest wenn er nicht kommentiert ist)

    *so rot werd* -> #FF0000 *schäm*

    geeky schrieb:

    Die meisten scheinen noch MCI zu nutzen.

    och nö, bitte nicht die MCI ^^"""

    merker schrieb:

    Azrael, il Meraz schrieb:

    Denn eine integration von DirectShow in eine (von einer Sterblichen Hand) verwendbare Klasse wird nicht erläutert.

    Du musst Dir die Struktur der Klasse "MMMUSIC" besser überlegen.
    Ev. würde es schon reichen, wenn Du in der WinMain folgendes auskommentierst :

    // mmm->MediaWindow(hWnd);
    
    // mmm->MusicMsgDp();
    

    das Programm verursacht keinen Fehler mehr, hört aber net auf, abzuspielen, nachdem man es beendet ^^", bzw. wird nachm schließen nicht mehr beendet xD. Irgendwas stimmt im WinAPI teil glaub ich nicht ganz ^^"". Oder irgendwelche DirectShow threads werden net beendet. oh man 🙄



  • Azrael, il Meraz schrieb:

    wieso erstellt MediaWindow eine zweite uninitialisierte instanz???

    Mit "zweiter Instanz" meinte ich, dass der Aufruf von "mmm->MediaWindow(hWnd)" ein zweites Fenster erzeugt hat. Das ist kein "Pseudo-Fenster" sondern ein "echtes".
    In der WndProc des zweiten Fensters wird "DispatchMessage(&msg)" aufgerufen -> FATAL.
    Innerhalb von "DispatchMessage(&msg)" ruft das Betriebssystem immer die WndProc auf -> solange bis der Stack überläuft.

    Azrael, il Meraz schrieb:

    Irgendwas stimmt im WinAPI teil glaub ich nicht ganz

    Teste erstmal, ob die "MMMUSIC" generell funktioniert, z.B. so :

    // in der WinMain nur folgendes :
     MMMUSIC *mmm = new MMMUSIC;
    
     mmm -> InitDirectShow ();
     mmm -> LoadFile       (TEXT("amr.mp3"));
     mmm -> play           ();
     Sleep (10000);
     mmm -> stop           ();
     mmm -> release        ();
     delete (mmm);
    
    // MMMUSIC::stop () ändern :
    void MMMUSIC::stop()
    {
      mMediaControl  -> Stop ();
      mMediaPosition -> put_CurrentPosition (0); // <- hinzufügen
    }
    


  • jap, klappt, brauche aber umbedingt messageverarbeitung^^""".

    Und ich glaube, ich habs nicht ganz verstanden, was jetzt so fatal ist Oo.
    das zweite Fenster wird doch legal erstellt und initialisiert Oo.

    der darf man nun nur einen DispatchMessage() pro programm haben?

    bzw. das PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE) nimmt sich doch nur die nachrichten, die für das zweite fenster bestimmt sind, also die manuelle WM_GRAPHEVENT...

    DispatchMessage() wird doch garnicht innerhalb eines WndProcs aufgerufen Oo. in der Messageschleife darfs auch net sein, oder wie?

    Ich glaub, ich kapier grad irgendwas nicht xDD



  • Azrael, il Meraz schrieb:

    DispatchMessage() wird doch garnicht innerhalb eines WndProcs aufgerufen

    Stimmt. Mein Fehler. Da habe ich irgendwas übersehen. Vielleicht schon ein bischen spät. 🙂

    Die "MMMUSIC" läuft also.
    Dann setz jetzt mal in der WinMain "mmm->MediaWindow(hWnd);" wieder ein (an der gleichen Stelle), aber änder mal folgendes in der MessageLoop der WinMain :

    mmm->InitDirectShow(); 
    mmm->MediaWindow(hWnd); 
    mmm->LoadFile(TEXT("amr.mp3")); 
    mmm->play(); 
    
    while(true) 
    { 
    
     if(PeekMessage(&msg,hWnd, 0,0, PM_REMOVE)) 
     { 
      if(msg.message == WM_QUIT) break; 
    //   mmm->MusicMsgDp(); // <- nicht hier aufrufen
                            // sonst kann das zweite Fenster immer nur dann seine
                            // Botschaften bearbeiten, wenn das erste Fenster eine kriegt
      TranslateMessage (&msg); 
      DispatchMessage  (&msg); 
     } 
    
     mmm->MusicMsgDp();     // <- sondern hier (ausserhalb)
    
    }
    


  • öhm. kann das sein, dass das erste fenster nachrichten an den WndProc vom 2ten schickt? Oo. Das wär für mich zwar unerklärlich, aber irgendwie scheint das so zu sein... obwohl das garnicht sein kann - es wird eine WM_GRAPHEVENT nachricht geschickt

    ich hab grad wieder debuggt - und etwas unmögliches gesehen. hier:

    if(!mmm)
    	{
    		return DefWindowProc(hwnd, uMsg, wParam, lParam);
    	}
    	else
    	{
    		return mmm->MusicProc(hwnd, uMsg, wParam, lParam);
    	}
    

    macht er beide returns.... ich glaub ich krieg alpträume...



  • "mmm" ist erst dann ein gültiger Zeiger wenn das Betriebssystem die Static_proc mit WM_CREATE aufgerufen hat. Vorher nicht.
    D.h. er geht 2,3,4 mal in die DefWindowProc(hwnd, uMsg, wParam, lParam) und dann nicht mehr.

    Funktioniert die "MMMUSIC" nun auch mit eigenem Fenster ? Falls ja, dann brauchst Du das Fenster aus der WinMain nicht mehr.



  • ist mir schon klar, dass zuerst noch paar andere nachrichten kommen^^ hab mir alles schön gemerkt 😛 . ich hab aber im einzelschrittmodus debuggt und da springt er nach dem if() zum return DefWindowProc() und danach geht er einfach in die else zeile und zu return mmm->MusicProc(). sowas ist meiner meinung nach recht krank.

    Müsste auch mit eigenem Fenster gehen. hab auch umprogrammiert, klappt aber trotzdem nicht >.<. noch komischer - hier ein schönes Bild:
    http://xcpp.de/ressources/cpp/hae.jpg

    Hab versucht, ein haltepunkt im MusicProc zu machen (der muss ja aufgerufen werden, damit OnGraphEvent ausgeführt wird) und naja, der Haltepunkt wird einfach ignoriert, und da steht dann sowas... Das megakranke dabei ist ja, dass OnGraphEvent aufgerufen wird, ohne dass der MusicProc erreicht wird.

    Also - das ist jetzt so ziemlich meine kränkste programmiererfahrung xD



  • Ups. sorry leute - ich hab hier den totalen schwachsinn gemacht. Eigentlich brauch ich garkein WndProc für die Messageverarbeitung von DirectShow. geht auch ganz einfach ohne. Das Buch, nach welchem ich lerne ist an allem schuld xD, das hat mich total verwirrt. so Wie s dort erklärt war, ist das unvermeidlich, aber ein netter Mensch hat mich grad darauf hingewiesen, dass das kompletter schwachsinn ist, was ich mache 😣 xD. Trotzdem vielen Dank für die hilfe^^


Anmelden zum Antworten