Version 2.0!
Features
Tutorials
Files
Glossary
Projects
Contact
Links
Message Board
Extras
LuckyCam
Old News
Sign Guestbook
View Guestbook
VB Horoscope
VB Photo Album
.
ATTENTION READERS! Lucky's VB Gaming Site is no longer active. For updated game programming information and tutorials, please visit The Game Programming Wiki!

DirectShow Einführung / Einfache Wiedergabe


Was ist DirectShow?

Active Movie war der ursprüngliche Name für DirectShow. Jetzt, da DirectShow ein Teil von DirectX, seit Version 8, geworden ist, wird der Name ActiveMovie nicht mehr verwendet. Trotzdem heißt die Programmbibliothek, die wir verwenden werden "ActiveMovie control type library" (QUARTZ.DLL).

DirectShow ist eine Schnittstelle für qualitativ hochwertiges und schnelles Wiedergeben und Aufnehmen von Multimedialen Streaming Daten. Es unterstützt eine breite Front von Dateiformaten, unter anderem ASF, MPEG, AVI, MP3 und WAV Dateien. In DirectShow sind andere DirectX Technologien eingebaut, und es prüft und verwendet automatisch Beschleuniger-Hardware, falls vorhanden, läuft aber auch auf Systemen ohne Beschleuniger-Hardware.


DirectShow Initialisierung

Als erstes müsst ihr im Menü Projekt - Verweise einen Verweis auf die Programmbibliothek "ActiveMovie control type library" herstellen.

Der nächste Schritt ist die Deklaration der benötigten Objekte. Kopiert diesen Code in den Deklarationsteil eurer Anwendung:

Private m_objBasicAudio As IBasicAudio
Private m_objBasicVideo As IBasicVideo
Private m_objMediaEvent As IMediaEvent
Private m_objVideoWindow As IVideoWindow
Private m_objMediaControl As IMediaControl
Private m_objMediaPosition As IMediaPosition

OK... bevor wir aber neue Instanzen dieser Objekte erstellen können um eine Datei abzuspielen, müssen wir erst die alten Instanzen zerstören! Hier ist eine kleine Prozedur, die alle Objekte aus dem Speicher entfernt:

Sub RemoveDShow()
    On Local Error GoTo RemoveDShowError
    
    'Wenn eine MediaControl Instanz existiert, dann stoppen wir als erstes die Wiedergabe
    If ObjPtr(m_objMediaControl) > 0 Then
        m_objMediaControl.Stop
    End If
    'Wenn eine VideoWindow Instanz existiert, dann beseitigen wir den Verweis auf das
    'Wiedergabeziel (render target)
    If ObjPtr(m_objVideoWindow) > 0 Then
        m_objVideoWindow.Owner = 0
    End If
    'Alle Objekte zerstören
    If ObjPtr(m_objBasicAudio) > 0 Then Set m_objBasicAudio = Nothing
    If ObjPtr(m_objBasicVideo) > 0 Then Set m_objBasicVideo = Nothing
    If ObjPtr(m_objMediaControl) > 0 Then Set m_objMediaControl = Nothing
    If ObjPtr(m_objVideoWindow) > 0 Then Set m_objVideoWindow = Nothing
    If ObjPtr(m_objMediaPosition) > 0 Then Set m_objMediaPosition = Nothing
    Exit Sub
RemoveDShowError:
    Err.Clear
    Exit Sub
End Sub

So, nun sind wir bereit, eine Multimedia Datei zu öffnen. Das funktioniert so:

Sub OpenDShowFile(Filename As String)
    On Local Error GoTo OpenFileError
    Set m_objMediaControl = New FilgraphManager
    Call m_objMediaControl.RenderFile(Filename)
    
    Set m_objBasicAudio = m_objMediaControl
    m_objBasicAudio.Volume = 0 'Volle Lautstärke
    m_objBasicAudio.Balance = 0 'Zentrierte Balance
    
    Set m_objVideoWindow = m_objMediaControl
    m_objVideoWindow.WindowStyle = WS_VISIBLE 'WS_VISIBLE = &H10000000
    m_objVideoWindow.Top = 0
    m_objVideoWindow.Left = 0
    m_objVideoWindow.Width = picTarget.Width
    m_objVideoWindow.Height = picTarget.Height
    m_objVideoWindow.Owner = picTarget.hWnd
    
    Set m_objMediaEvent = m_objMediaControl
    
    Set m_objMediaPosition = m_objMediaControl
    m_objMediaPosition.Rate = 1 'Normale Wiedergabegeschwindigkeit
    
    Exit Sub
OpenFileError:
    Err.Clear
    Resume Next
End Sub

Bevor ich beschreibe was hier eigentlich passiert, fragt ihr euch bestimmt, warum wir bei Fehlern einfach mit der nächsten Anweisung fortfahren. Nun, das ist einfach: Stellt euch vor, dass ihr eine Audio Datei öffnet. Unglücklicherweise haben Audio Dateien keine Video Daten (zumindest meine haben keine). Also gibt DirectShow einen Fehler aus, wenn wir versuchen das VideoWindow Objekt zu initialisieren.

Als erstes erstellen wir eine Instanz des FilterGraph Objekts für das jeweilige Dateiformat. Ein FilterGraph bestimmt wie Multimedia Dateien, die mit DirectShow geöffnet wurden, verarbeitet werden.

Dann erstellen und initialisieren wir unser BasicAudio Objekt, und stellen die anfängliche Lautstärke (volume) und Balance (balance) ein. Diese drei Zeilen könnten auch einen Fehler verursachen. Zum Beispiel, wenn ihr eine Videodatei ohne Audiodaten öffnet.

Im nächsten Schritt erstellen wir eine Instanz des VideoWindow Objekts, das wir für die Visualisierung von Video Dateien brauchen. Wie schon zuvor erwähnt, können diese Codezeilen aufgrund der gelieferten Daten Fehler verursachen! Wir setzen die WindowStyle Eigenschaft des VideoWindow Objekts auf WS_VISIBLE. Alle verfügbaren WindowStyle konstanten sind am Ende dieses Tutorials aufgelistet, und sind ausserdem in den API Text viewer Dateien, die mit Visual Basic ausgeliefert werden, aufgeführt. Die Top, Left, Width und Height Eigenschaften bestimmen die Größe des Ausgabefensters. Nun müssen wir noch einen sog. Besitzer (owner) bestimmen. Das ist das Ausgabeziel. In diesem Fall ist es ein einfaches PictureBox Steuerelement, und wir übergeben dessen WindowHandle.

Jetzt initialisieren wir das MediaEvent Objekt, mit dem wir die Wiedergabe steuern können. Wir werden es später dazu verwenden, den derzeitigen Wiedergabestatus zu erfahren.

Das letzte Objekt, dass wir initialisieren müssen, ist das MediaPosition Objekt. Das MediaPosition Objekt ermöglicht es uns die derzeitige Wiedergabeposition (current position) zu lesen und zu schreiben, die Wiedergabegeschwindigkeit (rate) zu lesen und zu schreiben und die Wiedergabedauer der Datei (duration) zu lesen. In dem oben gezeigten Code setzen wir die Wiedergabegeschwindigkeit auf 1, die eine normale Wiedergabegeschwindigkeit darstellt. Höhere Werte werden DirectShow die Datei schneller spielen lassen, niedrigere werden die Datei langsamer ablaufen lassen.

So, das war's mit der Initialisierung.


Wiedergeben der Datei

Wir werden mit der Wiedergabe der geladenen Datei anfangen:

If CLng(m_objMediaPosition.CurrentPosition) = CLng(m_objMediaPosition.Duration) Then
    m_objMediaPosition.CurrentPosition = 0
End If
Call m_objMediaControl.Run

Ja, es ist so einfach, wie es aussieht! :) Zuerst überprüfen wir, ob die derzeitige Wiedergabeposition am Ende der Datei ist. Falls das so ist, setzen wir die Wiedergabeposition an den Anfang zurück. Dann rufen wir einfach die Run Methode des MediaControl Objekts auf, und das war's!


Pausieren der Wiedergabe

Um die Wiedergabe zu unterbrechen, rufen wir einfach die Pause Methode des MediaControl Objekts auf:

Call m_objMediaControl.Pause


Anhalten der Wiedergabe

Manchmal wollen einfältige Benutzer die Wiedergabe stoppen und von vorne beginnen. Na gut, dann werden wir sie lassen. :)

Call m_objMediaControl.Stop
m_objMediaPosition.CurrentPosition = 0


Vorwärts und Rückwärts suchen

Ein weiteres simples Feature, dass ein potentieller Benutzer gern verwenden würde :) Wir erreichen dies, indem wir einfach die CurrentPosition Eigenschaft des MediaPosition Objekts verändern. Dies WIRD den filter graph dazu veranlassen die Wiedergabe zu unterbrechen (pause), die neue Position einzustellen und dann die Wiedergabe fortzusetzen (run). Aber diese Methode hat sich als schnell genug erwiesen, um sie in Echtzeit zu verwenden .

Public Sub SeekPosition(Amount As Double)
    If m_objMediaPosition.CurrentPosition + Amount < 0 Then
       m_objMediaPosition.CurrentPosition = 0
    ElseIf m_objMediaPosition.CurrentPosition + Amount > _
       m_objMediaPosition.Duration Then
        m_objMediaPosition.CurrentPosition = m_objMediaPosition.Duration
    Else
        m_objMediaPosition.CurrentPosition = m_objMediaPosition.CurrentPosition + Amount
    End If
End Sub

Um rückwärts zu suchen, brauchen wir nur einen negativen Wert für Amount zu übergeben. Nun, da wir dem Benutzer ein derart mächtiges Werkzeug zur Verfügung stellen, müssen wir auch genau auf seine Eingaben achten! :) Denn, wenn er eine Position vor dem Start oder hinter dem Ende der Datei sucht, müssen wir diesen Fehler korrigieren.

Das MediaEvent Objekt

Syntax:

m_objMediaEvent.WaitForCompletion msTimeout, EvCode

Wir werden nur die WaitForCompletion Methode dieses Objekts verwenden. Diese Methode akzeptiert zwei Variablen als Argumente. Das erste Argument legt fest, nach welchem Zeitraum die Methode die Kontrolle an uns zurückgeben soll, und das zweite Argument wird von der Methode selbst gesetzt und enthält den sog. event completion code. Wenn wir nun 0 oder eine höhere Zahl als msTimeout übergeben, dann wird die Methode die Kontrolle erst an uns zurückgeben, wenn dieses Zeitlimit erreicht (0 = sofort) oder wenn das Dateiende erreicht wurde, was auch immer zuerst eintritt. Wenn das Zeitlimit erreicht wurde, dann wird der EvCode gleich 0 (null) sein und der Laufzeit Fehler 287 wird eintreten ("Application-defined or object-defined error"). Wir können diesen Fehler so ignorieren:

On Error Resume Next

Also für alles andere ausser -1, dass als msTimeout übergeben wird, müssen wir den Fehler ignorieren und den EvCode überprüfen. 0 (null) bedeutet, dass DirectShow die Datei immer noch wiedergibt, 1 oder höher bedeutet, dass das Dateiende erreicht wurde. Wenn wir -1 als msTimeout übergeben, dann wird DirectShow uns die Kontrolle erst wiedergeben, sobald das Dateiende erreicht wurde. Aber in der Zwischenzeit reagiert unsere Anwendung auf keinerlei Benutzereingaben!


Das war's!

Das war der ganze grundlegende Kram, den ihr wissen müsst! Mit diesem Code seit ihr in der Lage jede Datei abzuspielen, die ihr sonst mit eurem Standart Player abspielt! Falls ihr eine Datei abspielen wollt, die nicht zu DirectShows normalen Dateiformaten gehört, dann müsst ihr nur den entsprechenden codec (COder/DECoder) für dieses Format installieren.

Ich habe ausserdem eine Beispielanwendung erstellt, die den oben gezeigten Code verwendet. Ladet sie hier herunter. (Die Kommentare in dieser Beispielanwendung sind alle englisch!)

Ich hoffe ihr habt unsere Zeit zusammen genossen. Bis zum nächsten Mal! 

Und noch viel Spaß beim coden von coolen Multimedia Spielen und Anwendungen mit DirectShow

-Paladin




Anhang

Alle WindowStyle konstanten... Ich schätze ihr braucht eh nur WS_VISIBLE, aber ich hab sie trotzdem alle aufgelistet:

Public Const WS_BORDER = &H800000
Public Const WS_CAPTION = &HC00000 
Public Const WS_CHILD = &H40000000
Public Const WS_CHILDWINDOW = (WS_CHILD)
Public Const WS_CLIPCHILDREN = &H2000000
Public Const WS_CLIPSIBLINGS = &H4000000
Public Const WS_DISABLED = &H8000000
Public Const WS_DLGFRAME = &H400000
Public Const WS_GROUP = &H20000
Public Const WS_HSCROLL = &H100000
Public Const WS_ICONIC = WS_MINIMIZE
Public Const WS_MAXIMIZE = &H1000000
Public Const WS_MAXIMIZEBOX = &H10000
Public Const WS_MINIMIZE = &H20000000
Public Const WS_MINIMIZEBOX = &H20000
Public Const WS_OVERLAPPED = &H0&
Public Const WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED Or WS_CAPTION Or _
                                                                       WS_SYSMENU Or WS_THICKFRAME Or _
                                                                       WS_MINIMIZEBOX Or WS_MAXIMIZEBOX)
Public Const WS_POPUP = &H80000000
Public Const WS_POPUPWINDOW = (WS_POPUP Or WS_BORDER Or WS_SYSMENU)
Public Const WS_SIZEBOX = WS_THICKFRAME
Public Const WS_SYSMENU = &H80000
Public Const WS_TABSTOP = &H10000
Public Const WS_THICKFRAME = &H40000
Public Const WS_TILED = WS_OVERLAPPED
Public Const WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
Public Const WS_VISIBLE = &H10000000
Public Const WS_VSCROLL = &H200000