Freigeben über


Streaming- und Anwendungsthreads

[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde durch MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation ersetzt. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code nach Möglichkeit MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet. Microsoft schlägt vor, vorhandenen Code, der die Legacy-APIs verwendet, um nach Möglichkeit die neuen APIs zu verwenden.]

Jede DirectShow-Anwendung enthält mindestens zwei wichtige Threads: den Anwendungsthread und mindestens einen Streamingthread. Beispiele werden für die Streamingthreads übermittelt, und Zustandsänderungen finden im Anwendungsthread statt. Der Standard Streamingthreads wird von einem Quell- oder Parserfilter erstellt. Andere Filter können Workerthreads erstellen, die Beispiele liefern, und diese werden auch als Streamingthreads betrachtet.

Einige Methoden werden im Anwendungsthread aufgerufen, während andere in einem Streamingthread aufgerufen werden. Beispiel:

Mit einem separaten Streamingthread können Daten das Diagramm durchlaufen, während der Anwendungsthread auf Benutzereingaben wartet. Die Gefahr mehrerer Threads besteht jedoch darin, dass ein Filter Ressourcen erstellen kann, wenn er anhält (im Anwendungsthread), sie innerhalb einer Streamingmethode verwendet und diese beim Anhalten zerstört (auch im Anwendungsthread). Wenn Sie nicht vorsichtig sind, versucht der Streamingthread möglicherweise, die Ressourcen zu verwenden, nachdem sie zerstört wurden. Die Lösung besteht darin, Ressourcen mithilfe kritischer Abschnitte zu schützen und Streamingmethoden mit Zustandsänderungen zu synchronisieren.

Ein Filter benötigt einen kritischen Abschnitt, um den Filterzustand zu schützen. Die CBaseFilter-Klasse verfügt über eine Membervariable für diesen kritischen Abschnitt : CBaseFilter::m_pLock. Dieser kritische Abschnitt wird als Filtersperre bezeichnet. Außerdem benötigt jeder Eingabenadel einen kritischen Abschnitt, um die vom Streamingthread verwendeten Ressourcen zu schützen. Diese kritischen Abschnitte werden als Streamingsperren bezeichnet. Sie müssen sie in Ihrer abgeleiteten Pinklasse deklarieren. Am einfachsten ist die Verwendung der CCritSec-Klasse , die ein Windows-CRITICAL_SECTION-Objekt umschließt und mit der CAutoLock-Klasse gesperrt werden kann. Die CCritSec-Klasse bietet auch einige nützliche Debugfunktionen. Weitere Informationen finden Sie unter Debuggen von Funktionen im kritischen Abschnitt.

Wenn ein Filter beendet oder geleert wird, muss er den Anwendungsthread mit dem Streamingthread synchronisieren. Um Deadlocking zu vermeiden, muss zuerst die Blockierung des Streamingthreads aufgehoben werden, was aus mehreren Gründen blockiert werden kann:

  • Es wartet darauf, ein Beispiel innerhalb der IMemAllocator::GetBuffer-Methode abzurufen, da alle Beispiele der Zuordnung verwendet werden.
  • Es wartet darauf, dass ein anderer Filter von einer Streamingmethode zurückgegeben wird, z. B. Receive.
  • Es wartet in einer seiner eigenen Streamingmethoden, bis eine Ressource verfügbar wird.
  • Es handelt sich um einen Rendererfilter, der auf die Präsentationszeit des nächsten Beispiels wartet.
  • Es handelt sich um einen Rendererfilter, der innerhalb der Receive-Methode wartet, während er angehalten wird.

Wenn der Filter daher beendet oder geleert wird, muss er folgendes tun:

  • Lassen Sie jedes Beispiel, das es aus irgendeinem Grund enthält, frei. Dadurch wird die Blockierung der GetBuffer-Methode aufgehoben.
  • Kehren Sie von jeder Streamingmethode so schnell wie möglich zurück. Wenn eine Streamingmethode auf eine Ressource wartet, muss sie sofort nicht mehr warten.
  • Beginnen Sie mit der Ablehnung von Beispielen in Receive, sodass der Streamingthread nicht auf weitere Ressourcen zugreift. (Die CBaseInputPin-Klasse verarbeitet dies automatisch.)
  • Die Stop-Methode muss alle Zuordnungen des Filters aufheben. (Die CBaseInputPin-Klasse verarbeitet dies automatisch.)

Beide werden im Anwendungsthread geleert und beendet. Ein Filter wird als Reaktion auf die IMediaControl::Stop-Methode beendet. Der Filter Graph-Manager gibt den Befehl stop in Upstream Reihenfolge aus, beginnend mit den Renderern und rückwärts bis zu den Quellfiltern. Der Befehl stop erfolgt vollständig innerhalb der CBaseFilter::Stop-Methode des Filters. Wenn die Methode zurückgibt, sollte sich der Filter in einem beendeten Zustand befinden.

Das Leeren tritt in der Regel aufgrund eines Suchbefehls auf. Ein Flush-Befehl beginnt mit dem Quell- oder Parserfilter und wandert nach unten. Das Leeren erfolgt in zwei Phasen: Die IPin::BeginFlush-Methode informiert einen Filter, alle ausstehenden und eingehenden Daten zu verwerfen. Die IPin::EndFlush-Methode signalisiert dem Filter, daten erneut zu akzeptieren. Das Leeren erfordert zwei Phasen, da sich der BeginFlush-Aufruf im Anwendungsthread befindet, in dem der Streamingthread weiterhin Daten übermittelt. Daher können einige Beispiele nach dem BeginFlush-Aufruf eintreffen. Diese sollten vom Filter verworfen werden. Alle Proben, die nach dem EndFlush-Aufruf eintreffen, sind garantiert neu und sollten übermittelt werden.

Die folgenden Abschnitte enthalten Codebeispiele, die zeigen, wie die wichtigsten Filtermethoden wie Pause, Receive usw. implementiert werden, um Deadlocks und Racebedingungen zu vermeiden. Jeder Filter hat jedoch andere Anforderungen, sodass Sie diese Beispiele an Ihren jeweiligen Filter anpassen müssen.

Hinweis

Die Basisklassen CTransformFilter und CTransInPlaceFilter behandeln viele der in diesem Artikel beschriebenen Probleme. Wenn Sie einen Transformationsfilter schreiben und Ihr Filter nicht auf Ereignisse innerhalb einer Streamingmethode wartet oder beispiele außerhalb von Receive hält, sollten diese Basisklassen ausreichend sein.