Die Community zu .NET und Classic VB.
Menü

Verarbeitung von Audio und Video in .NET

 von 

Kurzfassung 

Inhalt dieser Arbeit sind Schnittstellen zur Verarbeitung von Audio und Video für die Verwendung in Anwendungen, die auf der .NET-Technologie von Microsoft basieren. Die Charakteristika der einzelnen Schnittstellen bzw. Bibliotheken werden beschrieben und mit Beispielen illustriert. Im Zentrum stehen Microsoft DirectX (DirectShow, DirectSound, DirectMusic und AudioVideoPlayback) und Windows Media (Windows Media Format, Windows Media Encoder und Windows Media Player) als Programmierschnittstellen für Audio und Video unter dem Betriebssystem Microsoft Windows. Schnittstellen zur Darstellung von 2D- und 3D-Szenen (DirectX Graphics) sind nicht Teil dieser Arbeit.

Einleitung  

Während mit Java entwickelte Anwendungen und Applets bereits im Jahr 1998, als Sun Microsystems das JMF (Java Media Framework) in der Version 1.0[28] vorstellte, von einem für Java entwickelten Framework zur Medienverarbeitung Gebrauch machen konnten, verwendete man in Win32-Anwendungen entweder VfW (Video for Windows) oder setzte das 1996 von Microsoft als Active-Movie veröffentlichte DirectShow ein, welches später in DirectX integriert wurde[1]. Das JMF lag im Jahr 2001, als Version 1.0 des .NET Framework veröffentlicht wurde, bereits in Version 2.1 vor. Zu dieser Zeit stand DirectX in Version 8 zur Verfügung. Die in DirectX enthaltenen Technologien verfügten allerdings noch nicht über verwaltete Schnittstellen, die eine komfortable Nutzung innerhalb von auf .NET basierenden Anwendungen ermöglichten. Für DirectX 9 werden verwaltete Schnittstellen für den Zugriff auf DirectX-Technologien bereitgestellt; diese decken jedoch nicht alle Bereiche von DirectX ab; so gab es bspw. im Oktober 2004 noch keine verwaltete Schnittstelle für DirectShow[7].

Ziel dieses Artikels ist es, zu erkunden, wie weit verschiedene Programmierschnittstellen von Microsoft zur Medienverarbeitung für .NET-basierende Anwendungen benutzbar sind und in welchen Bereichen man weiterhin auf die Nutzung nativer Schnittstellen oder COM-Schnittstellen angewiesen ist. Weiters soll beleuchtet werden, ob eine vollständige Öffnung bestehender Schnittstellen zur Medienverarbeitung unter Windows für die Verwendung mit .NET überhaupt in allen Fällen sinnvoll ist oder wie weit fallweise technische Gründe dagegen sprechen. Die Verwendung der beschriebenen Technologien wird exemplarisch anhand praxisnaher Beispiele für die Programmiersprache Visual Basic .NET illustriert. Außerdem wird ein Ausblick auf mögliche Entwicklungen im Gebiet der Medienverarbeitung mit .NET geboten.

Möglichkeiten des Schnittstellenzugriffs in .NET  

Die in diesem Artikel vorgestellten Programmierschnittstellen zur Medienverarbeitung in .NET können auf unterschiedliche Art und Weise innerhalb von .NET-basierenden Anwendungen aus genutzt werden. Um eine Klassifikation der in weiterer Folge betrachteten Schnittstellen zu erleichtern, bietet dieser Abschnitt eine Übersicht über die vielfältigen Möglichkeiten des Zugriffs auf Programmierschnittstellen, die das .NET Framework bereitstellt. Jede dieser Möglichkeiten besitzt charakteristische Vor- und Nachteile, die jeweils kurz erläutert werden sollen.

Verwaltete Assemblies

Technisch ideal für die Verwendung in .NET-basierenden Anwendungen sind Komponenten, die selbst vollständig auf dem .NET Framework basieren und als verwalteter Code ausgeführt werden. Derartige Bibliotheken erlauben einen nativen Zugriff durch .NET-basierende Anwendungen unter voller Ausnutzung der Möglichkeiten der Common Language Runtime (CLR) wie bspw. dem .NET-eigenen Ausnahme- und Sicherheitsmodell.

COM Interop

COM Interop[1] stellt eine Möglichkeit zur Nutzung von COM-Komponenten innerhalb von .NET-basierenden Anwendungen dar, schließt aber auch das Verfügbarmachen von verwalteten Implementierungen für die Verwendung in COM-Umgebungen ein. Entweder stellt der Hersteller einer Komponente PIAs (siehe nächster Punkt) bereit, oder die Interoperabilitätsassemblies können mittels des Hilfswerkzeugs „Tlbimp.exe“ automatisch generiert werden. Bei Verwendung der Entwicklungsumgebung Visual Studio .NET ist es ausreichend, einen Verweis auf die COM-Bibliothek hinzuzufügen; eine Schnittstellenbeschreibung in Form einer CLR-Assembly, welche zur in der COM-Typbibliothek äquivalente Typdefinitionen enthält, wird automatisch generiert. Zur Nutzung von .NET-Assemblies aus einer COM-Umgebung sind COM Callable Wrapper (CCW)[9] erforderlich. Beim Zugriff auf die COM-Komponente aus einer .NET-basierenden Anwendung fungiert der CCW als Proxy, über den die Kommunikation und das erforderliche Marshalling zwischen COM und .NET abgewickelt werden.

Primary Interop Assemblies (PIAs)

Einen Kompromiss zwischen dem Ideal der vollständig verwalteten Assemblies und dem hohen Aufwand einer Neuimplementierung bestehender Komponenten stellen Primary Interop Assemblies (PIAs) dar. PIAs sind vom Hersteller einer Komponente bereitgestellte und unterstützte Wrapper, die eine verwaltete Programmierschnittstelle für bestehende, auf COM basierende Bibliotheken bereitstellen. PIAs erlauben es, mögliche technische Konflikte zwischen COM und .NET innerhalb der Implementierung einer PIA zu lösen und die Programmierschnittstelle an die Konventionen zur Entwicklung von .NET-Bibliotheken anzupassen.

Platform Invoke (PInvoke)

Bei Platform Invoke (PInvoke)[4] handelt es sich um einen Dienst des .NET Frameworks, der es erlaubt, auf unverwaltete Programmierschnittstellen bestehend aus von DLLs exportierten Funktionen zuzugreifen, wobei das Marshalling von Argumenten vom Dienst erledigt wird. Beispiele solcher Programmierschnittstellen sind das Win32/Win64-API und im Bereich der Medienverarbeitung Video for Windows (VfW). Funktionen können mit dem Attribut DllImport markiert werden, um auszudrücken, dass sie extern, nämlich in einer DLL, implementiert und von dieser exportiert werden. Die in Visual Basic .NET zu diesem Zweck zusätzlich bereitstehende Declare-Anweisung verfügt über komfortablere Möglichkeiten des automatischen Marshalling.

Managed Extensions for C++

Managed Extensions for C++[21] sind eine Erweiterung der Programmiersprache C++ um die Möglichkeit, von der Klassenbibliothek des .NET Framework Gebrauch zu machen und Code mittels der Common Language Runtime (CLR) als verwalteten Code auszuführen. Damit besteht die Möglichkeit, in ein und demselben Projekt unverwaltetem Code mit verwaltetem Code zu mischen. Diese als It Just Works (IJW) bezeichnete Vorgehensweise bietet mehr Möglichkeiten als COM Interop und erleichtert sowohl die Entwicklung verwalteter Wrapper um unverwalteten Code als auch die Verwendung von Klassen aus der Klassenbibliothek des .NET Framework innerhalb von mit C++ erstellten Anwendungen.

Schnittstellen zur Medienverarbeitung in .NET  

Als im Jahre 2001 Microsoft das .NET Framework veröffentlichte, standen erst wenige auf der .NET-Technologie basierende Komponenten für die Verwendung in .NET-Programmiersprachen (Microsoft Visual Basic .NET, Microsoft Visual C#, Managed Extensions for C++ und Microsoft Visual J# sowie Compiler und Entwicklungswerkzeuge anderer Hersteller) bereit. Um dennoch den Entwicklern ein leistungsstarkes Werkzeug in die Hand zu geben, stellt das .NET Framework die Möglichkeiten des COM Interop sowie von PInvoke zur Verfügung, über die bestehende Schnittstellen, die auf COM basierenden oder nativen Bibliotheken exportieren, auch in .NET-Anwendungen benutzt werden kön-nen. Einen Überblick über die Technologien zur Medienverarbeitung, die von Microsoft bereitgestellt werden, gewährt[17].

Parallel dazu werden laufend .NET-Schnittstellen für bereits bestehende Technologien zur Medienverarbeitung bereitgestellt. So war bspw. das Codieren von Videodaten im Windows Media-Format bei Erscheinen des .NET Framework nur über COM Interop möglich. In der Zwischenzeit wurden verwaltete Assemblies, meist in Form von PIAs, für bestehende COM-Komponenten, veröffentlicht. Eine vollständige Neuimplementierung aller bestehenden COM-Komponenten ist nicht nur aus ökonomischer Sicht unmöglich, sondern widerspricht auch der Ausrichtung von .NET als Technologie für die Entwicklung von User-Mode-Anwendungen, in denen direkte Zugriffe auf Peripheriegeräte aus Sicherheitsgründen nicht möglich sind und bei denen Echtzeitverhalten zur Laufzeit keine hohe Priorität genießt.

DirectX  

DirectX[6] stellt eine Sammlung von Programmierschnittstellen zur Entwicklung von Multimediaanwendungen für das Betriebssystem Microsoft Windows dar. Neben den in diesem Artikel genauer betrachteten Teiltechnologien DirectShow, DirectSound, DirectMusic und AudioVideoPlayback enthält DirectX u.a. DirectX Graphics, eine Low-Level-Programmierschnittstelle für das Darstellen von 3D-Szenen, DirectPlay, eine medienunabhängige Netzwerkprogrammierschnittstelle und DirectInput zur Arbeit mit Eingabegeräten wie Tastatur, Maus, Joystick und anderen Spielsteuerungen. Alle in DirectX enthaltenen Programmierschnittstellen arbeiten untereinander eng zusammen, so basieren Computerspiele häufig auf einer Kombination von DirectX Graphics, DirectSound und DirectInput.

Zum Zeitpunkt des Entstehens dieses Artikels stellte DirectX 9.0c die neueste Version der DirectX-Bibliotheken dar. Das zur Entwicklung von Anwendungen, die von DirectX Gebrauch machen, erforderliche DirectX 9.0 SDK lag als Update vom April 2005[31] vor. Dieses Paket bietet sowohl Unterstützung für die Verwendung von DirectX in unverwalteten, bspw. mit Microsoft Visual C++ oder Visual Basic 6.0 erstellten, als auch verwalteten Anwendungen, die bspw. mit Microsoft Visual Basic .NET oder Microsoft Visual C# erstellt werden können. Nach der Installation können .NET-Projekten direkt innerhalb der Entwicklungsumgebung von Visual Studio .NET Verweise zu den DirectX-Bibliotheken hinzugefügt werden.

Managed DirectX 9.0 deckt jedoch nicht die vollständigen Möglichkeiten von DirectX 9.0 ab. Vielmehr stehen, insbesondere im Fall von DirectShow, Wrapper nur für die einfachsten, grundlegendsten und gemeinhin „wichtigsten“ Teile von DirectX bereit. Die Entwicklung vollständiger, auf verwaltetem Code basierender Anwendungen, die vom vollen von DirectX 9.0 gebotenen Funktionsumfang Gebrauch machen, ist damit nicht möglich.

DirectShow  

DirectShow ist eine Architektur für Streaming von Audio und Video unter Microsoft Windows, die Wiedergabe, Aufnahme, Formatkonvertierung sowie eine breite Palette von Datenformaten unterstützt[5]. DirectShow basiert auf COM, eine Erweiterung ist ebenfalls nur über COM möglich. Das Abspielen von Audio und Video ist nicht Teil von DirectShow, sondern wird getrennt davon als Teil von Managed DirectX 9.0 bereitgestellt (siehe Abschnitt „AudioVideoPlayback“). DirectShow kann innerhalb von mit Visual Basic entwickelten Anwendungen zum Abspielen eingesetzt werden, weitere Funktionalität wird in Visual Basic nicht unterstützt.

Verwaltete Schnittstellen für die Verwendung von DirectShow stehen nicht zur Verfügung. Es bestehen allerdings dennoch Möglichkeiten, in .NET-basierenden Anwendungen Funktionalität von DirectShow zu nutzen. Die Schnittstellen von DirectShow werden auf zwei Wegen verfügbar gemacht, einerseits als Custom Interfaces für C++ und als COM-Bibliothek für die Verwendung in mit Visual Basic entwickelten Anwendungen. Am Einfachsten dürfte es sein, COM Interop mit der DirectShow-Laufzeitbibliothek „quartz.dll“ zu verwenden, die in beschränktem Umfang Zugriff auf DirectShow gewährt.

Will man die Custom Interfaces benutzen, kann man entweder das Projekt mittels der Managed Extensions for C++ entwickeln oder die Schnittstellen von Interface Definition Language (IDL) nach Visual Basic .NET oder C# übersetzen. Bei der Verwendung der Managed Extensions for C++ entsteht der Nachteil, an C++ gebunden zu sein und Gebrauch von dessen „unschönen“ Syntaxerweiterungen machen zu müssen (C++/CLI[24] könnte hier eine Verbesserung bewirken). Das Nachbilden der Schnittstellen in einer verwalteten Programmiersprache ist dagegen aufgrund des Umfangs der DirectShow-Schnittstellen ein aufwendiger Prozess. Eine Beispielanwendung in C#, die auf der „quartz.dll“ basiert, hat Daniel Strigl entwickelt[27]. Thomas Scheidegger hat in [26] experimentellen Code zur letzteren Vorgehensweise und einige dazugehörige Beispielanwendungen publiziert.

DirectSound  

DirectSound ist eine Programmierschnittstelle zum Abspielen von Klängen mit geringer Latenz unter hoher Kontrolle über die zum Einsatz gelangenden Hardwareressourcen. Audiodaten im Wave-Format können wiedergegeben und über ein Mikrophon aufgenommen werden. Zudem können mehrere Klänge zugleich abgespielt und Klänge mit Effekten versehen werden. Die räumliche Anordnung von Klangquellen wird ebenso unterstützt[10]. Das DirectX 9.0 SDK enthält eine PIA für DirectSound mit dem Namen „Microsoft.DirectX.DirectSound.dll“. Die Klassen von DirectSound befinden sich im Namensraum Microsoft.DirectX.DirectSound. Damit ist eine unproblematische Verwendung der Programmierschnittstelle DirectSound innerhalb von auf .NET basierenden Anwendungen möglich.

Vergleich von DirectSound 8.0 und DirectSound 9.0

Zur Illustration der Unterschiede zwischen der Verwendung von unverwaltetem DirectSound und der verwalteten Version innerhalb von .NET-basierenden Projekten betrachten wir ein einfaches Beispiel, in dem eine Wave-Datei geladen und abgespielt werden soll. Die Beschreibung der Vorgehensweise bezieht sich lediglich auf DirectSound 9.0, ist jedoch methodisch auch auf DirectSound 8.0 anwendbar.

Als Erstes wird ein Device-Objekt instanziert, das zur Konfiguration der Umgebung, dem Verwalten von Geräten und dem Erstellen von Pufferobjekten dient. Das Device-Objekt wird dazu an ein Fenster bzw. eine Fensterzugriffsnummer gebunden. Die Klasse BufferDescription dient zur Beschreibung eines Puffers, hier können Eigenschaften wie Datenformat, Lautstärke und Frequenz eines Puffers gesetzt oder abgefragt werden. Im Anschluss daran wird die Wave-Datei unter Angabe des Geräts und der Pufferbeschreibung in ein SecondaryBuffer-Objekt geladen. Bei SecondaryBuffer handelt es sich um eine von Buffer abgeleitete Klasse, über die u.a. die Wiedergabe der Audiodaten mittels der Methoden Play und Stop gesteuert werden kann. Auf eine vollständige Implementierung eines Audioplayers soll hier verzichtet werden, im Abschnitt „Ein einfacher Audioplayer“ finden sich Ausschnitte aus einer auf AudioVideoPlayback basierenden Playeranwendung, die einer möglichen Lösung mittels DirectSound ähnlich ist. Code zum Aufräumen nach Verwendung der Objekte wurde ebenfalls weggelassen.

Imports Microsoft.DirectX.DirectSound
.
.
.
Dim dev As New Device()
dev.SetCooperativeLevel(Me, CooperativeLevel.Normal)
Dim bd As New BufferDescription()
bd.ControlVolume = True
Dim b As New SecondaryBuffer("C:\WINDOWS\Media\tada.wav", bd, dev)
b.Volume = -100
b.Play(0, BufferPlayFlags.Default)

Listing 1

Ist der Abspielvorgang beendet und wird das SecondaryBuffer-Objekt nicht mehr gebraucht, empfiehlt es sich, dessen Dispose-Methode aufzurufen, um vom Objekt belegte unverwaltete Ressourcen wieder freizugeben und für andere Objekte bereitzustellen. Der zum oben stehenden Beispiel äquivalente Quellcode für DirectSound 8.0 unter Verwendung der DirectX-Bibliothek für Visual Basic ist im folgenden Listing angegeben.

Imports DxVBLibA
.
.
.
Dim dx As New DirectX8()
Dim ds As DirectSound8 = dx.DirectSoundCreate("")
Dim bd As DSBUFFERDESC
ds.SetCooperativeLevel(Me.Handle.ToInt32(), CONST_DSSCLFLAGS.DSSCL_NORMAL)
bd.lFlags = CONST_DSBCAPSFLAGS.DSBCAPS_CTRLVOLUME
Dim b As DirectSoundSecondaryBuffer8 = _
    ds.CreateSoundBufferFromFile("C:\WINDOWS\Media\tada.wav", bd)
b.SetVolume(-100)
b.Play(CONST_DSBPLAYFLAGS.DSBPLAY_DEFAULT)

Listing 2

Das Objektmodell von Managed DirectX 9.0 wirkt aufgeräumter als jenes von DirectX 8.0. Klassen- und Konstantennamen wurden den Benennungskonventionen für .NET-Komponenten angepasst. Während es sich beim Typ DSBUFFERDESC um eine Struktur, also einen Werttyp handelte, ist BufferDescription eine Klasse. Anstelle von Set- und Get-Methoden zum Zugriff auf Objektattribute werden Eigenschaften verwendet, die eine intuitivere Form des Zugriffs erlauben. Unklar bleibt, warum die Methode Play der Klasse SecondaryBuffer über einen zusätzlichen, nicht-optionalen Parameter zur Angabe der Priorität des Klangs verfügt; hier hätte evtl. das Bereitstellen einer überladenen Version der Methode für besser lesbaren Code sorgen können.

Anwenden von Effekten auf Puffer

DirectSound stellt mehrere vordefinierte Standardeffekte wie bspw. Echo, Chor und Gurgeln zur Verfügung. Weiters besteht die Möglichkeit, selbst Effekte für die Verwendung mit der High-Level-Programmierschnittstelle DirectSound zu implementieren. Effekte liegen in Form von DMOs (DirectX Media Objects)[8] vor. Dabei handelt es sich um Low-Level-COM-Objekte, die Daten transformieren und die beiden COM-Schnittstellen IMediaObject und IMediaObjectInPlace implementieren. Das Erstellen von DMOs ist mit verwaltetem Code, also mittels einer der .NET-Programmiersprachen, zwar theoretisch möglich; in der Praxis wird stattdessen dazu üblicherweise auf unverwaltetes C++ zurückgegriffen. .NET-Bibliotheken können mittels eines CCW von COM-Anwendungen aus angesprochen werden. Jedoch gewährt die CLR aufgrund ihres Ausführungsmodells nicht ausreichende Sicherheiten für das bei DMOs erforderliche Zeitverhalten. .NET-Anwendungen können jedoch problemlos selbst mit z.B. C++ erstellte DMOs innerhalb von DirectSound benutzen.

Folgendes Listing zeigt, wie auf ein SecondaryBuffer-Objekt Echo- und Gurgeleffekte angewendet werden können. Zu diesem Zweck müssen in der später zur Erstellung des Puffers verwendeten Pufferbeschreibung über deren Eigenschaft ControlEffects Effekte aktiviert werden. Anschließend wird ein Array von EffectDescription-Objekten mit Beschreibungen der anzuwendenden Effekte gefüllt und die Effekte über die Methode SetEffects des SecondaryBuffer-Objekts dem Puffer zugewiesen. Die Klasse DSoundHelper stellt GUIDs der COM-Klassen, welche die vordefinierten Effekte implementieren, bereit.

Dim bd As New BufferDescription()
bd.ControlEffects = True
Dim b As New SecondaryBuffer("C:\WINDOWS\Media\tada.wav", bd, dev)
Dim effects(1) As EffectDescription
effects(0) = New EffectDescription()
effects(0).GuidEffectClass = DSoundHelper.StandardEchoGuid
effects(1) = New EffectDescription()
effects(1).GuidEffectClass = DSoundHelper.StandardGargleGuid
b.SetEffects(effects)

Listing 3

Mischen von Klängen

Wenngleich das Implementieren eigener Effekte in DirectSound nicht mit reinem verwaltetem Code praktikabel möglich ist, können mit reinem verwaltetem Code mit vertretbarem Aufwand einfach Klänge zu einem neuen „Musikstück“ in Form eines Audiodatenstroms gemischt werden. Die Vorgehensweise demonstriert Ianier Munoz in seinem Artikel „Building a Drum Machine with Direct-Sound“[25]. In diesem Beispiel wird aus mehreren Wave-Dateien basierend auf Benutzereingaben ein neuer Wave-Datenstrom erzeugt und abgespielt. Die Arbeit mit Speicheradressen erfordert, dass der Anwendung Rechte zur Ausführung unverwalteten Codes zu gewährt werden; derartige Rechte benötigt allerdings jede verwaltete Anwendung, die DirectShow benutzt.

DirectMusic  

Die Programmierschnittstelle von DirectMusic wurde in DirectX 9 nicht signifikant verändert[20]. DirectMusic bietet Unterstützung für Wiedergabe und Aufnahme von Klängen innerhalb von mit C oder C++ entwickelten Anwendungen, es besteht keine direkte Unterstützung für die Verwendung innerhalb von .NET-basierenden Anwendungen[19]. Eine Möglichkeit, DirectMusic gemeinsam mit verwaltetem Code zu nutzen, stellen die Managed Extensions for C++ dar, d.h., der von DirectMusic Gebrauch machende Code wird in unverwaltetem C++ implementiert und die Klassen über die Managed Extensions for C++ mit einer verwalteten Schnittstelle versehen, die es ermöglicht, die Klassen innerhalb von .NET-basierenden Anwendungen zu nutzen. Ggf. ist es ausreichend, die Programmierschnittstelle DirectMusic 8 mit der Bibliothek „DirectX 8 for Visual Basic Type Library“ über COM Interop zu verwenden. Für die aktuelle Version 9.0 von DirectMusic liegt keine entsprechende Typbibliothek vor.

Wiedergeben von Audiodaten im MIDI-Format

DirectMusic unterstützt das MIDI-Format und Downloadable Sounds (DLS). Während bei MIDI Samples für die einzelnen Instrumente vordefiniert auf der Hardware vorliegen, können Samples bei DLS zur Laufzeit generiert werden. Auf Basis dieser Samples wird später im Zuge der Wavetable-Synthese der Klang entsprechend den MIDI-Noten generiert[22].

Betrachten wir als Beispiel das Abspielen einer MIDI-Datei bzw. MIDI-Sequenz mit der „DirectX 8 for Visual Basic Type Library“. Anders als das Starten (Methode PlaySegmentEx) und Beenden (Methode StopEx) der Wiedergabe ist die Implementierung des Anhaltens der Wiedergabe nicht mittels eines einzigen Methodenaufrufs zu bewerkstelligen. Stattdessen muss vor dem Anhalten die aktuelle Wiedergabeposition gesichert und daraus der Startabstand für das Fortsetzen der Wiedergabe berechnet werden. Zu diesem Zweck bietet sich die in [23] vorgestellte Funktion GetTimeOffset an, die zu Demonstrationszwecken in die Programmiersprache Visual Basic .NET umgewandelt wurde.

Imports DxVBLibA
.
.
.
Private m_DirectX As New DirectX8()
Private m_Segment As DirectMusicSegment8
Private m_Performance As DirectMusicPerformance8
Private m_SegmentState As DirectMusicSegmentState8
Private m_Offset As Integer

Private Sub LoadButton_Click(...) Handles LoadButton.Click
    m_Performance = m_DirectX.DirectMusicPerformanceCreate()
    Dim ap As DMUS_AUDIOPARAMS
    m_Performance.InitAudio(
        Me.Handle.ToInt32(), _
        CONST_DMUS_AUDIO.DMUS_AUDIOF_ALL, _
        ap, _
        Nothing, _
        CONST_DMUSIC_STANDARD_AUDIO_PATH.DMUS_APATH_DYNAMIC_STEREO, _
        128 _
    )

    ' Automatisches Herunterladen von Instrumenten aktivieren.
    m_Performance.SetMasterAutoDownload(True)

    m_Performance.AddNotificationType( _
        CONST_DMUS_NOTIFICATION_TYPE.DMUS_NOTIFY_ON_SEGMENT _
    )
    Dim Loader As DirectMusicLoader8 = m_DirectX.DirectMusicLoaderCreate()
    m_Segment = Loader.LoadSegment("C:\WINDOWS\Media\flourish.mid")
End Sub

Public Sub PauseButton_Click(...) Handles PauseButton.Click
    m_Offset = _
        GetTimeOffset( _
            m_Performance.GetMusicTime, _
            m_SegmentState.GetStartTime(), _
            m_SegmentState.GetStartPoint(), _
            m_Segment.GetLoopPointStart(), _
            m_Segment.GetLoopPointEnd(), _
            m_Segment.GetLength, _
            m_Segment.GetRepeats() _
        )
    Performance.StopEx(m_Segment, 0, 0)
End Sub

Private Sub StartButton_Click(...) Handles StartButton.Click
    m_Segment.SetStartPoint(0)
    m_SegmentState = _
        m_Performance.PlaySegmentEx( _
            m_Segment, _
            CONST_DMUS_SEGF_FLAGS.DMUS_SEGF_DEFAULT, _
            0 _
        )
End Sub

Private Sub StopButton_Click(...) Handles StopButton.Click
    m_Performance.StopEx(m_Segment, 0, 0)
End Sub

' Convert 'mtNow' from absolute time to an offset from when the segment
' started playing.
Private Function GetTimeOffset( _
    ByVal mtNow As Integer, _
    ByVal mtStartTime As Integer, _
    ByVal mtStartPoint As Integer, _
    ByVal mtLoopStart As Integer, _
    ByVal mtLoopEnd As Integer, _
    ByVal mtLength As Integer, _
    ByVal dwLoopRepeats As Integer _
) As Integer
    Dim llOffset As Long = mtNow - (mtStartTime - mtStartPoint)

    ' If 'mtLoopEnd' is not zero, set 'llLoopEnd' to 'mtLoopEnd';
    ' otherwise use the segment length.
    Dim llLoopEnd As Long
    If mtLoopEnd <> 0 Then
        llLoopEnd = mtLoopEnd
    Else
        llLoopEnd = mtLength
    End If

    Dim llLoopStart As Long = mtLoopStart

    ' Adjust offset to take looping into account.
    Const DMUS_SEG_REPEAT_INFINITE As Int32 = -1
    If _
        dwLoopRepeats <> 0 AndAlso _
        llLoopStart < llLoopEnd AndAlso _
        llLoopEnd > mtStartPoint _
    Then
        If _
            dwLoopRepeats <> DMUS_SEG_REPEAT_INFINITE AndAlso _
            llOffset > (llLoopStart + (llLoopEnd - llLoopStart) * dwLoopRepeats) _
        Then
            llOffset -= (llLoopEnd - llLoopStart) * dwLoopRepeats
        ElseIf llOffset > llLoopStart Then
            llOffset = _
                llLoopStart + _
                (llOffset - llLoopStart) Mod (llLoopEnd - llLoopStart)
        End If
    End If

    llOffset = Math.Min(llOffset, Integer.MaxValue)
    Return CInt(llOffset)
End Function

Listing 4

Um benachrichtigt zu werden, wenn bei der Wiedergabe das Ende des Segments erreicht wurde, kann über die Methode CreateEvent des DirectX8-Objekts ein Ereignis erzeugt werden. Dieses Ereignis wird anschließend mit der Methode SetNotificationHandle eines DirectMusicPerformance8-Objekts an dieses gebunden. Eine Ereignisbehandlungsprozedur für das Ereignis DirectXEvent8.DXCallback kann durch Implementieren der Schnittstelle DirectXEvent8 hinzugefügt werden. An den Typ des Ereignisses gelangt man theoretisch mittels der Methode GetNotificationPMSG des DirectMusicPerformance8-Objekts. In einem Praxistest schlug diese Methode jedoch fehl, was vermutlich auf fehlerhafte Wrapperassemblies bzw. Unzulänglichkeiten im Marshaller zurückzuführen ist.

Wenngleich theoretisch von DirectMusic in .NET-basierenden Anwendungen über COM Interop Gebrauch gemacht werden kann, handelt es sich dabei um eine nicht unterstützte Vorgehensweise, bei der nicht sichergestellt wird, dass ggf. auftretende Fehler behoben werden[29]. Hinzu kommt, dass einige Methoden nicht die in .NET vorgesehenen Typen benutzen und nicht alle erforderlichen Konstanten über die Bibliothek bereitgestellt werden.

AudioVideoPlayback  

Für einfaches Abspielen von Audio und Video enthält DirectX die Programmierschnittstelle AudioVideoPlayback[18], die zwar einfacher zu verwenden ist als DirectSound, aber auch weit weniger Möglichkeiten bietet. AudioVideoPlayback stellt verwaltete Schnittstellen für die Verwendung in .NET-basierenden Anwendungen in der DLL „Microsoft.DirectX.AudioVideoPlayback.dll“ bereit, die Klassen befinden sich im Namensraum Microsoft.DirectX.AudioVideoPlayback. Hauptbestandteile sind die beiden Klassen Audio und Video. AudioVideoPlayback ist jedoch nicht unumstritten, der Artikel „Problems in the AudioVideoPlayback namespace of managed DirectX9“ von Christian Graus[1] fasst einige der Probleme dieser Assembly zusammen.

Ein einfacher Audioplayer

Betrachten wir im Folgenden ein einfaches Beispiel für die Wiedergabe einer frei aus dem Dateisystem zu wählenden Audiodatei. Die Klasse Audio unterstützt mehrere Audioformate, darunter das Wave-Format, Dateien im MP3-Format und MIDI-Daten. Das Beispiel erlaubt dem Benutzer, die Wiedergabe zu starten, anzuhalten und zu stoppen, die aktuelle Wiedergabeposition zu verändern und Lautstärke und Balance einzustellen. Zusätzlich werden Fortschritt und Status der Wiedergabe dargestellt. Es wird davon ausgegangen, dass sich auf einem Windows Forms-Formular entsprechende Steuerelemente befinden, die im Code verwendet werden; nicht relevanter Code zur Verwaltung der Benutzerschnittstelle wurde der Übersichtlichkeit halber weggelassen.

Das Einstellen der Balance funktioniert zwar für Dateien im Wave-Format, beim Zuweisen der Eigenschaft bei einem Audio-Objekt, das an eine Datei im MIDI-Format gebunden ist, wird manchmal eine Ausnahme des Typs Microsoft.DirectXException mit dem Fehlertext „In der Anwendung ist ein Fehler aufgetreten“ geworfen. Die Klasse Audio bietet allerdings keine Möglichkeit dazu, das Auftreten dieser Ausnahme zu vermeiden. Werte für die Balance reichen von -10.000 (linker Kanal bei voller Lautstärke, rechter Kanal vollkommen stumm) bis 10.000 (wie vor, nur rechts und links umgekehrt). Lautstärkenangaben besitzen einen Wertebereich von -10.000 (vollkommen stumm) bis 0 (maximale Lautstärke). Da Instanzen der Klasse Audio unverwaltete Ressourcen belegen, empfiehlt es sich, deren Dispose-Methode aufzurufen, wenn sie nicht mehr benötigt werden, damit diese Ressourcen deterministisch freigegeben werden.

Imports Microsoft.DirectX.AudioVideoPlayback
.
.
.
Private WithEvents m_Audio As Audio

Private Sub Form1_Load(...) Handles MyBase.Load
    With Me.BalanceTrackBar
        .Minimum = -10000
        .Maximum = 10000
        .Value = 0
    End With
    With Me.VolumeTrackBar
        .Maximum = 10000
        .Minimum = 0
        .LargeChange = 1000
        .SmallChange = 100
        .TickFrequency = 1000
        .Value = .Maximum
    End With
End Sub

Private Sub m_Audio_Ending(...) Handles m_Audio.Ending
    Me.ProgressTimer.Enabled = False
    Me.StatusLabel.Text = "Beendet."
End Sub

Private Sub m_Audio_Pausing(...) Handles m_Audio.Pausing
    Me.ProgressTimer.Enabled = False
    Me.StatusLabel.Text = "Angehalten."
End Sub

Private Sub m_Audio_Starting(...) Handles m_Audio.Starting
    Me.ProgressTimer.Enabled = True
    Me.StatusLabel.Text = "Gestartet."
End Sub

Private Sub m_Audio_Stopping(...) Handles m_Audio.Stopping
    Me.ProgressTimer.Enabled = False
    Me.StatusLabel.Text = "Gestoppt."
End Sub

Private Sub PlayButton_Click(...) Handles PlayButton.Click
    Me.ProgressTimer.Enabled = True
    m_Audio.Play()
End Sub

Private Sub PauseButton_Click(...) Handles PauseButton.Click
    m_Audio.Pause()
End Sub

Private Sub StopButton_Click(...) Handles StopButton.Click
    m_Audio.Stop()
End Sub

Private Sub ProgressTimer_Tick(...) Handles ProgressTimer.Tick
    Me.SeekTrackBar.Value = CInt(m_Audio.CurrentPosition)
End Sub

Private Sub SeekTrackBar_Scroll(...) Handles SeekTrackBar.Scroll
    Dim SourceControl As TrackBar = DirectCast(sender, TrackBar)
    Me.ToolTip1.SetToolTip(SourceControl, CStr(SourceControl.Value) & " s")
    m_Audio.CurrentPosition = SourceControl.Value
End Sub

Private Sub BalanceTrackBar_Scroll(...) Handles BalanceTrackBar.Scroll
    Dim SourceControl As TrackBar = DirectCast(sender, TrackBar)
    Try
        m_Audio.Balance = SourceControl.Value
    Catch
    End Try
End Sub

Private Sub VolumeTrackBar_Scroll(...) Handles VolumeTrackBar.Scroll
    Dim SourceControl As TrackBar = DirectCast(sender, TrackBar)
    m_Audio.Volume = -SourceControl.Maximum + SourceControl.Value
End Sub

Private Sub LoadButton_Click(...) Handles LoadButton.Click
    If Me.OpenFileDialog1.ShowDialog() <> DialogResult.OK Then
        Return
    End If
    Dim FileName As String = Me.OpenFileDialog1.FileName
    Me.FileNameLabel.Text = FileName
    Me.StatusLabel.Text = "Bereit."
    If Not m_Audio Is Nothing Then
        m_Audio.Dispose()
    End If

    ' Laden der ausgewählten Audiodatei.
    m_Audio = New Audio(FileName)
    With Me.SeekTrackBar
        .Minimum = 0
        .Maximum = CInt(m_Audio.Duration)
        .LargeChange = .Maximum \ 10
        .SmallChange = .Maximum \ 100
    End With
    Try
        m_Audio.Balance = Me.BalanceTrackBar.Value
    Catch
    End Try
End Sub

Listing 5

Im Beispiel nicht gezeigt wurde das Laden eines Audio-Objekts auf Basis eines URLs über die Methode FromUrl. Der Einfachheit halber wurde auch darauf verzichtet, die Suchfähigkeiten des Audio-Objekts in der Benutzerschnittstelle zu berücksichtigen, welche über die Eigenschaft SeekingCaps zugänglich gemacht werden.

Wiedergabe von Video

Die Klasse Video ist ausgerichtet für das Darstellen von Videos innerhalb von Anwendungen, die Direct3D benutzen. Die Steuerung des Abspielvorgangs verläuft ähnlich wie beim Audio-Objekt, allerdings wird, anders als etwa beim Windows Media Player-Steuerelement (siehe Abschnitt „Windows Media Player“), keine grafische Oberfläche zur Darstellung des Videos bereitgestellt. Stattdessen werden für die einzelnen Frames Direct3D-Texturen generiert. Liegt ein neuer Frame für die Darstellung bereit, löst das Video-Objekt das Ereignis TextureReadyToRender aus, bei dem im Parameter e der Ereignisbehandlungsroutine ein TextureRenderEventArgs-Objekt übergeben wird, dessen Eigenschaft Texture einen Verweis auf die Textur für das darzustellenden Bild enthält. Wird das Objekt an ein Steuerelement gebunden, erfolgt die Darstellung des Videos in diesem Steuerelement.

Windows Media  

Windows Media[5] stellt Funktionalität zur Aufnahme, Bearbeitung und Wiedergabe von Medieninhalten bereit. Dabei werden sowohl Windows Media-eigene Datenformate als auch Audio- und Videoformate anderer Hersteller unterstützt. Windows Media arbeitet zusammen mit DirectShow und anderen Medientechnologien von Microsoft. Im Folgenden soll betrachtet werden, wie weit Teiltechnologien aus Windows Media in .NET-basierten Anwendungen genutzt werden können und inwieweit verwaltete Schnittstellen für deren Nutzung vorhanden sind.

Windows Media Format

Das Windows Media Format 9.5 SDK[32] stellt eine Programmierschnittstelle zur Verarbeitung von Mediendateien bereit, die in der Dateistruktur des Advanced Systems Format (ASF) vorliegen. ASF ist ein Containerformat für verschiedenste streamingfähige Mediendaten. Das SDK stellt zudem Codecs für Audio- und Videodaten und die Möglichkeit zum Bearbeiten von Metadaten bereit[14].

Für die Benutzung der Funktionalität des Media Format SDK stehen keine verwalteten Programmierschnittstellen bereit, die Nutzung der Programmierschnittstelle in verwalteten Anwendungen wird ausgeschlossen: „To develop an application by using the Windows Media Format SDK, you must use Microsoft® Visual C++® version 6.0 or later. The only programming languages appropriate for development are C++ and C“[15]. Dennoch ist theoretisch eine zum Teil verwaltete Lösung mittels der Managed Extensions for C++ vorstellbar, mit denen verwalteter mit unverwaltetem Code gemischt werden kann.

Windows Media Encoder

Das Windows Media Encoder 9 Series SDK[16] stellt eine Programmierschnittstelle für den Windows Media Encoder bereit. Mit dem Windows Media Encoder können Liveinhalte gesendet, große Mengen an Mediendaten per Stapelverarbeitung verarbeitet, eigene Schnittstellen zur Steuerung des Windows Media Encoders implementiert und Windows Media-Anwendungen ferngewartet werden.

Die Programmierschnittstelle des Windows Media Encoders kann innerhalb von .NET-basierenden Anwendungen über COM Interop genutzt werden; bei Verwendung von Visual Studio .NET als Entwicklungsumgebung reicht das Aufnehmen einer COM-Referenz zur Datei „wmenc.exe“. Es werden keine PIAs bereitgestellt, jedoch enthält das SDK Beispiele für die Verwendung der Komponenten des Windows Media Encoders in verwalteten Anwendungen. Um das Windows Media Encoder 9 Series SDK [33] benutzen zu können, muss die getrennt verfügbare Windows Media Encoder 9 Series-Codiereranwendung[34] auf dem System installiert sein.

Codieren von Audio- und Videodaten

Der eigentliche Codierungsvorgang wird über ein WMEncoder-Objekt gesteuert und läuft in einem eigenen Prozess ab. Wird der Codierer in einer Anwendung benutzt, die eine eigene Benutzerschnittstelle bereitstellt, muss das WMEncoder-Objekt über die Schnittstelle WMEncoderApp instanziert werden. Ein WMEncoderApp bietet über die Eigenschaft Encoder Zugriff auf ein WMEncoder-Objekt und stellt Eigenschaften zur Manipulation der Benutzerschnittstelle des Codierers bereit. Der Status des Codierers und den Fortschritt der Verarbeitung kann man entweder über Abfrage der Eigenschaften RunState und Statistics während des Codierungsvorgangs oder durch Behandeln des Ereignisses OnStateChange des WMEncoder-Objekts ermitteln, um ihn dann z.B. in einer Statusanzeige einer eigenen Benutzerschnittstelle anzuzeigen.

Profile dienen dazu, den Medientyp des codierten Ausgabestroms und die Bandbreite des Zielpublikums zu beschreiben und enthalten Information darüber, ob der Ausgabestrom mit unterschiedlichen Bitraten codiert werden kann. Daten eines Profils können in einer Profildatei persistent gemacht werden. Innerhalb von Anwendungen, die den Windows Media Encoder nutzen, werden sie durch Objekte des Typs WMEncProfile2 repräsentiert. Dieser Typ bietet auch die Möglichkeit, das Profil über die Methode SaveToFile in eine Datei zu speichern und mit der Methode LoadFromFile ein bestehendes Profil zu laden. Verschiedene Profile können in einer Auflistung des Typs IWMEncProfileCollection abgelegt werden, die Objekte des Typs IWMEncProfile aufnimmt. Der Typ WMEncProfile2 implementiert diese Schnittstelle.

Die zu codierenden Daten werden dem Codierer in einer IWMSourceGroupCollection in dessen Eigenschaft SourceGroupCollection übergeben. Dieser Auflistung können bspw. Audio- (IWMEncAudioSource) und Videoquellen (IWMEncVideoSource2) hinzugefügt werden. Die Quelldaten können für die Codierung angepasst werden. So besteht etwa bei Videoquellen die Möglichkeit, mittels der Eigenschaften Cropping* den zu übernehmenden Bereich auszuwählen und die Daten der Quelle durch Setzen ihrer Eigenschaft Repeat zu wiederholen.

Das folgende Beispiel zeigt, wie mit Hilfe des Windows Media Encoders eine bestehende Videodatei unter Anwendung eines vordefinierten Profils codiert werden kann. Dabei werden Statusänderungen durch Behandeln des Ereignisses OnStatusChange des Codierers ermittelt und in einem Label-Steuerelement ausgegeben. Außerdem wird eine Fortschrittsanzeige angezeigt, über die der Fortschritt des Codierungsvorgangs einsehbar ist. Zur Berechnung des Fortschritts wird das Verhältnis zwischen Gesamtdauer der zu codierenden Daten und der Dauer der bereits codierten Daten mittels einer Timer-Komponente in regelmäßigen zeitlichen Intervallen bestimmt. Die Gesamtdauer ist das Maximum der Längen von Audio- und Videoquelle. Alle Zeitangaben werden in Sekunden umgerechnet. Die im Code verwendete Funktion MakeValid stellt sicher, dass ein Wert zwischen zwei übergebenen Grenzen zu liegen kommt. Es wird vorausgesetzt, dass sich auf einem Windows Forms-Formular eine Schaltfläche mit Namen StartButton, ein Label-Steuerelement StatusLabel und ein ProgressBar-Steuerelement EncodingProgressBar befinden.

Imports WMEncoderLib
.
.
.

' Erstellen des Codierers.
Private WithEvents m_Encoder As New WMEncoder()

' Gesamtdauer der zu codierenden Daten.
Private m_TotalDuration As Double

Private Sub StartButton_Click(...) Handles StartButton.Click

    ' Quellengruppe der Gruppenauflistung hinzufügen.
    Dim SrcGrp As IWMEncSourceGroup2 = _
        DirectCast( _
            m_Encoder.SourceGroupCollection.Add("SG_1"), _
            IWMEncSourceGroup2 _
        )

    ' Hinzufügen einer Video- und einer Audioquelle.
    Dim SrcVid As IWMEncVideoSource2 = _
        DirectCast( _
            SrcGrp.AddSource(WMENC_SOURCE_TYPE.WMENC_VIDEO), _
            IWMEncVideoSource2 _
        )
    SrcVid.SetInput("C:\WINDOWS\clock.avi")
    Dim SrcAud As IWMEncAudioSource = _
        DirectCast( _
            SrcGrp.AddSource(WMENC_SOURCE_TYPE.WMENC_AUDIO), _
            IWMEncAudioSource _
        )
    SrcAud.SetInput("C:\WINDOWS\Media\Ee_rev.wav")

    ' Profil für Audio/Video anhand des Namens wählen ("scmeda.prx").
    Const ProfileName As String = _
        "Bildschirmvideo/Audio mit mittlerer Bitrate (CBR)"
    For Each Profile As IWMEncProfile In m_Encoder.ProfileCollection
        If Profile.Name = ProfileName Then
            SrcGrp.Profile = Profile
            Exit For
        End If
    Next Profile

    ' Eigenschaften des Medienobjekts setzen.
    With m_Encoder.DisplayInfo
        .Author = "John Doe"
        .Copyright = _
            "Copyright © 2005 John Doe Media Corporation. " & _
            "All rights reserved."
        .Description = "An animated clock with sound"
        .Rating = "Great video."
        .Title = "The Animated Clock"
    End With

    ' Ausgabedateinamen angeben.
    m_Encoder.File.LocalFileName = "C:\test.wmv"

    ' Videoframes um zwei Pixel auf jeder Seite beschneiden.
    With SrcVid
        .CroppingBottomMargin = 2
        .CroppingTopMargin = 2
        .CroppingLeftMargin = 2
        .CroppingRightMargin = 2
    End With

    ' Encoder vorbereiten. Dies muss vor der Berechnung Längen der
    ' Datenquellen geschehen.
    m_Encoder.PrepareToEncode(True)

    m_TotalDuration = _
        Math.Max(SrcVid.Duration, SrcAud.Duration) / 1000

    ' Start the encoding process.
    m_Encoder.Start()
End Sub

Private Sub Encoder_OnStateChange( _
    ByVal enumState As WMENC_ENCODER_STATE _
) Handles m_Encoder.OnStateChange
    Dim s As String
    Select Case enumState
        Case WMENC_ENCODER_STATE.WMENC_ENCODER_END_PREPROCESS
            s = "Vorverarbeitung beendet."
        Case WMENC_ENCODER_STATE.WMENC_ENCODER_PAUSED
            s = "Unterbrochen."
        Case WMENC_ENCODER_STATE.WMENC_ENCODER_PAUSING
            s = "Unterbrechen..."
        Case WMENC_ENCODER_STATE.WMENC_ENCODER_RUNNING
            s = "Läuft..."
        Case WMENC_ENCODER_STATE.WMENC_ENCODER_STARTING
            s = "Startet..."
            Me.EncodingProgressBar.Value = 0
            Me.ProgressTimer.Enabled = True
        Case WMENC_ENCODER_STATE.WMENC_ENCODER_STOPPED
            s = "Beendet."
            Me.EncodingProgressBar.Value = 100
            Me.ProgressTimer.Enabled = False
        Case WMENC_ENCODER_STATE.WMENC_ENCODER_STOPPING
            s = "Beenden..."
    End Select
    Me.StatusLabel.Text = s
End Sub

Private Sub ProgressTimer_Tick(...) Handles ProgressTimer.Tick
    If m_Encoder.RunState = WMENC_ENCODER_STATE.WMENC_ENCODER_RUNNING Then
        Dim FileStats As IWMEncFileArchiveStats = _
            DirectCast( _
                m_Encoder.Statistics.FileArchiveStats, _
                IWMEncFileArchiveStats _
            )
        Me.EncodingProgressBar.Value = _
            CInt( _
                MakeValid( _
                     FileStats.FileDuration * 10 / m_TotalDuration * 100, _
                     0, _
                     100 _
                ) _
            )
    End If
End Sub

Listing 6

Das oben stehende Beispiel verwendet bereits vollständig vorliegende Mediendaten und schreibt das Ergebnis des Codierungsvorgangs in eine Datei. Die Möglichkeiten des Windows Media Encoders reichen jedoch noch weiter, so könnte unter Verwendung eines entsprechenden Profils eine Kamera als Datenquelle zum Einsatz gelangen und die Ausgabe live in einen Datenstrom geschrieben werden.

Videodaten können mit dem Windows Media Encoder mit Wasserzeichen versehen werden, um bspw. Informationen zu Copyright und Herkunft zu integrieren. Wasserzeicheneffekte liegen in Form von DMOs vor, die nicht alleine mit verwaltetem Code erstellt werden können. Der Windows Media Encoder ist aber bei Weitem nicht die einzige Technologie zur Medienverarbeitung aus dem Hause Microsoft, die von DMOs Gebraucht macht, weshalb vollständig verwaltete Lösungen nur dann möglich sind, wenn DMOs auch mit verwaltetem Code erstellt bzw. über verwaltete Schnittstellen angesprochen werden können.

Windows Media Player

Beim Windows Media Player handelt es sich um eine Anwendung zur Wiedergabe und Verwaltung von Mediendateien. Zusätzlich zur eigenständigen Anwendung Windows Media Player existiert ein ActiveX-Steuerelement, welches es erlaubt, die Funktionsmerkmale des Windows Media Players in eigenen Anwendungen zu nutzen, sei es zur Wiedergabe von Audio- und Videodaten oder zur Medienverwaltung. Microsoft selbst macht in Internet Explorer, dem Office-Paket und anderen Anwendungen Gebrauch von dieser Komponente.

Das Windows Media Player 10 SDK[11] stellt zwar keine verwalteten Schnittstellen für die Verwendung der genannten Komponenten innerhalb von .NET-Anwendungen bereit, jedoch werden in [12] Anwendungen, die auf dem .NET Framework basieren, explizit als Gastumgebungen für das Windows Media Player-Steuerelement angeführt. Im Windows Media Player 9 SDK war eine PIA mit dem Namen „WMPPIA.DLL“ enthalten, die in Version 10 nicht mehr unterstützt wird[30]. Damit ist eine Nutzung des Windows Media Players innerhalb von .NET-basierten Anwendungen nur über COM Interop möglich. In der Entwicklungsumgebung Visual Studio .NET reicht dazu das Aufnehmen eines Verweises auf die „WMP.DLL“ aus[13], die Interoperabilitätsassemblies werden automatisch erstellt.

Folgendes Listing zeigt den zum Laden und Abspielen mehrer Mediendateien erforderlichen Quellcode. Dabei wird eine Wiedergabeliste angelegt und dieser Medien hinzugefügt. Zudem wird die Benutzerschnittstelle des Windows Media Players auf den Bereich zur Wiedergabe des Mediums reduziert und es werden eigene Steuerelemente zur Kontrolle des Abspielvorgangs bereitgestellt. Im Beispiel wird davon ausgegangen, dass sich ein Windows Media Player-Steuerelement mit dem Namen MediaPlayer und drei Schaltflächen mit den Namen PlayButton, PauseButton und StopButton auf einem Windows Forms-Formular befinden.

Imports WMPLib
.
.
.
Private Sub Form_Load(...) Handles MyBase.Load

    ' Erstellen einer Wiedergabeliste.
    Dim p As IWMPPlaylist = .newPlaylist("My Playlist", vbNullString)
    p.appendItem(.newMedia("C:\WINDOWS\clock.avi"))
    p.appendItem(.newMedia("C:\WINDOWS\Media\flourish.mid"))
    p.appendItem(.newMedia("C:\WINDOWS\Media\town.mid"))
    .currentPlaylist = p

    ' Benutzerschnittstelle auf Wiedergabefläche reduzieren.
    .uiMode = "none"

    ' Abspielen stoppen.
    .Ctlcontrols.Stop()
End With

Private Sub PlayButton_Click(...) Handles PlayButton.Click
    Me.MediaPlayer.Ctlcontrols.play()
End Sub

Private Sub PauseButton_Click(...) Handles PauseButton.Click
    Me.MediaPlayer.Ctlcontrols.pause()
End Sub

Private Sub StopButton_Click(...) Handles StopButton.Click
    Me.MediaPlayer.Ctlcontrols.Stop()
End Sub

Private Sub MediaPlayer_StatusChange(...) Handles MediaPlayer.StatusChange
    Select Case Me.MediaPlayer.playState
        Case WMPPlayState.wmppsPaused
            Me.PlayButton.Enabled = True
            Me.PauseButton.Enabled = False
            Me.StopButton.Enabled = True
        Case WMPPlayState.wmppsStopped, WMPPlayState.wmppsMediaEnded
            Me.PlayButton.Enabled = True
            Me.PauseButton.Enabled = False
            Me.StopButton.Enabled = False
        Case WMPPlayState.wmppsPlaying
            Me.PlayButton.Enabled = False
            Me.PauseButton.Enabled = True
            Me.StopButton.Enabled = True
    End Select
End Sub

Listing 7

Das Windows Media Player-Steuerelement bietet Kontrolle über die Darstellungsgröße und -art wiedergegebener Videodaten, so kann die Wiedergabe bspw. durch Setzen der Eigenschaft fullScreen im Vollbildmodus erfolgen und über die Eigenschaft stretchToFit die Größe des Players jener des abzuspielenden Videos angeglichen werden. Über die Eigenschaft network können Informationen wie Protokoll, Bandbreite, Qualität und Bildfrequenz einer bestehenden Netzwerkverbindung ermittelt werden. Zugriff auf die Medienbibliothek, Wiedergabelisten und Metadaten von Medienobjekten sind ebenfalls möglich.

Schlusswort  

Microsoft stellt mit den in DirectX enthaltenen Medientechnologien und Windows Media ein umfassendes Repertoire an Schnittstellen zur Entwicklung von verteilten Multimediaanwendungen bereit. Wenngleich der Einsatz dieser Technologien in mit C++ entwickelten COM-Anwendungen meist kein Problem darstellt, sind die für .NET-basierende Anwendungen verfügbaren Wrapper unvollständig, sodass eine homogene, in .NET implementierte Lösung nicht möglich ist und von Mechanismen zur Interoperabilität zwischen COM und .NET Gebrauch gemacht werden muss. Dennoch geht mit dem zunehmenden Bereitstellen von PIAs die Entwicklung hin zu einer zunehmenden Adaptierung bestehender, häufig auf COM basierender Technologien für die native Verwendung innerhalb von .NET-basierenden Anwendungen.

Literaturverzeichnis  

Die Ausarbeitung stützt sich vorwiegend auf die vom Hersteller bereitgestellte Dokumentation zu den beschriebenen Programmierschnittstellen:

[1] Geraint Davies Consulting Ltd: „ActiveMovie and DirectShow“, http://www.gdcl.co.uk/names.htm, Stand vom 3. April 2005.
[2] Graus, C.: „Problems in the AudioVideoPlayback namespace of managed DirectX9“, http://www.codeproject.com/cs/media/DirectX9_media_playback.asp, 13. September 2004.
[3] Microsoft Corporation: „.NET Framework Developer’s Guide – Advanced COM Interop“, http://msdn.microsoft.com/library/en-us/cpguide/html/cpconadvancedcominterop.asp, Version 1.1 der Dokumentation zum .NET Framework.
[4] Microsoft Corporation: „.NET Framework Developer’s Guide – Consuming Unmanaged DLL Functions“, http://msdn.microsoft.com/library/en-us/cpguide/html/cpconconsumingunmanageddllfunctions.asp, Version 1.1 der Dokumentation zum .NET Framework.
[5] Microsoft Corporation: „Windows Media – Audio and Video“, http://msdn.microsoft.com/library/en-us/dnanchor/html/audiovideo.asp, Stand vom 20. März 2005.
[6] Microsoft Corporation: „DirectX“, http://msdn.microsoft.com/library/en-us/dnanchor/html/anch_DirectX.asp, Stand vom 20. März 2005.
[7] Microsoft Corporation: „Microsoft DirectX 9.0 SDK Update (October 2004) – Introduction to DirectShow“, http://msdn.microsoft.com/library/en-us/directshow/htm/introductiontodirectshow.asp, Stand vom 5. April 2005.
[8] Microsoft Corporation: „Windows Media – DMO Basics“, http://msdn.microsoft.com/library/en-us/wmform95/htm/dmobasics.asp, Stand vom 6. April 2005.
[9] Microsoft Corporation: „.NET Framework Developer’s Guide – COM Callable Wrapper“, http://msdn.microsoft.com/library/en-us/cpguide/html/cpconCOMCallableWrapper.asp, Stand vom 7. April 2005.
[10] Microsoft Corporation: „Microsoft DirectX 9.0 SDK Update (April 2005) – The Power of DirectSound“, http://msdn.microsoft.com/library/en-us/directx9_c/directx/htm/thepowerofdirectsound.asp, Stand vom 9. April 2005.
[11] Microsoft Corporation: „Windows Media – Windows Media Player 10 SDK“, http://msdn.microsoft.com/library/en-us/wmplay10/mmp_sdk/windowsmediaplayer10sdk.asp, Stand vom 9. April 2005.
[12] Microsoft Corporation: „Windows Media – About the Windows Media Player SDK“, http://msdn.microsoft.com/library/en-us/wmplay10/mmp_sdk/aboutthewindowsmediaplayersdk.asp, Stand vom 9. April 2005.
[13] Microsoft Corporation: „Windows Media – Using the Windows Media Player Control with Microsoft Visual Studio .NET“, http://msdn.microsoft.com/library/en-us/wmplay10/mmp_sdk/usingtheplayercontrolwithmicrosoftvisualstudionet.asp, Stand vom 10. April 2005.
[14] Microsoft Corporation: „Windows Media – About the Windows Media Format SDK“, http://msdn.microsoft.com/library/en-us/wmform95/htm/overviewwindowsmediaformatsdk.asp, Stand vom 10. April 2005.
[15] Microsoft Corporation: „Windows Media – SDK Library Files and Compiler Settings“, http://msdn.microsoft.com/library/en-us/wmform95/htm/sdklibraryfilesandcompilersettings.asp, Stand vom 11. April 2005.
[16] Microsoft Corporation: „Windows Media 9 Series – Windows Media Encoder 9 Series SDK“, http://msdn.microsoft.com/library/en-us/wmencode/htm/windowsmediaencoderautomation.asp, Stand vom 11. April 2005.
[17] Microsoft Corporation: „Windows Media – Graphics and Multimedia“, http://msdn.microsoft.com/library/en-us/dnanchor/html/graphicsmultimedia.asp, Stand vom 10. April 2005.
[18] Microsoft Corporation: „Microsoft DirectX 9.0 SDK Update (April 2005) – Audio Video Playback“, http://msdn.microsoft.com/en-us/directx9_m/directx/audiovideoplayback/audiovideoplayback.asp, Stand vom 12. April 2005.
[19] Microsoft Corporation: „Microsoft DirectX 9.0 SDK Update (Summer 2004) – DirectMusic“, http://msdn.microsoft.com/library/en-us/DMusicC/htm/directmusic.asp, Stand vom 12. April 2005.
[20] Microsoft Corporation: „Microsoft DirectX 9.0 SDK Update (Summer 2004) – What’s New in DirectMusic“, http://msdn.microsoft.com/library/en-us/DMusicC/htm/whatsnewindirectmusic.asp, Stand vom 12. April 2005.
[21] Microsoft Corporation: „Managed Extensions for C++ Concepts – Managed Extensions for C++ Programming“, http://msdn.microsoft.com/library/en-us/vcmex/html/vcconMCOverview.asp, Stand vom 14. April 2005.
[22] Microsoft Corporation: „Microsoft DirectX 8.1 (Visual Basic) – DirectSound and DirectMusic“, http://msdn.microsoft.com/archive/en-us/dx81_vb/directx_vb/htm/_dx_directsound_and_directmusic_dxaudio.asp, Stand vom 14. April 2005.
[23] Microsoft Corporation: „DirectX 9.0 C++ Archive – Pausing Segments“, http://msdn.microsoft.com/archive/en-us/directx9_c/directx/htm/pausingsegments.asp, Stand vom 15. April 2005.
[24] Microsoft Corporation: „C++/CLI Language Specification Standard“, http://msdn.microsoft.com/visualc/homepageheadlines/ecma/, Stand vom 18. April 2005.
[25] Munoz, I.: „Building a Drum Machine with DirectSound“, http://msdn.microsoft.com/library/en-us/dncodefun/html/code4fun02032004.asp, Stand vom 25. Mai 2005.
[26] Scheidegger, T.: „DirectShow.NET“, http://www.codeproject.com/cs/media/directshownet.asp, Stand vom 23. Juli 2002.
[27] Strigl, D.: „DirectShow MediaPlayer in C#“, http://www.codeproject.com/cs/media/DirectShowMediaPlayer.asp, Stand vom 17. Dezember 2003.
[28] Sun Microsystems: „Java Media Framework – Documentation 1.0 Programmers Guide“, http://java.sun.com/products/java-media/jmf/1.0/, Version 1.0.5, 1998.
[29] Taylor, P.: Beitrag eines Microsoft-Mitarbeiters aus der Newsgroup „microsoft.public.dotnet.languages.csharp“, http://groups.google.de/groups?selm=%23rlEjrVGCHA.1632%40tkmsftngp10, 21. Juni 2002.
[30] Travis, J.: Beitrag eines Microsoft-Mitarbeiters aus der Newsgroup „microsoft.public.windowsmedia.sdk“, http://groups.google.de/groups?selm=esZ3fitaEHA.3332%40TK2MSFTNGP09.phx.gbl, 15. Juli 2004.

Bibliotheken

Um das Nachvollziehen der im Artikel enthaltenen Beispielcodes zu erleichtern, enthält dieser Abschnitt eine Liste von Adressen, an denen die zum Entwickeln und Ausführen der Beispiele erforderlichen Komponenten bezogen werden können:

[31] Microsoft Corporation: „Download details: DirectX 9.0 SDK Update – (April 2005)“, http://www.microsoft.com/downloads/details.aspx?familyid=AFC15F29-D7C9-4CF7-A8D5-8AB81F14AE1B, Stand vom 6. April 2005.
[32] Microsoft Corporation: „Windows Media Downloads – Windows Media Format 9.5 SDK“, http://download.microsoft.com/download/9/F/D/9FDFB288-B4BF-45FA-959C-1CC6D909AA92/WMFormat95SDK.exe, Stand vom 10. April 2005.
[33] Microsoft Corporation: „Windows Media Downloads – Windows Media Encoder 9 Series SDK“, http://www.microsoft.com/downloads/details.aspx?familyid=000a16f5-d62b-4303-bb22-f0c0861be25b, Stand vom 10. April 2004.
[34] Microsoft Corporation: „Windows Media Encoder 9-Reihe (für Windows XP und 2000)“, http://download.microsoft.com/download/c/0/0/c00a1f8f-0ef1-490c-89e1-57a7b14d2c00/WMEncoder.exe (Informationen zum Codierer: http://www.microsoft.com/windows/windowsmedia/de/9series/encoder/), Stand vom 11. April 2005.

Ihre Meinung  

Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.