Videos per SourceReader der MediaFoundation lesen

Mein letzter Beitrag auf dieser Seite hatte das Schreiben von Videos per Media Foundation zum Thema, in diesem hier geht es entsprechend um das Lesen. Auch hier habe ich mich an die Vorlagen von Microsoft gehalten, beispielsweise dieses kurze Tutorial [1]. Die Klasse SourceReader der Media Foundation ist hierbei Dreh- und Angelpunkt. Mit ihr kann man eine neue Video-Datei anlegen und entsprechend alle Video-Frames einzeln übergeben. Alles nichts weltbewegendes, letzten Endes hat es mir aber trotzdem ein paar Tage gekostet, die Sache ordentlich zum Laufen zu kriegen. Wer denkt auch daran, dass Alpha-Werte vom SourceReader ignoriert werden?

Doch bevor ich mich über die Probleme auslasse, noch ein paar allgemeinere Worte. Endresultat dieses Themas ist die Klasse MediaFoundationVideoReader, welche entsprechend über das Projekt Seeing# von jedem abgerufen werden kann [2]. Die Klasse ist so ausgelegt, dass sie im Konstruktor einen Zeiger auf eine Videodatei bekommt (hier repräsentiert durch ResourceLink). Die Videodatei wird direkt geöffnet und kann mit der Methode ReadFrame Bild für Bild ausgelesen werden. Wie üblich verwende ich die eigene Klasse MemoryMappedTexture32bpp als Speicherblock für die übertragenen Pixel-Daten.

Kommen wir zu den Problemen. Zunächst hatte ich mit der Tatsache zu kämpfen, dass ich anstelle eines Dateipfades direkt einen Stream übergeben möchte. Warum einen Stream? Damit der VideoReader unabhänigig von einer Datei im Dateisystem arbeiten kann. Warum ein Problem? Weil der SourceReader der Media Foundation u. A. auch den Dateinamen zur Erkennung des zu verwendenden Codecs betrachtet. Wie im nachfolgenden Codeausschnitt zu sehen, kann man aber trotzdem per Attribut einen „Dummy“-Dateinamen an den Stream der Media Foundation anhängen, somit kennt sich der SourceReader wieder aus.

Ein weiterer Punkt zum vorangegangenen Codeausschnitt: Ganz am Anfang setze ich die Attribute EnableVideoProcessing und DisableDxva. Diese dienen dazu, dass ich am Ende Bilder im RBG32 Format bekomme, denn nicht jeder Codec unterstützt das Lesen in dieses Format direkt. Die beiden Attribute kümmern sich entsprechend darum, dass der SourceReader im Hintergrund automatisch konvertiert.

Das zweite Problem hatte ich dann innerhalb meiner ReadFrame Methode, und zwar an der Stelle, an der der Inhalt des aktuellen Sample-Buffers der Media Foundation (= aktuell gelesenes Bild) in meinen eigenen Speicherblock kopiert wird. Zunächst habe ich hierzu die Methode MediaFactory.CopyImage von SharpDX verwendet [3]. Das Endresultat war, dass sich das ReadFrame an sich korrekt verhalten hat: Zeitstempel wurden korrekt gelesen, Anzahl Bytes im Speicherblock haben gepasst und End-of-File wurde nach der richtigen Anzahl Frames erreicht. Nur: Das von mir generierte Bitmap war immer Schwarz bzw. völlig transparent. Irgendwas musste also an den Bilddaten nicht passen, welche von dem SourceReader geliefert wurden. Letzten Endes war das Problem aber viel trivialer: Ich initialisiere meinen eigenen Speicherblock immer komplett mit 0 (für Rot-, Grün-, Blau- und Alpha-Kanal). Das CopyImage der Media Foundation ignoriert den Alpha-Kanal aber und somit bleibt dieser bei mir immer 0 und mein generiertes Bitmap bleibt durchsichtig – obwohl Rot-, Grün- und Blau-Werte passen. Auf sowas muss man kommen. Nachfolgend noch der ganze Codeausschnitt zum Lesen von Bildern aus dem SourceReader.

 

Verweise
[1] https://msdn.microsoft.com/de-de/library/windows/desktop/dd389281(v=vs.85).aspx
[2] https://github.com/RolandKoenig/SeeingSharp/blob/master/SeeingSharp.Multimedia/DrawingVideo/_Readers/MediaFoundationVideoReader.cs
[3] http://sharpdx.org/documentation/api/m-sharpdx-mediafoundation-mediafactory-copyimage

Schreibe einen Kommentar

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