Asynchrone MFTs
In diesem Thema wird die asynchrone Datenverarbeitung für Media Foundation-Transformationen (MFTs) beschrieben.
Hinweis
Dieses Thema gilt für Windows 7 oder höher.
- Informationen zu asynchronen MFTs
- Allgemeine Anforderungen
- Ereignisse
- ProcessInput
- ProcessOutput
- Ausgleichen
- Spülung
- Marker
- Formatänderungen
- Attribute
- Entsperren asynchroner MFTs
- Herunterfahren des MFT
- Registrierung und Enumeration
- Zugehörige Themen
Informationen zu asynchronen MFTs
Als MFTs in Windows Vista eingeführt wurden, wurde die API für die synchrone Datenverarbeitung konzipiert. In diesem Modell wartet der MFT immer auf eingaben oder wartet auf die Ausgabe.
Betrachten Sie einen typischen Videodecoder. Um einen decodierten Frame abzurufen, ruft der Client IMFTransform::P rocessOutput auf. Wenn der Decoder über genügend Daten zum Decodieren eines Frames verfügt, wird ProcessOutput blockiert, während der MFT den Frame decodiert. Andernfalls gibt ProcessOutputMF_E_TRANSFORM_NEED_MORE_INPUT zurück, was angibt, dass der Client IMFTransform::P rocessInput aufrufen soll.
Dieses Modell funktioniert gut, wenn der Decoder alle Decodierungsvorgänge auf einem Thread ausführt. Angenommen, der Decoder verwendet mehrere Threads, um Frames parallel zu decodieren. Um eine optimale Leistung zu erzielen, sollte der Decoder immer dann neue Eingaben erhalten, wenn ein Decodierungsthread im Leerlauf ist. Aber die Rate, mit der Threads Decodierungsvorgänge abschließen, stimmt nicht genau mit den Aufrufen des Clients an ProcessInput und ProcessOutput überein, was dazu führt, dass Threads auf Arbeit warten.
Windows 7 führt die ereignisgesteuerte, asynchrone Verarbeitung für MFTs ein. Wenn der MFT in diesem Modell eine Eingabe benötigt oder eine Ausgabe aufweist, sendet er ein Ereignis an den Client.
Allgemeine Anforderungen
In diesem Thema wird beschrieben, wie sich asynchrone MFTs von synchronen MFT unterscheiden. Sofern in diesem Thema nicht angegeben, sind die beiden Verarbeitungsmodelle identisch. (Insbesondere ist die Formatverhandlung identisch.)
Ein asynchroner MFT muss die folgenden Schnittstellen implementieren:
Ereignisse
Ein asynchroner MFT verwendet die folgenden Ereignisse, um seine Datenverarbeitung status zu signalisieren:
Ereignis | BESCHREIBUNG |
---|---|
METransformNeedInput | Wird gesendet, wenn der MFT mehr Eingaben akzeptieren kann. |
METransformHaveOutput | Wird gesendet, wenn die MFT-Ausgabe aufweist. |
METransformDrainComplete | Wird gesendet, wenn ein Ablaufvorgang abgeschlossen ist. Siehe Entwässerung. |
METransformMarker | Wird gesendet, wenn ein Marker verarbeitet wird. Siehe Marker. |
Diese Ereignisse werden out-of-band gesendet. Es ist wichtig, den Unterschied zwischen In-Band- und Out-of-Band-Ereignissen im Kontext eines MFT zu verstehen.
Das ursprüngliche MFT-Design unterstützt In-Band-Ereignisse . Ein In-Band-Ereignis enthält Informationen zum Datenstrom, z. B. Informationen zu einer Formatänderung. Der Client sendet In-Band-Ereignisse an den MFT, indem er IMFTransform::P rocessEvent aufruft. Der MFT kann In-Band-Ereignisse in der ProcessOutput-Methode zurück an den Client senden. (Insbesondere werden Ereignisse im pEvents-Member der MFT_OUTPUT_DATA_BUFFER-Struktur übermittelt.)
Ein MFT sendet Out-of-Band-Ereignisse über die IMFMediaEventGenerator-Schnittstelle wie folgt:
- Der MFT implementiert die IMFMediaEventGenerator-Schnittstelle , wie unter Medienereignisgeneratoren beschrieben.
- Der Client ruft IUnknown::QueryInterface auf dem MFT für die IMFMediaEventGenerator-Schnittstelle auf. Eine asynchrone MFT muss diese Schnittstelle verfügbar machen. Synchrone MFTs sollten diese Schnittstelle nicht verfügbar machen.
- Der Client ruft IMFMediaEventGenerator::BeginGetEvent und IMFMediaEventGenerator::EndGetEvent auf, um Out-of-Band-Ereignisse vom MFT zu empfangen.
ProcessInput
Die IMFTransform::P rocessInput-Methode wird wie folgt geändert:
- Wenn das Streaming gestartet wird, sendet der Client die MFT_MESSAGE_NOTIFY_START_OF_STREAM Nachricht.
- Während des Streamings fordert der MFT Daten an, indem ein METransformNeedInput-Ereignis gesendet wird. Die Ereignisdaten sind der Streambezeichner.
- Für jedes METransformNeedInput-Ereignis ruft der Client ProcessInput für den angegebenen Stream auf.
- Am Ende des Streamings kann der Client ProcessMessage mit der MFT_MESSAGE_NOTIFY_END_OF_STREAM-Nachricht aufrufen.
Implementierungshinweise:
- Der MFT darf keine METransformNeedInput-Ereignisse senden, bis er die MFT_MESSAGE_NOTIFY_START_OF_STREAM-Nachricht empfängt.
- Während des Streamings kann der MFT jederzeit METransformNeedInput-Ereignisse senden.
- Der MFT sollte die Anzahl der ausstehenden METransformNeedInput-Ereignisse beibehalten. Jeder Aufruf von ProcessInput , der nicht einem METransformNeedInput-Ereignis entspricht, muss MF_E_NOTACCEPTING zurückgeben.
- Wenn der MFT die MFT_MESSAGE_NOTIFY_END_OF_STREAM-Nachricht empfängt, setzt er die Anzahl der ausstehenden METransformNeedInput-Ereignisse auf 0 zurück.
- Der MFT darf keine METransformNeedInput-Ereignisse senden, nachdem er die MFT_MESSAGE_NOTIFY_END_OF_STREAM-Nachricht empfangen hat.
- Wenn ProcessInput vor MFT_MESSAGE_NOTIFY_START_OF_STREAM oder nach MFT_MESSAGE_NOTIFY_END_OF_STREAM aufgerufen wird, muss die Methode MF_E_NOTACCEPTING zurückgeben.
ProcessOutput
Die IMFTransform::P rocessOutput-Methode wird wie folgt geändert:
- Wenn der MFT eine Ausgabe aufweist, sendet er ein METransformHaveOutput-Ereignis .
- Für jedes METransformHaveOutput-Ereignis ruft der Client ProcessOutput auf.
Implementierungshinweise:
- Wenn der Client ProcessOutput zu einem anderen Zeitpunkt aufruft, gibt die Methode E_UNEXPECTED zurück.
- Ein asynchroner MFT sollte niemals MF_E_TRANSFORM_NEED_MORE_INPUT von der ProcessOutput-Methode zurückgeben. Wenn der MFT mehr Eingabe erfordert, sendet er ein METransformNeedInput-Ereignis .
Ausgleichen
Das Entleeren eines MFT bewirkt, dass der MFT so viel Ausgabe wie möglich aus den bereits gesendeten Eingabedaten erzeugt. Das Entladen eines asynchronen MFT funktioniert wie folgt:
- Der Client sendet die MFT_MESSAGE_COMMAND_DRAIN-Nachricht .
- MFT sendet weiterhin METransformHaveOutput-Ereignisse , bis keine weiteren Daten verarbeitet werden können. Während dieser Zeit werden keine METransformNeedInput-Ereignisse gesendet.
- Nachdem MFT das letzte METransformHaveOutput-Ereignis gesendet hat, sendet es ein METransformDrainComplete-Ereignis .
Nach Abschluss des Entladens sendet der MFT kein weiteres METransformNeedInput-Ereignis , bis es eine MFT_MESSAGE_NOTIFY_START_OF_STREAM Nachricht vom Client empfängt.
Spülung
Der Client kann den MFT leeren, indem er die MFT_MESSAGE_COMMAND_FLUSH-Nachricht sendet. Der MFT löscht alle Eingabe- und Ausgabebeispiele, die er enthält.
Das MFT sendet erst dann ein weiteres METransformNeedInput-Ereignis , wenn es eine MFT_MESSAGE_NOTIFY_START_OF_STREAM Nachricht vom Client empfängt.
Marker
Der Client kann einen Punkt im Stream markieren, indem er die MFT_MESSAGE_COMMAND_MARKER Nachricht sendet. Der MFT reagiert wie folgt:
- Der MFT generiert so viele Ausgabebeispiele wie möglich aus den vorhandenen Eingabedaten und sendet ein METransformHaveOutput-Ereignis für jedes Ausgabebeispiel.
- Nachdem die gesamte Ausgabe generiert wurde, sendet der MFT ein METransformMarker-Ereignis . Dieses Ereignis muss nach allen METransformHaveOutput-Ereignissen gesendet werden.
Angenommen, ein Decoder verfügt über genügend Eingabedaten, um vier Ausgabebeispiele zu erzeugen. Wenn der Client die MFT_MESSAGE_COMMAND_MARKER-Nachricht sendet, stellt der MFT vier METransformHaveOutput-Ereignisse (eins pro Ausgabebeispiel) in die Warteschlange, gefolgt von einem METransformMarker-Ereignis .
Die Markernachricht ähnelt der Entleerungsmeldung. Ein Abfluss wird jedoch als Unterbrechung im Stream betrachtet, während ein Marker nicht ist. Entwässerung und Marker weisen die folgenden Unterschiede auf.
Entwässerung:
- Beim Entladen sendet der MFT keine METransformNeedInput-Ereignisse .
- Der MFT verwirft alle Eingabedaten, die nicht zum Erstellen eines Ausgabebeispiels verwendet werden können.
- Einige MFTs erzeugen am Ende der Daten einen "Tail". Beispielsweise erzeugen Audioeffekte wie Hall oder Echo zusätzliche Daten, nachdem die Eingabedaten beendet wurden. Ein MFT, der einen Tail generiert, sollte dies am Ende eines Abflussvorgangs tun.
- Nachdem die MFT-Entwässerung abgeschlossen ist, markiert es das nächste Ausgabebeispiel mit dem attribut MFSampleExtension_Discontinuity , um eine Diskontinuität im Stream anzuzeigen.
Marker:
- MFT sendet weiterhin METransformNeedInput-Ereignisse , bevor das Markerereignis gesendet wird.
- Der MFT verwirft keine Eingabedaten. Wenn teilweise Daten vorhanden sind, sollten diese nach dem Markerpunkt verarbeitet werden.
- Der MFT erzeugt keinen Schwanz am Markerpunkt.
- Das MFT legt das Diskontinuitätsflag nicht nach dem Markerpunkt fest.
Formatänderungen
Ein asynchroner MFT muss dynamische Formatänderungen unterstützen, wie unter Behandeln von Streamänderungen beschrieben.
Attribute
Ein asynchroner MFT muss die IMFTransform::GetAttributes-Methode implementieren, um einen gültigen Attributspeicher zurückzugeben. Die folgenden Attribute gelten für asynchrone MFTs:
attribute | BESCHREIBUNG |
---|---|
MF_TRANSFORM_ASYNC | Das MFT muss dieses Attribut auf TRUE (1) festlegen. Der Client kann dieses Attribut abfragen, um zu ermitteln, ob das MFT asynchron ist. |
MF_TRANSFORM_ASYNC_UNLOCK | |
MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE | Das MFT muss dieses Attribut auf TRUE (1) festlegen. Der Client kann davon ausgehen, dass dieses Attribut festgelegt ist. |
Entsperren asynchroner MFTs
Asynchrone MFTs sind nicht mit dem ursprünglichen MFT-Datenverarbeitungsmodell kompatibel. Um zu verhindern, dass asynchrone MFTs vorhandene Anwendungen unterbrechen, wird der folgende Mechanismus definiert:
- Der Client ruft IMFTransform::GetAttributes auf dem MFT auf.
Der Client fragt nach diesem MF_TRANSFORM_ASYNC-Attribut ab. Bei einem asynchronen MFT ist der Wert dieses Attributs **TRUE**.
Zum Entsperren des MFT muss der Client das MF_TRANSFORM_ASYNC_UNLOCK-Attribut auf **TRUE** festlegen.
Bis der Client den MFT entsperrt, sollten alle IMFTransform-Methoden mit den folgenden Ausnahmen MF_E_TRANSFORM_ASYNC_LOCKED zurückgeben:
- IMFTransform::GetAttributes (alle asynchronen MFTs)
- IMFTransform::GetInputAvailableType (alle asynchronen MFTs)
- IMFTransform::GetOutputCurrentType (nur Encoder)
- IMFTransform::SetOutputType (nur Encoder)
- IMFTransform::GetStreamCount (alle asynchronen MFTs)
- IMFTransform::GetStreamIDs (alle asynchronen MFTs)
Der folgende Code zeigt, wie Sie eine asynchrone MFT entsperren:
HRESULT UnlockAsyncMFT(IMFTransform *pMFT)
{
IMFAttributes *pAttributes = NULL;
HRESULT hr = hr = pMFT->GetAttributes(&pAttributes);
if (SUCCEEDED(hr))
{
hr = pAttributes->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE);
pAttributes->Release();
}
return hr;
}
Herunterfahren des MFT
Asynchrone MFTs müssen die IMFShutdown-Schnittstelle implementieren.
- Herunterfahren: Der MFT muss seine Ereigniswarteschlange herunterfahren. Wenn Sie die Standardereigniswarteschlange verwenden, rufen Sie IMFMediaEventQueue::Shutdown auf. Optional kann der MFT andere Ressourcen freigeben. Der Client darf den MFT nach dem Aufrufen des Herunterfahrens nicht verwenden.
- GetShutdownStatus: Nachdem Shutdown aufgerufen wurde, sollte der MFT den Wert zurückgeben, der impStatus-Parameter MFSHUTDOWN_COMPLETED. Der Wert MFSHUTDOWN_INITIATED sollte nicht zurückgegeben werden.
Registrierung und Enumeration
Um einen asynchronen MFT zu registrieren, rufen Sie die MFTRegister-Funktion auf, und legen Sie das MFT_ENUM_FLAG_ASYNCMFT-Flag im Flags-Parameter fest. (Zuvor war dieses Flag reserviert.)
Um asynchrone MFTs aufzulisten, rufen Sie die MFTEnumEx-Funktion auf, und legen Sie das flag MFT_ENUM_FLAG_ASYNCMFT im Flags-Parameter fest. Aus Gründen der Abwärtskompatibilität listet die MFTEnum-Funktion keine asynchronen MFTs auf. Andernfalls könnte die Installation eines asynchronen MFT auf dem Computer des Benutzers vorhandene Anwendungen unterbrechen.
Zugehörige Themen