共用方式為


異步 MFT

本主題描述媒體基礎轉換的異步數據處理(MFT)。

注意

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

 

關於異步 MFT

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

請考慮一般的視訊譯碼器。 若要取得譯碼框架,用戶端會呼叫 IMFTransform::P rocessOutput。 如果譯碼器有足夠的數據可譯碼框架,ProcessOutput 區塊,而 MFT 會譯碼框架。 否則,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 方法中將頻內事件傳送回用戶端。 (具體來說,事件會在 pEvents 中傳達MFT_OUTPUT_DATA_BUFFER 結構的成員。

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

  1. MFT 會實作 IMFMediaEventGenerator 介面,如媒體事件產生器 中所述。
  2. 用戶端會 針對IMFMediaEventGenerator 介面,在MFT上呼叫 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:呼叫 Shutdown 之後,MFT 應該傳回 pStatus 參數中的值 MFSHUTDOWN_COMPLETED。 它不應該傳回值 MFSHUTDOWN_INITIATED

註冊和列舉

若要註冊異步 MFT,請呼叫 MFTRegister 函式,並在 Flags 參數中設定 MFT_ENUM_FLAG_ASYNCMFT 旗標。 (先前這個旗標是保留的。

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

媒體基礎轉換