Schreiben einer benutzerdefinierten Medienquelle

In diesem Thema wird beschrieben, wie Sie eine benutzerdefinierte Medienquelle in Microsoft Media Foundation implementieren. Sie enthält die folgenden Abschnitte:

Erstellen des Präsentationsdeskriptors

Die IMFMediaSource::CreatePresentationDescriptor-Methode gibt eine Kopie des Präsentationsdeskriptors der Quelle zurück. Um den Präsentationsdeskriptor zu erstellen, müssen Sie die Anzahl der Streams im Quellinhalt und die möglichen Formate der einzelnen Datenströme kennen. Erstellen Sie für jeden Stream wie folgt einen Streamdeskriptor:

  1. Erstellen Sie ein Array von Medientypen. Jeder Medientyp im Array stellt ein mögliches Format für den Stream dar. Weitere Informationen zum Erstellen von Medientypen finden Sie unter Medientypen.
  2. Rufen Sie MFCreateStreamDescriptor auf, um den Streamdeskriptor zu erstellen. Übergeben Sie das Array der Medientypen. Die Funktion gibt einen IMFStreamDescriptor-Zeiger zurück.
  3. Rufen Sie IMFStreamDescriptor::GetMediaTypeHandler auf, um den Medientyphandler des Streamdeskriptors abzurufen.
  4. Rufen Sie IMFMediaTypeHandler::SetCurrentMediaType auf, um das Standardstreamformat festzulegen. Verwenden Sie einen der Medientypen, die Sie in Schritt 1 erstellt haben. Im Allgemeinen sollten Sie das Format mit höchster Qualität verwenden.
  5. Legen Sie optional Attribute für den Streamdeskriptor fest. Eine Liste der Attribute, die für Streamdeskriptoren gelten, finden Sie unter Streamdeskriptorattribute.

Erstellen Sie nun den Präsentationsdeskriptor:

  1. Rufen Sie MFCreatePresentationDescriptor auf, und übergeben Sie das Array der Streamdeskriptoren. Die Funktion gibt einen IMFPresentationDescriptor-Zeiger zurück.
  2. Wählen Sie die Standardstreamauswahl aus, indem Sie IMFPresentationDescriptor::SelectStream aufrufen, um einen oder mehrere Streams auszuwählen. In der Standardkonfiguration muss mindestens ein Stream ausgewählt sein.
  3. Legen Sie optional Attribute für den Präsentationsdeskriptor fest. Eine Liste der Attribute, die für Streamdeskriptoren gelten, finden Sie unter Presentation Descriptor Attributes.

Sie sollten den Präsentationsdeskriptor einmal erstellen, entweder beim Start oder nachdem die Quelle genügend Quelldaten analysiert hat, um den Inhalt zu bestimmen. Die CreatePresentationDescriptor-Methode sollte eine Kopie des Präsentationsdeskriptors zurückgeben. Um die Kopie zu erstellen, rufen Sie IMFPresentationDescriptor::Clone auf. Das Zurückgeben einer Kopie verhindert, dass der Client den Status der ursprünglichen Präsentationsbeschreibung ändert, z. B. die Attribute oder die Streamauswahl. Beachten Sie jedoch, dass Clone eine flache Kopie erstellt, sodass der Client möglicherweise die zugrunde liegenden Streambeschreibungen ändern kann.

Starten der Medienquelle

Die IMFMediaSource::Start-Methode startet die Medienquelle oder sucht eine neue Position. Ein Aufruf von Start verursacht eine Suche , wenn der vorherige Zustand entweder angehalten oder ausgeführt wurde und eine neue Startzeit angegeben wird. Andernfalls verursacht die Start-Methode einen Start. Wenn der Startvorgang abgeschlossen ist, senden Sie die folgenden Ereignisse.

  1. Senden Sie ein MENewStream-Ereignis für jeden neuen Stream, d. h. für jeden Stream, der zuvor deaktiviert wurde und jetzt ausgewählt ist. Die Ereignisdaten sind ein Zeiger auf den Stream.
  2. Senden Sie ein MEUpdatedStream-Ereignis für jeden Stream, der zuvor ausgewählt war und weiterhin ausgewählt ist. Die Ereignisdaten sind ein Zeiger auf den Stream. (Senden Sie kein Ereignis für nicht ausgewählte Streams.)
  3. Wenn die Quelle sucht, senden Sie ein MESourceSeeked-Ereignis . Senden Sie andernfalls ein MESourceStarted-Ereignis . Die Ereignisdaten sind die Startzeit, die in der Start-Methode angegeben wurde. Legen Sie für das MESourceStarted-Ereignis das Attribut MF_EVENT_SOURCE_ACTUAL_START fest, wenn die Startzeit VT_EMPTY ist. Der Attributwert ist die tatsächliche Startzeit.
  4. Senden Sie für jeden Stream, wenn die Quelle sucht, ein MEStreamSeeked-Ereignis . Senden Sie andernfalls ein MEStreamStarted-Ereignis . Die Ereignisdaten sind die Startzeit. (Die Medienquelle kann ein Ereignis im Stream in die Warteschlange stellen, indem die IMFMediaEventGenerator::QueueEvent-Methode des Streams aufgerufen wird.)

Wenn ein Stream deaktiviert wird, fahren Sie den Stream herunter. Der Stream sollte zu diesem Zeitpunkt keine weiteren Ereignisse in die Warteschlange stellen.

Das Zeitformat für die Start-Methode wird im pguidTimeFormat-Parameter angegeben. Das Durch GUID_NULL angegebene Standardzeitformat beträgt 100 Nanosekundeneinheiten. Eine Medienquelle muss dieses Zeitformat unterstützen.

Suchen

Bei der Suche fällt die angeforderte Startposition möglicherweise nicht auf eine genaue Beispielgrenze. Außerdem kann die Startposition für komprimierte Inhalte zwischen Keyframes liegen. Ein Stream sollte Proben ab dem frühesten Zeitpunkt liefern, der erforderlich ist, um ein unkomprimiertes Beispiel an der angeforderten Startposition zu erstellen. Für Videos bedeutet dies, dass sie mit dem vorherigen Keyframe beginnen. Die Pipeline ist dafür verantwortlich, die zusätzlichen Frames aus dem Decoder zu löschen, sodass die Wiedergabe zum angeforderten Zeitpunkt beginnt.

Die in den Quellereignissen (MESourceStarted, MESourceSeeked, MEStreamStarted und MEStreamSeeked) angegebene Startzeit ist die angeforderte Startzeit (der in der Start-Methode angegebene Wert), unabhängig von der tatsächlichen Startposition.

Angenommen, die ersten Frames eines Videostreams weisen die folgenden Merkmale auf:

Beispiel 1 2 3 4
Time 33 msec 66 msec 100 msec 133 msec
Keyframe? Ja Nein Nein Ja

 

Wenn die Start-Methode mit einem Wert von 100 Millisekunden aufgerufen wird, muss die Quelle Video ab Frame 1 ausgeben, dem ersten Schlüsselbild vor dieser Zeit. Das Startereignis gibt weiterhin 100 Millisekunden in den Ereignisdaten an.

Anhalten der Medienquelle

Die IMFMediaSource::P ause-Methode hält die Medienquelle an.

Während die Quelle angehalten wird, kann ein Stream neue Beispiele erstellen und in einer Warteschlange speichern, aber der Stream liefert die Beispiele nicht. Hier sind einige Ausnahmen von dieser Regel:

  • Livequellen sollten Daten löschen, während sie angehalten werden.
  • Wenn die Quelle Daten aus einem Netzwerk abruft, wird der Server möglicherweise angehalten.

Wenn der Client IMFMediaStream::RequestSample aufruft, während die Quelle angehalten wird, wird die Anforderung auch in die Warteschlange gestellt, bis die Quelle erneut gestartet wird. Anforderungen sollten nicht gelöscht werden.

Das Anhalten ist nur ab dem Startzustand zulässig. Andernfalls sollte PauseMF_E_INVALID_STATE_TRANSITION zurückgeben.

Generieren von Quelldaten

Media Foundation verwendet ein Pullmodell. Dies bedeutet, dass Streams Beispiele als Reaktion auf Anforderungen aus der Pipeline generieren und übermitteln. Ein Stream kann Beispiele liefern, wenn die Medienquelle ausgeführt wird und der Stream ausgewählt ist. Ein Stream übermittelt Daten nur, wenn der Client ein neues Beispiel anfordert.

Beispielanforderungen

Der Client fordert ein neues Beispiel an, indem er IMFMediaStream::RequestSample aufruft. Hier ist die Reihenfolge der Vorgänge:

  1. Der Client ruft IMFMediaStream::RequestSample auf. Das Argument ist ein Zeiger auf ein optionales Tokenobjekt , das der Client zum Nachverfolgen der Anforderung verwendet. Der Client implementiert das Token. Token müssen die IUnknown-Schnittstelle verfügbar machen. Der Client kann auch einen NULL-Zeiger anstelle eines Tokens übergeben.

  2. Wenn der Client ein Token bereitgestellt hat, ruft der Medienstream AddRef für das Token auf und platziert das Token in einer First-In-, First-Out-Warteschlange. Die -Methode gibt zurück, und die verbleibenden Schritte werden asynchron ausgeführt.

  3. Wenn mehr Daten verfügbar sind, erstellt der Medienstream ein neues Beispiel. (Dieser Schritt wird im nächsten Abschnitt ausführlicher beschrieben.)

  4. Der Mediendatenstrom ruft das erste Token aus der Warteschlange ab.

  5. Wenn das Token nicht NULL ist, legt der Medienstream das attribut MFSampleExtension_Token für das Medienbeispiel fest. Der Wert des Attributs ist ein Zeiger auf das Token.

  6. Der Medienstream sendet ein MEMediaSample-Ereignis . Die Ereignisdaten sind ein Zeiger auf die IMFSample-Schnittstelle des Beispiels.

  7. Wenn der Client ein Token bereitgestellt hat, ruft der Medienstream Release für das Tokenobjekt auf.

Wenn der Mediendatenstrom die RequestSample-Anforderung des Clients nicht erfüllen kann, ruft er das Token aus der Warteschlange ab und ruft Release für das Token auf, sendet jedoch kein MEMediaSample-Ereignis .

Der Client kann das Token verwenden, um die status der Anforderung nachzuverfolgen. Wenn der Client das MEMediaSample-Ereignis empfängt, kann er das Token aus dem Beispiel abrufen und mit der ursprünglichen Anforderung abgleichen. Der Client kann das Token auch verwenden, um zu erkennen, ob die Medienquelle die Anforderung gelöscht hat. Wenn die Verweisanzahl des Tokens auf null fällt und der Mediendatenstrom kein MEMediaSample-Ereignis sendet, bedeutet dies, dass die Anforderung gelöscht wurde.

Bei den hier aufgeführten Schritten wird davon ausgegangen, dass die RequestSample-Methode als asynchroner Vorgang implementiert ist. Wenn die Methode synchron ist, müssen Sie das Anforderungstoken nicht in einer Warteschlange platzieren. Wenn das Generieren von Daten jedoch einen erheblichen Zeitraum in Anspruch nimmt, wird ein asynchroner Ansatz empfohlen, z. B. wenn die Quelle Daten aus einem Bytedatenstrom liest.

Der Stream ist für das Puffern aller Daten verantwortlich, die zwischen Aufrufen von RequestSample angesammelt werden.

Wenn der Mediendatenstrom das Ende des Datenstroms erreicht, sendet er nach dem letzten Beispiel ein MEEndOfStream-Ereignis . Nachdem jeder Stream beendet wurde, sendet die Medienquelle ein MEEndOfPresentation-Ereignis . Nachdem ein Mediendatenstrom das MEEndOfStream-Ereignis gesendet hat, gibt die RequestSample-MethodeMF_E_END_OF_STREAM zurück, bis die Quelle neu gestartet wird.

Zuordnen von Beispielen

Wenn der Stream bereit ist, eine ausstehende Beispielanforderung auszufüllen, erstellt er ein neues Beispiel und fügt dem Beispiel einen oder mehrere Medienpuffer hinzu. Weitere Informationen zum Erstellen von Medienpuffern finden Sie unter Medienpuffer.

Der Stream muss den Zeitstempel und die Dauer festlegen, sofern bekannt. Der Zeitstempel ist relativ zur Quelle. In den meisten Fällen entspricht der Anfang des Inhalts einem Zeitstempel von null. Wenn die Quelle z. B. aus einer Mediendatei liest, weist der Anfang der Datei einen Zeitstempel von 0 (null) auf.

Der Zeitstempel im Beispiel entspricht nicht unbedingt der Präsentationszeit. Die Mediensitzung wird von der Quellzeit in die Präsentationszeit übersetzt. Für komprimierte Daten sollte der Stream Daten generieren, die beim nächsten Keyframe vor der Startzeit beginnen. Dadurch kann der Decoder den Frame bereitstellen, der zur angeforderten Startzeit angezeigt wird. (Andernfalls müsste der Decoder bis zum folgenden Keyframe warten.)

Wenn die Wiedergaberate schneller oder langsamer als 1,0 ist, passt die Pipeline die Rate der Präsentationsuhr an. Die Quelle passt die Zeitstempel für Beispiele nicht an.

Die Quelle kann zusätzliche Informationen für das Beispiel festlegen, indem Attribute festgelegt werden. Eine Liste der Beispielattribute finden Sie unter Beispielattribute.

Lücken im Stream

Wenn ein Stream eine Lücke von erheblicher Länge enthält, wird empfohlen, dass der Stream ein MEStreamTick-Ereignis sendet. Dieses Ereignis benachrichtigt den Client, dass ein Beispiel fehlt. Die Ereignisdaten sind der Zeitstempel der fehlenden Stichprobe in 100 Nanosekundeneinheiten (VT_I8). Dieses Ereignis kann speichern, dass Downstreamkomponenten nicht auf Beispiele warten, die nicht eintreffen. Der Stream kann so viele MEStreamTick-Ereignisse wie erforderlich senden, um die Lücke im Stream zu überspannen.

Herunterfahren der Medienquelle

Wenn der Client die Medienquelle verwendet, ruft er IMFMediaSource::Shutdown auf. Innerhalb dieser Methode sollte die Medienquelle alle Kreisverweisanzahlen unterbrechen. In der Regel gibt es zirkuläre Verweise zwischen der Medienquelle und den Medienstreams.

Wenn Sie die Ereigniswarteschlange zum Implementieren von IMFMediaEventGenerator verwenden, rufen Sie INFMediaEventQueue::Shutdown in der Ereigniswarteschlange auf. Diese Methode beendet die Ereigniswarteschlange und signalisiert jeden Aufrufer, der derzeit auf ein Ereignis wartet.

Nach dem Herunterfahren geben alle Methoden auf der Quelle MF_E_SHUTDOWN zurück, mit Ausnahme der IUnknown-Methoden .

Livequellen

Ab Windows 7 unterstützt Media Foundation automatisch Audio- und Videoaufnahmegeräte. Für Video muss das Gerät einen KS-Minitreiber (Kernel Streaming) in der Kategorie Videoaufnahme bereitstellen. Media Foundation verwendet den PnP-Pfad, um das Gerät aufzulisten. Für Audio verwendet Media Foundation die MMDevice-API (Windows Multimedia Device), um Audioendpunkte aufzulisten. Wenn das Gerät diese Kriterien erfüllt, ist es nicht erforderlich, eine benutzerdefinierte Medienquelle zu implementieren.

Möglicherweise möchten Sie jedoch eine benutzerdefinierte Medienquelle für einen anderen Gerätetyp oder eine andere Livedatenquelle implementieren. Es gibt nur wenige Unterschiede zwischen einer Livequelle und anderen Medienquellen:

  • Geben Sie in der IMFMediaSource::GetCharacteristics-Methode das flag MFMEDIASOURCE_IS_LIVE zurück.
  • Das erste Beispiel sollte einen Zeitstempel von 0 (null) aufweisen.
  • Ereignisse und Streamingzustände werden mit Ausnahme des angehaltenen Zustands wie Medienquellen behandelt.
  • Wenn sie angehalten sind, stellen Sie keine Beispiele in die Warteschlange. Löschen Sie alle Daten, die generiert werden, während sie angehalten werden.
  • Livequellen unterstützen in der Regel keine Such-, ReversePlay- oder Ratensteuerung.

Medienquellen

Tutorial: Schreiben einer benutzerdefinierten Medienquelle