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_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 (currentposition)
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. :)
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.
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 completioncode. 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.
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