Media Foundation Transcoding mit C#

BeispielprogrammLangsam aber sicher hangele ich mich durch die MF (Media Foundation) durch. Im Gegensatz zu dem Video Player aus den letzten beiden Posts geht es hier um eine andere Aufgabe: Dem Transcoding (Konvertieren). Mein Beispielprogramm lässt dem Benutzer eine Quell- und eine Zieldatei auswählen und eine neue Auflösung für das Video einstellen. Nach Klick auf „Transcode!“ wird das Video entsprechend konvertiert und in die neue Zieldatei geschrieben. Rein von der MF-API her ist diese Aufgabe relativ einfach zu lösen, wie aber bei meinen letzten Posts lag die Schwierigkeit auch hier eher bei der Brücke zwischen C# und MF-API. Die Stolpersteine hier waren allerdings noch etwas größer und zeitaufwändiger.

Die Komponente MFTranscoder
Die wichtigste Komponente in meinem Beispielprogramm ist die Klasse MFTranscoder. Wie im folgenden Screenshot zu sehen besitzt sie lediglich eine öffentliche Methode: TranscodeAsync. Dieser werden lediglich die Parameter Quell- und Zieldatei und Videogröße übergeben. Die Methode arbeitet asynchron, der zurückgegebene Task ist fertig, sobald die Zieldatei fertig geschrieben ist – ganz wie man sich das als .Net Entwickler wünscht.

Klasse MFTranscoder

Beispiele auf Basis von C++
Als Spickzettel bei der Entwicklung habe ich einige C++-Beispielcodes verwendet. Einer davon ist das Beispiel „Transcoding“, welches man sich hier runterladen kann. Dazu auch sehr hilfreich ist das Kapitel Transcoding im Buch „Developing Microsoft Media Foundation Applications„.

Grundlegender Aufbau
Die Methode TranscodeAsync braucht eigentlich nicht viel machen. Die komplette Funktionalität wird quasi schon so von der Media Foundation bereitgestellt, dass man im Prinzip nur noch per Code konfigurieren muss. Ähnlich wie beim Video Player muss man ein Session-Objekt anlegen, danach über die MF-API entsprechend die Quelle und das Ziel konfigurieren und danach das Session-Objekt starten und auf das Ende warten. Das Anlegen der Quelle erfolgt genauso wie beim Video Player, das Ziel und die Topology dagegen logischerweise etwas anders. Glücklicherweise reicht es, für das Ziel einfach nur das Video-, Audio- und Container-Format anzugeben. Feineinstellungen wie die Videoauflösung, Bitrate usw. werden über Attribute gemacht. Die Topology selber ist relativ einfach zu bauen, da es dafür speziell für die Transcoding-Aufgabe entsprechende Schnittstellen und Methoden gibt, mit der sie unter Angabe von Quelle, Ziel und Container gebaut werden kann. Kern der Logik in der MF-API ist das TranscodingProfile. Folgender Code ist so ziemlich die wichtigste Stelle im Beispielprogramm und zeigt den grundsätzlichen Ablauf bei der Erstellung der Topology.

Das drum herum ist dann ähnlich wie beim Video Player. Es wird ein Session-Objekt erzeugt, diesem wird die Topology zugeordnet und danach wird es gestartet und überwacht. Die drei Methoden ConfigureAudioOutput, ConfigureVideoOutput und ConfigureOutputContainer sind eigene Entwicklungen, welche weitgehend den entsprechenden Methoden in den C++-Beispielen (siehe oben) entsprechen.

Konfiguration des Video-Formats
Ab hier möchte ich auf einen Zeitfresser eingehen, der mir einige Stunden gekostet hat. In den C++-Beispielen werden zur Angabe des Video-Formats Konstanten verwendet. Hier ein Beispiel:

Ich spreche hier beispielsweise von der Konstante MFVideoFormat_WMV3. Natürlich gibt es noch ein paar mehr, aber in SharpDX (2.5) lassen sich diese Konstanten im Gegensatz zu denen für Audio-Formaten nicht finden. Scheinbar ist SharpDX an der Stelle noch nicht komplett. Aber gut, normalerweise wäre das ja kein Problem, man kann die Konstante(n) ja auch selber aus den Header der MF-API abschreiben. Im C++-Header sind diese aber wie folgt definiert:

Bitte nicht verwirren lassen, obige Schnipsel stammen aus verschiedenen Teilen der C++-Header. Hieraus kann man lesen, dass es sich um Guids handelt und dass alle bis auf das erste Feld genau gleich aufgebaut sind (Siehe Makro DEFINE_MEDIATYPE_GUID). Das erste Feld ergibt sich aus dem Wert, der hier bei dem Makro FCC heraus kommt. Nun, mein erster Versuch diese „Bitshifterei“ in C# nachzubauen ging in die Hose – warum auch immer.  Nach einer kurzen Suche im Web und einem genaueren Blick auf den Makro zeigt, welche primitive Logik dahintersteckt: Der übergebene String wird einfach so wie er ist in eine Variable vom Typ Integer geschrieben (Siehe Wikipedia). Wichtig für .Net ist, dass als Kodierung ASCII verwendet wird. Nachfolgende Methode habe ich mir schließlich gebaut, um diese Guid nach Angabe des FCC-Strings zusammen zu bauen.

Mit Hilfe dieser Methode hat sich dann relativ einfach eine Klasse basteln lassen, welche die Guids aller möglichen Video-Formate enthält – so wie man es erwarten würde.

Weitere Schwierigkeiten
Alles Weitere lief glücklicherweise gewöhnlich ab. Gewöhnlich in dem Sinne, wie man es sich beim Umsetzen von C++ Code in C# erwarten kann…

Quellcode
www.rolandk.de/files/Testing.SimpleMFTranscoding.zip

Quellen

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.