[C# Net] Anfänger leidet unter Directshowlib - Capturetest

chmee

verstaubtes inventar
Premium-User
Mahlzeit. Also mal wieder Ich. Es ist zum Heulen. Ich sitze in unregelmäßigen Abständen am Visualstudio2005 und versuche meine ersten Schritte in aktuellen Sprachen. Wenn ich doch zumindest eine Source runterladen und einfach kompilieren könnte, wäre zumindest ein kleines Glücksgefühl da.
Nee Nee, so einfach ist das alles nicht #WÜRG# !

Aufgabenstellung:
Unter VS2005 - ob VB oder C# - einfach nur ein Previewfenster des Videoeingangs zeigen.
Also FirewireCam angeschlossen und per WDM oÄ ansprechen.

Sources mit 100% Lösungsansätzen:
http://www.limegreensocks.com/DShow/
http://sourceforge.net/project/showfiles.php?group_id=136334

Nun:
Ich bekomme nicht mal "Capturetest" von der ersten Seite zum Laufen.
Fehler/Warnungen: Directshowlib nicht referenziert.
In der DirectX.Capture ist sie sauber verwiesen, in der Capturetest findet er sie nicht.

Also:
Suche Hilfe. Jemand der mit mir die Capturetest von Anfang bis zum erfolgreichem
Release-Compile durchgeht.

Nebenbei: Bin bereit, zu Donaten, wenn mir jemand die Basics von VB/C#.Net beibringt.
Beispiel: Diese Seite - deren Codesnippets und ihre Anwendung in eigenen Projekten
hinreichend erklären

mfg chmee
 
Zuletzt bearbeitet:
Warum löscht Du den defekten Verweis nicht und fügst ihn von Hand wieder hinzu?
Könnte sein, dass die Version nicht stimmt oder ähnliche Probleme...
 
Danke :) Das mit dem neu Hinzufügen hat geklappt.

Kommt davon, wenn ich es nicht gewohnt bin, dass ein einfacher Code einen
Riesenunterbau benötigt ( Projektordner, IDE-Einstellungen )

mfg chmee
 
Zu guter Erst, Ich kenne es aus den mir innewohnenden Fachgebieten, dass nuub-Fragen
echt ärgerlich sind. Und Meine Antwort ist das diplomatische "Die Welt ist voll von Tuts,
also lerne !" Stehe nun als genau der "N o o b" da :(

1. Video per Openfiledialog aussuchen - Läuft
2. Graphbuilder erstellen - ?
3. Videowindow initialisieren - ? Wo wird das Video dargestellt ? Form ?
4. Video im Pause Modus auf Frame 0 darstellen UND auslesen können

Ziel: Einzelbilder eines Videos mit Tastendruck durchgehen.

Im Directshowlib2005-Sample(PlayWnd) ist natürlich ein Beispiel drin, aber leider mit so einem
Overhead, dass ich nicht durchblicke.

Nochmal: Ein bisschen unter die Arme greifen täte mir wirklich gut :) mfg chmee
 
Zuletzt bearbeitet:
  • Sollte selbst für einen n o o b kein Problem darstellen. *fg* :D
  • Benötigte Objekte
C#:
IGraphBuilder m_objGraphBuilder = null;

IBasicVideo2 m_objBasicVideo2 = null;
IBasicAudio m_objBasicAudio = null;

IVideoWindow m_objVideoWindow = null;
IVideoFrameStep m_objVideoFrameStep = null;

IMediaEventEx m_objMediaEventEx = null;
//IMediaSeeking m_objMediaSeeking = null;
IMediaPosition m_objMediaPosition = null;
IMediaControl m_objMediaControl = null;
/*-------------------------------------------------------------------------------------------*/
const int WM_APP = 0x8000;
const int WM_GRAPHNOTIFY = WM_APP + 1;
const int EC_COMPLETE = 0x01;
const int WS_CHILD = 0x40000000;
const int WS_CLIPCHILDREN = 0x02000000;
const int WS_CLIPSIBLINGS = 0x04000000;
Interfaces Öffnen:
C#:
void GetInterfaces( string clipFile ) {
	Type comtype = null;
	object comobj = null;
	try {
		try{
			comtype = Type.GetTypeFromCLSID( Clsid.FilterGraph );
			if ( comtype == null )
				throw new NotSupportedException( "DirectX (8.1 or higher) not installed?" );
			comobj = Activator.CreateInstance( comtype );
			m_objGraphBuilder = (IGraphBuilder) comobj;
			comobj = null;

			int hr = m_objGraphBuilder.RenderFile( clipFile, null );
			if ( hr < 0 )
				Marshal.ThrowExceptionForHR( hr );

			m_objMediaControl = (IMediaControl) m_objGraphBuilder;
			m_objMediaEventEx = (IMediaEventEx) m_objGraphBuilder;
			//m_objMediaSeeking = (IMediaSeeking) m_objGraphBuilder;
			m_objMediaPosition = (IMediaPosition) m_objGraphBuilder;

			m_objVideoWindow = m_objGraphBuilder as IVideoWindow;
			m_objBasicVideo2 = m_objGraphBuilder as IBasicVideo2;
			m_objBasicAudio = m_objGraphBuilder as IBasicAudio;
		}
		finally {
			if ( comobj != null ){
				Marshal.ReleaseComObject( comobj );
				comobj = null;
			}
		}
	}
	catch ( Exception ex ){
		throw new COMException( string.Format(
			"DirectShow.NET Error!{0}Could not get interfaces. See InnerException for Details!{0}", Environment.NewLine ),
			ex );
	}
	
}
Interfaces Schließen:
C#:
public int CloseInterfaces() {
	int hr = 0;
	try {
		if ( m_objMediaControl != null ){
			hr = m_objMediaControl.StopWhenReady();
			m_objMediaControl = null;
		}

		if ( m_objMediaEventEx != null ){
			hr = m_objMediaEventEx.SetNotifyWindow( IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero );
			m_objMediaEventEx = null;
		}

		if ( m_objVideoWindow != null ){
			hr = m_objVideoWindow.put_Visible( DsHlp.OAFALSE );
			hr = m_objVideoWindow.put_Owner( IntPtr.Zero );
			m_objVideoWindow = null;
		}

		//m_objMediaSeeking = null;
		m_objMediaPosition = null;
		m_objBasicVideo2 = null;
		m_objVideoFrameStep = null;
		m_objBasicAudio = null;

		if ( m_objGraphBuilder != null )
			Marshal.ReleaseComObject( m_objGraphBuilder );
		m_objGraphBuilder = null;
	}
	catch{}
	return hr;
}}
  • Input Typ Analysieren:
C#:
internal enum ClipType
{
	None,
	AudioVideo,
	VideoOnly,
	AudioOnly
}

ClipType clipType;

void CheckClipType() {
	if ( m_objBasicAudio == null )
		clipType = ClipType.None;
	else
		clipType = ClipType.AudioOnly;

	if ( (m_objVideoWindow == null) || (m_objBasicVideo2 == null) )
		return;

	int visible;
	int hr = m_objVideoWindow.get_Visible( out visible );
	if ( hr < 0 )
		return;
	else{
		if ( m_objBasicAudio == null )
			clipType = ClipType.VideoOnly;
		else
			clipType = ClipType.AudioVideo;
	}
}
Video Laden:
Das videoWindowHandle ist das Handle zu einem Control, in dem das Video "hineingemalt" werden soll.
In der Regel ein Panel
Das notifyWindowHandle ist has Handle zu dem Control an welches die EC_COMPLETE Nachricht gesendet wird.
(Wenn die Wiedergabe abgeschlossen ist)
Dieses Control sollte immer das Parent des Panels sein, in dem Du das Video wieder gibst.
C#:
int PrepareToPlayback( out int hr, IntPtr videoWindowHandle, Rectangle videoWindowRectangle, IntPtr notifyWindowHandle ) {
	
	hr = -1;

	CloseInterfaces();
	if ( !GetInterfaces( sFileName ) )
		return hr;

	CheckClipType();
	if ( clipType == ClipType.None )
		return hr;

	hr = m_objMediaEventEx.SetNotifyWindow( notifyWindowHandle, WM_GRAPHNOTIFY, IntPtr.Zero );

	if ( (clipType == ClipType.AudioVideo) || (clipType == ClipType.VideoOnly) ){
		m_objVideoWindow.put_Owner( videoWindowHandle ); //Handle des Video Panel's holen
		m_objVideoWindow.put_WindowStyle( WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
		m_objVideoWindow.SetWindowPosition(
			videoWindowRectangle.Left, //VideoFenstergröße dem Video Panel anpassen
			videoWindowRectangle.Top,
			videoWindowRectangle.Width,
			videoWindowRectangle.Height );
	}
	else throw new Exception( "Tartegetfile has only Audio Stream!" );

	return hr;
}
Video Abspielen:
C#:
public bool Play( IntPtr videoWindowHandle, Rectangle videoWindowRectangle, IntPtr notifyWindowHandle ) {
	try {
		int hr;
		
		PrepareToPlayback( out hr, videoWindowHandle, videoWindowRectangle, notifyWindowHandle );
		else
			hr = 0;

		if ( hr >= 0 )
			hr = m_objMediaControl.Run();
		return hr >= 0;
	}
	catch ( Exception ex ){
		throw new COMException( string.Format("DirectShow.NET{0}Could not start clip. See InnerException for Details!{0}", Environment.NewLine ), ex );
	}
}
Ende der Wiedergabe:
Um festzustellen wann eine Datei abgespielt wurde, wird die WndProc-Methode des Controls überschrieben,
welches in der Play Funktion als NotifyWindow angegeben wurde, um die EC_COMPLETE Nachricht abzufangen.
C#:
DsEvCode DirectShowEventCode;
int DirectShowEventParam1, DirectShowEventParam2, DXexec_hr = 0;

protected override void WndProc( ref Message m ) {
	
	if ( m.Msg == myDirectShowPlayer.WMgraphnotify ) {
		try {
			do {
				v_DXexec_hr = myDirectShowPlayer.objMediaEventEx.GetEvent(
					out DirectShowEventCode,
					out DirectShowEventParam1,
					out DirectShowEventParam2,
					0 );
				if ( DXexec_hr < 0 )
					break;

				DXexec_hr = myDirectShowPlayer.objMediaEventEx.FreeEventParams(
					DirectShowEventCode,
					DirectShowEventParam1,
					DirectShowEventParam2 );

				if ( DirectShowEventCode == DsEvCode.Complete )	
					myDirectShowPlayer.objMediaControl.Pause();
			} while ( DXexec_hr == 0 );
		}
		catch ( Exception ex ) {
			Trace.WriteLine( ex.ToString() );
		}
	}
	

	base.WndProc( ref m );
}
  • Video Stoppen und "zurück spulen":
C#:
public bool Stop() {
	try {
		m_objMediaControl.StopWhenReady();
		int hr = m_objMediaPosition.put_CurrentPosition( 0 );
		return hr >= 0;
	}
	catch ( Exception ex ){
		throw new COMException( string.Format("DirectShow.NET{0}Could not stop clip. See InnerException for Details!{0}", Environment.NewLine ), ex );
	}
}
Der Code ist kein Copy-Paste. Es sind snippeds meiner Implemtation,
aus denen ich einiges an Statusangaben entfernt und anderen Sachen habe.
Er zeigt Dir lediglich wie man die Interfaces öffnet, den Videotyp prüft, das Video abspielt, stoppt und das Ende der Wiederagabe fest stellt.

Frag wenn Du noch offene Fragen hast.
 
Zuletzt bearbeitet:
Erstmal 1000 Dank. Leider komme ich gerade von Arbeit und muss gleich weiter,
habe morgen Zeit, teste damit meine Knowledge und melde mich .

mfg chmee

**EDIT**

zu 1. Doch :) Da ist nix Sequentielles mehr. :) Mein Problem ist - wie schon mehrmals angedeutet -
dass ich in die OOP-Denke noch nicht reinfinden konnte. Aber dann eben jetzt mit der Brechstange.

2.
Interfaces öffnen - hmm , ok .. Darf man sowas Prozedur oder Funktion nennen ?
Rückgabewert Bool ob oK oder nicht, right ? Warum ist hiervor kein Public ?

Interfaces schließen - auch OK - und warum wird hier ein public gesetzt ?
-- Eine Klammer am Ende zuviel ?

Play - Wozu das Else da drin ?

DSevCode ? Welche Klasse/Verweis ?
ClsId - Woher das und woher Marshal

Werde es jetzt auf meine Bedürfnisse umschreiben bzw. erst mal zum Laufen kriegen.
Trial and Error to learn this Shice :)

mfg chmee
 
Zuletzt bearbeitet:
Ohh mann, hättest ruhig einen neuen Post erstellen und den alten löschen können.
Hab deine Antort gar net mitbekommen. :-(

  1. GetInterfaces - Die Methode würde ich eine Funktion nenen, da sie einen Rückgabewert hat. ;)
    Die Funktion ist nicht public, da sie nur intern verwendet werden soll. Also nur von den Wiedergabemethoden.
  2. CloseInterfaces - Die Methode ist public damit von aussen her alles abgebrochen werden kann.
    Zb bei'm schließen des Programms. Ich würde das sowieso explizit in der Dispose Methode deines Controls aufrufen!
    Also das mit der Klammer ist ja mal tragisch. :D
  3. Play - Das else ist drinnen, damit hr auf 0 gesetzt wird wenn die Widergabe nicht initialisiert werden konnte.
  4. DsEvCode ist in der DS Lib vorhanden, ergo musst sie auch referenzieren.
    Was Marshal ist, kannst in der MSDN oder in deinem Objektbrowser nachlesen.
 
Nicht schlimm.. Musste mich eh n paar Tage damit beschäftigen.

Habe jetzt ne Woche nicht dran gesessen, stand da vor dem Problem, dass ich
den Pause-Modus bzw. frameweises Weitergehen nicht hinbekommen habe.

Danke erstmal, ich merke, dass mir alle Hilfe nichts bringt, wenn ich es nicht restlos
verstanden habe..

mfg chmee
 
Dann debugge dich durch das Beispiel auf TheCodeProject. Das ist für mein verhältnisse einfach gestrickt und lauffähig.
Ich denke wenn Du dir ein bissel mühe gibst, wirst das schon verstehen. :)
Ich hab das auch nur mit Hilfe von dem Beispiel von TheCodeProject verstanden.

Für das vor- und zurückspulen verwendest m_objMediaPosition.put_CurrentPosition.
Als Control könntest eine TrackBar verwenden. TrackBar.MaxValue währe dann m_objMediaPosition.get_Duration.
 
Hi :) Mal wieder die Zeit gefunden, um weiter am Modul Video zu drehen..

Bin im Geiste C# näher gekommen.

Also neue Fragen - nehmen wir den obigen SourceCode als Beispiel.
Code:
 m_objVideoWindow.put_Owner( videoWindowHandle );
1. Das videoWindowHandle wäre im Falle des gemeinten Panel also Panel1.Handle ?
( bzw in Deinem Fall ein Panel namens videoWindowRectangle )

Und das WindowNotify-Handle wäre als Parent zB Mainform.Handle ?

Code:
PrepareToPlayback( out hr, videoWindowHandle, videoWindowRectangle, notifyWindowHandle );
2. Was heisst das out hr ?

Code:
const int WM_APP = 0x8000;
const int WM_GRAPHNOTIFY = WM_APP + 1;
ist im DShow-Sample
Code:
private const int WMGraphNotify = 0x0400 + 13;
3. Ist 0x0400+13=0x8000+1 ? Hex-Kodierung und Dezimal gemischt?

Letzte Frage für Heute:
Code:
hr = mediaEventEx.SetNotifyWindow(Handle, WMGraphNotify, IntPtr.Zero);
DsError.ThrowExceptionForHR(hr);

hr = videoWindow.put_Owner(this.Handle);
DsError.ThrowExceptionForHR(hr);
Ich bekomme trotz meines wachsenden Wissens an jener Stelle
immer eine NullReferenceException - Instanz erstellen mit Neu.

Hatte ich übrigens schon mehrere Male, dass ich gutgläubig Methoden
aufgerufen habe ( Bitmap.Clone() ), die mir ein NullRef-Exc geworfen haben.
4. Anfängerfehler ?

Mit besten Grüßen und
erstmal vielen Dank für erste erfolgreiche Schritte in eine neue Welt :)
chmee
 
Zuletzt bearbeitet:
Zurück