Schreiben eines Quellfilters für DirectShow

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde von MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation abgelöst. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code mediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet, wenn möglich. Microsoft schlägt vor, dass vorhandener Code, der die Legacy-APIs verwendet, so umgeschrieben wird, dass nach Möglichkeit die neuen APIs verwendet werden.]

In diesem Thema wird beschrieben, wie Sie einen benutzerdefinierten Quellfilter für DirectShow schreiben.

Hinweis

In diesem Thema werden nur Pushquellen beschrieben. Es beschreibt keine Pullquellen, z. B. den Async Reader-Filter, oder Splitterfilter, die eine Verbindung mit Pullquellen herstellen. Informationen zur Unterscheidung zwischen Push- und Pullquellen finden Sie unter Datenfluss für Filterentwickler.

Das DirectShow-Streamingmodell

Wenn Sie einen Quellfilter schreiben, ist es wichtig zu verstehen, dass eine Pushquelle nicht dasselbe ist wie eine Livequelle. Eine Livequelle ruft Daten aus einer externen Quelle ab, z. B. von einer Kamera oder einem Netzwerkstream. Im Allgemeinen kann eine Livequelle die eingehende Datenrate nicht steuern. Wenn die Downstreamfilter die Daten nicht schnell genug nutzen, muss die Quelle Beispiele löschen.

Eine Pushquelle muss jedoch keine Livequelle sein. Beispielsweise kann eine Pushquelle Daten aus einer lokalen Datei lesen. In diesem Fall bestimmen die nachgeschalteten Rendererfilter basierend auf der Referenzuhr und den Beispielzeitstempeln, wie schnell sie die Daten aus der Quelle nutzen. Der Quellfilter liefert So schnell wie möglich Stichproben, aber der tatsächliche Datenfluss wird durch die Renderer eingeschränkt. Die Mechanismen zum Gating des Datenflusses werden in Datenfluss für Filterentwickler beschrieben.

Jeder Ausgabepin im Quellfilter erstellt einen Thread, der als Streamingthread bezeichnet wird. Der Pin liefert Beispiele für den Streamingthread. In der Regel erfolgt die gesamte Decodierung, Verarbeitung und das Rendering in diesem Thread, obwohl einige Downstreamfilter möglicherweise zusätzliche Threads erstellen, um ihre Ausgabebeispiele in die Warteschlange zu stellen.

Der Streamingthread führt eine Schleife mit der folgenden Struktur aus:

until (stopped)
  1. Get a media sample from the allocator.
  2. Fill the sample with data.
  3. Time stamp the sample. 
  4. Deliver the sample downstream.

Wenn keine Beispiele verfügbar sind, blockiert Schritt 1, bis ein Beispiel verfügbar wird. Schritt 4 kann auch blockieren. sie kann z. B. blockiert werden, während der Graph angehalten wird.

Die Schleife wird so schnell wie möglich ausgeführt, ist jedoch durch die Zeit begrenzt, mit der der Rendererfilter jedes Beispiel rendert. Wenn das Filterdiagramm über eine Referenzuhr verfügt, wird die Rate durch die Präsentationszeiten der Stichproben bestimmt. Wenn keine Referenzuhr vorhanden ist, verwendet der Renderer die Beispiele so schnell wie möglich.

Verwenden von CSource und CSourceStream

Die DirectShow-Basisklassen enthalten zwei Klassen, die Pushquellen unterstützen: CSource und CSourceStream.

Ausgabepins

Ein Quellfilter kann über mehrere Ausgabepins verfügen. Erstellen Sie in der Konstruktormethode Ihres Filters einen oder mehrere von CSourceStream abgeleitete Pins (ein Pin pro Ausgabestream). Sie müssen keine Zeiger auf die Pins speichern. die Pins fügen sich automatisch dem Filter hinzu, wenn sie erstellt werden.

Ausgabeformate

Der Ausgabepin verarbeitet die Formataushandlung mit den folgenden CSourceStream-Methoden :

Methode BESCHREIBUNG
GetMediaType Ruft einen Medientyp vom Ausgabenadel ab.
Der Pin muss mindestens einen Medientyp vorschlagen, da der Downstreamfilter möglicherweise keine Typen vorschlägt. In den meisten Fällen ist der Downstreamfilter ein Decoder oder ein Renderer, je nachdem, ob der Quellfilter komprimierte oder nicht komprimierte Daten liefert. Ein Rendererfilter erfordert in der Regel einen vollständigen Medientyp, der alle Formatinformationen enthält, die zum Rendern des Datenstroms erforderlich sind. Bei einem Decoder hängt die Menge an Informationen, die im Medientyp erforderlich sind, stark vom Codierungsformat ab.
CheckMediaType Überprüft, ob der Ausgabepin einen bestimmten Medientyp akzeptiert. Das Überschreiben dieser Methode ist optional, je nachdem, wie Sie GetMediaType implementieren.

Die GetMediaType-Methode wird überladen:

Wenn der Ausgabepin des Quellfilters genau ein Medienformat unterstützt, sollten Sie (1) überschreiben, um das CMediaType-Objekt mit diesem Format zu initialisieren. Behalten Sie die Standardimplementierung von (2) bei, und behalten Sie auch die Standardimplementierung von CheckMediaType bei.

Wenn der Pin mehr als ein Format unterstützt, überschreiben Sie (2). Initialisieren Sie das CMediaType-Objekt entsprechend dem Wert der Indexvariablen. Der Pin sollte die Formate als sortierte Liste zurückgeben. In diesem Fall müssen Sie auch checkMediaType überschreiben, um den Medientyp anhand Ihrer Liste von Formaten zu überprüfen.

Denken Sie bei nicht komprimierten Videoformaten daran, dass der Downstreamfilter Formate mit verschiedenen Schrittwerten vorschlagen kann. Ihr Filter sollte jeden gültigen Schrittwert akzeptieren. Weitere Informationen finden Sie unter BITMAPINFOHEADER.

Sie müssen auch die rein virtuelle CBaseOutputPin::D ecideBufferSize-Methode überschreiben. Verwenden Sie diese Methode, um die Größe der Beispielpuffer festzulegen.

Streaming

Die CSourceStream-Klasse erstellt den Streamingthread für den Pin. Die Threadprozedur wird in der CSourceStream::D oBufferProcessingLoop-Methode implementiert. Diese Methode ruft die rein virtuelle CSourceStream::FillBuffer-Methode auf, die von der abgeleiteten Klasse außer Kraft gesetzt werden muss. Bei dieser Methode füllt die Pin den Puffer mit Daten aus. Wenn Ihr Filter beispielsweise unkomprimierte Videos liefert, würden Sie hier die Videoframes zeichnen.

Die Basisklasse startet und beendet die Threadschleife automatisch zum richtigen Zeitpunkt, wenn der Filter angehalten oder beendet wird. In diesem Fall ruft die CSourceStream-Klasse einige Methoden auf, um Ihre abgeleitete Klasse zu benachrichtigen:

Sie können diese Methoden überschreiben, wenn Sie eine spezielle Behandlung hinzufügen müssen. Andernfalls geben die Standardimplementierungen einfach S_OK zurück.

Suchen

Wenn Sie über einen Quellfilter mit einem Ausgabepin verfügen, können Sie die CSourceSeeking-Klasse als Ausgangspunkt für die Implementierung der Suche verwenden. Erben Sie Ihre Pin-Klasse sowohl von CSourceStream als auch von CSourceSeeking.

Hinweis

CSourceSeeking wird für einen Filter mit mehr als einem Ausgabepin nicht empfohlen. Das Standard Problem besteht darin, dass nur eine Pin auf Suchanforderungen reagieren sollte. In der Regel erfordert dies die Kommunikation zwischen den Pins und dem Filter.

Die CSourceSeeking-Klasse verwaltet die Wiedergaberate, die Startzeit, die Stoppzeit und die Dauer. Ihre abgeleitete Klasse sollte die anfängliche Stoppzeit und -dauer festlegen. Wenn sich einer dieser Werte ändert, wird die CSourceSeeking::ChangeRate-, CSourceSeeking::ChangeStart- oder CSourceSeeking::ChangeStop-Methode entsprechend aufgerufen. Die Methoden sind alle reinen virtuellen Methoden. Die abgeleitete Pinklasse überschreibt diese Methoden, um folgendes zu tun:

  1. Rufen Sie IPin::BeginFlush auf dem Downstream-Pin auf. Dies führt dazu, dass nachgeschaltete Filter Proben freigeben, die sie enthalten, und neue Proben ablehnen.
  2. Rufen Sie CSourceStream::Stop auf, um den Streamingthread zu beenden. Der Quellfilter hält die Erstellung neuer Daten an.
  3. Rufen Sie IPin::EndFlush auf dem Downstream-Pin auf. Dies signalisiert den nachgeschalteten Filtern, neue Daten zu akzeptieren.
  4. Rufen Sie IPin::NewSegment mit der neuen Start- und Stoppzeit und -rate auf.
  5. Legen Sie die Diskontinuitätseigenschaft im nächsten Beispiel fest.

Weitere Informationen finden Sie unter Unterstützung der Suche in einem Quellfilter.

Wenn Ihr Filter die Suche unterstützt, ist die Streamposition jetzt unabhängig von der Präsentationszeit. Nach einer Suche wird der Zeitstempel auf null zurückgesetzt. Die allgemeine Formel für Zeitstempel lautet:

  • Startzeit des Beispiels = verstrichene Zeit /Wiedergaberate
  • Sample-Endzeit = Startzeit des Beispiels + (Zeit pro Frame/Wiedergaberate)

Dabei ist die verstrichene Zeit die Zeit, die seit beginn der Ausführung des Filters oder seit dem letzten Seek-Befehl verstrichen ist.

Zeitformate für die Suche

Standardmäßig befinden sich Seek-Befehle in Einheiten von 100 Nanosekunden. Ihr Quellfilter kann zusätzliche Zeitformate unterstützen, z. B. die Suche nach Framenummer. Jedes Mal, wenn das Format durch eine GUID identifiziert wird; siehe Zeitformat-GUIDs.

Um zusätzliche Zeitformate zu unterstützen, müssen Sie die folgenden Methoden an Ihrem Ausgabepin implementieren:

Wenn die Anwendung ein neues Zeitformat festlegt, werden alle Positionsparameter in den IMediaSeeking-Methoden in Bezug auf das neue Zeitformat interpretiert. Wenn das Zeitformat beispielsweise Frames ist, muss die IMediaSeeking::GetDuration-Methode die Dauer in Frames zurückgeben.

In der Praxis unterstützen nur wenige DirectShow-Filter zusätzliche Zeitformate, und daher nutzen nur wenige DirectShow-Anwendungen diese Funktion.

Schreiben von Quellfiltern