非同步 MFT

本主題描述媒體基礎轉換的非同步資料處理, (MFT) 。

注意

本主題適用于 Windows 7 或更新版本。

 

關於非同步 MFT

在 Windows Vista 中引進 MFT 時,API 是專為 同步 資料處理而設計。 在該模型中,MFT 一律會等候取得輸入,或等候產生輸出。

請考慮典型的影片解碼器。 若要取得解碼的框架,用戶端會呼叫 IMFTransform::P rocessOutput。 如果解碼器有足夠的資料可解碼框架,則當 MFT 解碼框架時 ,ProcessOutput 會封鎖。 否則, ProcessOutput 會傳回 MF_E_TRANSFORM_NEED_MORE_INPUT,指出用戶端應該呼叫 IMFTransform::P rocessInput

如果解碼器在一個執行緒上執行其所有解碼作業,則此模型可正常運作。 但假設解碼器會使用數個執行緒平行解碼畫面。 為了達到最佳效能,解碼器應該會在解碼執行緒閒置時收到新的輸入。 但是執行緒完成解碼作業的速率不會與用戶端對 ProcessInputProcessOutput的呼叫完全一致,導致執行緒等候工作。

Windows 7 引進事件驅動、MFT 的非同步 處理。 在此模型中,每當 MFT 需要輸入或有輸出時,就會將事件傳送給用戶端。

一般需求

本主題描述非同步 MFT 與同步 MFT 有何不同。 除了本主題中所說明的以外,這兩個處理模型都相同。 (特別是,格式交涉相同。)

非同步 MFT 必須實作下列介面:

事件

非同步 MFT 會使用下列事件來發出其資料處理狀態的訊號:

事件 描述
METransformNeedInput 當 MFT 可以接受更多輸入時傳送。
METransformHaveOutput 當 MFT 有輸出時傳送。
METransformDrainComplete 清空作業完成時傳送。 請參閱 清空
METransformMarker 當標記正在處理時傳送。 請參閱 標記

 

這些事件會從頻外傳送。 請務必瞭解 MFT 內容中的頻內事件與頻外事件之間的差異。

原始 MFT 設計支援 頻內 事件。 頻內事件包含資料流程的相關資訊,例如格式變更的相關資訊。 用戶端會呼叫 IMFTransform::P rocessEvent,將頻內事件傳送至 MFT。 MFT 可以在 ProcessOutput 方法中將頻內事件傳回用戶端。 (具體來說,事件會在MFT_OUTPUT_DATA_BUFFER structure.) 的pEvents成員中傳達

MFT 會透過 IMFMediaEventGenerator 介面傳送頻外事件,如下所示:

  1. MFT 會實作 IMFMediaEventGenerator 介面,如 媒體事件產生器中所述。
  2. 用戶端會在MFT 上針對 IMFMediaEventGenerator介面呼叫IUnknown::QueryInterface。 非同步 MFT 必須公開此介面。 同步 MFT 不應該公開此介面。
  3. 用戶端會呼叫 IMFMediaEventGenerator::BeginGetEventIMFMediaEventGenerator::EndGetEvent ,以接收來自 MFT 的頻外事件。

ProcessInput

IMFTransform::P rocessInput方法會修改如下:

  1. 串流啟動時,用戶端會傳送 MFT_MESSAGE_NOTIFY_START_OF_STREAM 訊息。
  2. 在串流期間,MFT 會傳送 METransformNeedInput 事件來要求資料。 事件資料是資料流程識別碼。
  3. 針對每個 METransformNeedInput 事件,用戶端會呼叫指定資料流程的 ProcessInput
  4. 在串流結束時,用戶端可能會使用MFT_MESSAGE_NOTIFY_END_OF_STREAM訊息呼叫ProcessMessage

實作注意事項:

ProcessOutput

IMFTransform::P rocessOutput方法會修改如下:

  1. 每當 MFT 有輸出時,就會傳送 METransformHaveOutput 事件。
  2. 針對每個 METransformHaveOutput 事件,用戶端會呼叫 ProcessOutput

實作注意事項:

  • 如果用戶端在任何時間呼叫 ProcessOutput ,此方法會傳回 E_UNEXPECTED
  • 非同步 MFT 絕對不應該從ProcessOutput方法傳回MF_E_TRANSFORM_NEED_MORE_INPUT。 如果 MFT 需要更多輸入,它會傳送 METransformNeedInput 事件。

正在清空

清空 MFT 會導致 MFT 從任何已傳送的輸入資料產生盡可能多的輸出。 清空非同步 MFT 的運作方式如下:

  1. 用戶端會傳送 MFT_MESSAGE_COMMAND_DRAIN 訊息。
  2. MFT 會繼續傳送 METransformHaveOutput 事件,直到沒有其他要處理的資料為止。 它不會在此時間傳送 METransformNeedInput 事件。
  3. MFT 傳送最後一個 METransformHaveOutput 事件之後,它會傳送 METransformDrainComplete 事件。

清空完成後,MFT 不會傳送另一個 METransformNeedInput 事件,直到收到來自用戶端 的MFT_MESSAGE_NOTIFY_START_OF_STREAM 訊息為止。

沖洗

用戶端可以藉由傳送 MFT_MESSAGE_COMMAND_FLUSH 訊息來排清 MFT。 MFT 會卸載它所保存的所有輸入和輸出範例。

MFT 不會傳送另一個 METransformNeedInput 事件,直到收到來自用戶端 的MFT_MESSAGE_NOTIFY_START_OF_STREAM 訊息為止。

標記

用戶端可以傳送 MFT_MESSAGE_COMMAND_MARKER 訊息,以標記資料流程中的點。 MFT 會回應如下:

  1. MFT 會從現有的輸入資料產生任意數量的輸出範例,並針對每個輸出範例傳送 METransformHaveOutput 事件。
  2. 產生所有輸出之後,MFT 會傳送 METransformMarker 事件。 此事件必須在所有 METransformHaveOutput 事件之後傳送。

例如,假設解碼器有足夠的輸入資料來產生四個輸出樣本。 如果用戶端傳送 MFT_MESSAGE_COMMAND_MARKER 訊息,MFT 會將四個 METransformHaveOutput 事件排入佇列, (每個輸出範例) 一個,後面接著 METransformMarker 事件。

標記訊息類似于清空訊息。 不過,清空會被視為資料流程中的中斷,而標記則不是。 清空和標記有下列差異。

排水:

  • 清空時,MFT 不會傳送 METransformNeedInput 事件。
  • MFT 會捨棄任何無法用來建立輸出範例的輸入資料。
  • 某些 MFT 會在資料結尾產生「尾」。 例如,音訊效果,例如殘響或回應會在輸入資料停止之後產生額外的資料。 產生尾端的 MFT 應該在清空作業結束時執行。
  • MFT 完成清空之後,它會使用 MFSampleExtension_Discontinuity 屬性標記下一個輸出範例,以指出資料流程中的不連續。

標記:

  • MFT 會繼續傳送 METransformNeedInput 事件,再傳送標記事件。
  • MFT 不會捨棄任何輸入資料。 如果有部分資料,則應該在標記點之後處理。
  • MFT 不會在標記點產生尾端。
  • MFT 不會在標記點之後設定不連續旗標。

格式變更

非同步 MFT 必須支援動態格式變更,如 處理資料流程變更中所述。

屬性

非同步 MFT 必須實作 IMFTransform::GetAttributes 方法,才能傳回有效的屬性存放區。 下列屬性適用于非同步 MFT:

屬性 描述
MF_TRANSFORM_ASYNC MFT 必須將此屬性設定為 TRUE (1) 。 用戶端可以查詢這個屬性,以探索 MFT 是否為非同步。
MF_TRANSFORM_ASYNC_UNLOCK
MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE MFT 必須將此屬性設定為 TRUE (1) 。 用戶端可以假設已設定這個屬性。

 

解除鎖定非同步MFT

非同步 MFT 與原始 MFT 資料處理模型不相容。 若要防止非同步 MFT 中斷現有的應用程式,已定義下列機制:

用戶端會在 MFT 上呼叫 IMFTransform::GetAttributes 。 用戶端會查詢這個 MF_TRANSFORM_ASYNC 屬性的 。 對於非同步 MFT,此屬性的值是 **TRUE**。 若要解除鎖定 MFT,用戶端必須將 MF_TRANSFORM_ASYNC_UNLOCK 屬性設定為 **TRUE**。

在用戶端解除鎖定 MFT 之前,所有 IMFTransform 方法都應該傳回 MF_E_TRANSFORM_ASYNC_LOCKED,但有下列例外狀況:

下列程式碼示範如何解除鎖定非同步 MFT:

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;
}

關閉 MFT

非同步MFT 必須實作 IMFShutdown 介面。

  • 關機:MFT 必須關閉其事件佇列。 如果使用標準事件佇列,請呼叫 IMFMediaEventQueue::Shutdown。 或者,MFT 可能會釋放其他資源。 用戶端在呼叫 Shutdown之後不得使用 MFT。
  • GetShutdownStatus:呼叫關機之後,MFT 應該傳回pStatus參數中的值MFSHUTDOWN_COMPLETED。 它不應該傳回 值MFSHUTDOWN_INITIATED

註冊和列舉

若要註冊非同步 MFT,請呼叫MFTRegister函式,並在Flags參數中設定MFT_ENUM_FLAG_ASYNCMFT旗標。 (先前已保留此旗標。)

若要列舉非同步 MFT,請呼叫MFTEnumEx函式,並在Flags參數中設定MFT_ENUM_FLAG_ASYNCMFT旗標。 為了回溯相容性, MFTEnum 函式不會列舉非同步 MFT。 否則,在使用者的電腦上安裝非同步 MFT 可能會中斷現有的應用程式。

媒體基礎轉換