異步 MFT
本主題描述媒體基礎轉換的異步數據處理(MFT)。
注意
本主題適用於 Windows 7 或更新版本。
- 關於異步 MFT 的
- 一般需求
- 事件
- ProcessInput
- ProcessOutput
- 清空
- Flushing
- 標記
- 格式變更
- 屬性
- 解除鎖定異步 MFT
- 關閉 MFT
- 註冊和列舉
- 相關主題
關於異步 MFT
在 Windows Vista 中引進 MFT 時,API 是針對 同步 數據處理而設計。 在該模型中,MFT 一律會等候取得輸入,或等候產生輸出。
請考慮一般的視訊譯碼器。 若要取得譯碼框架,用戶端會呼叫 IMFTransform::P rocessOutput。 如果譯碼器有足夠的數據可譯碼框架,ProcessOutput 區塊,而 MFT 會譯碼框架。 否則,ProcessOutput 會傳回 MF_E_TRANSFORM_NEED_MORE_INPUT,表示客戶端應該呼叫 imfTransform::P rocessInput。
如果譯碼器在一個線程上執行其所有譯碼作業,此模型運作良好。 但假設譯碼器使用數個線程平行譯碼框架。 為了獲得最佳效能,譯碼器應該在譯碼線程閑置時接收新的輸入。 但是線程完成譯碼作業的速率不會與用戶端呼叫 ProcessInput 和 ProcessOutput完全一致,導致線程等候工作。
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 介面傳送頻外事件,如下所示:
- MFT 會實作 IMFMediaEventGenerator 介面,如媒體事件產生器 中所述。
- 用戶端會 針對IMFMediaEventGenerator 介面,在MFT上呼叫 IUnknown::QueryInterface。 異步 MFT 必須公開這個介面。 同步 MFT 不應該公開這個介面。
- 用戶端會呼叫 IMFMediaEventGenerator::BeginGetEvent 和 IMFMediaEventGenerator::EndGetEvent,以從 MFT 接收頻外事件。
ProcessInput
IMFTransform::P rocessInput 方法會修改如下:
- 串流啟動時,用戶端會傳送 MFT_MESSAGE_NOTIFY_START_OF_STREAM 訊息。
- 在串流期間,MFT 會傳送 METransformNeedInput 事件來要求數據。 事件數據是數據流標識碼。
- 針對每個 METransformNeedInput 事件,用戶端會針對指定的數據流呼叫 ProcessInput。
- 在串流結束時,用戶端可以使用 MFT_MESSAGE_NOTIFY_END_OF_STREAM 訊息呼叫 ProcessMessage。
實作注意事項:
- MFT 在收到 MFT_MESSAGE_NOTIFY_START_OF_STREAM 訊息之前,不得傳送任何 METransformNeedInput 事件。
- 在串流期間,MFT 可以隨時傳送 METransformNeedInput 事件。
- MFT 應維護暫止 METransformNeedInput 事件的計數。 未對應至 METransformNeedInput 事件之 processInput的任何呼叫都必須傳回 MF_E_NOTACCEPTING。
- 當 MFT 收到 MFT_MESSAGE_NOTIFY_END_OF_STREAM 訊息時,它會將暫止 METransformNeedInput 事件計數重設為零。
- MFT 在收到 MFT_MESSAGE_NOTIFY_END_OF_STREAM 訊息之後,不得傳送任何 METransformNeedInput 事件。
- 如果在 MFT_MESSAGE_NOTIFY_START_OF_STREAM 或 MFT_MESSAGE_NOTIFY_END_OF_STREAM之後呼叫 ProcessInput,則方法必須傳回 MF_E_NOTACCEPTING。
ProcessOutput
IMFTransform::P rocessOutput 方法會修改如下:
- 每當 MFT 有輸出時,就會傳送 METransformHaveOutput 事件。
- 針對每個 METransformHaveOutput 事件,用戶端會呼叫 ProcessOutput。
實作注意事項:
- 如果用戶端在任何時間呼叫 ProcessOutput,此方法會傳回 E_UNEXPECTED。
- 異步 MFT 絕不應從 ProcessOutput 方法傳回 MF_E_TRANSFORM_NEED_MORE_INPUT。 如果 MFT 需要更多輸入,它會傳送 METransformNeedInput 事件。
排水
清空 MFT 會導致 MFT 從任何已傳送的輸入資料產生盡可能多的輸出。 清空異步 MFT 的運作方式如下:
- 用戶端會傳送 MFT_MESSAGE_COMMAND_DRAIN 訊息。
- MFT 會繼續傳送 METransformHaveOutput 事件,直到沒有其他要處理的數據為止。 在此期間,它不會傳送 METransformNeedInput 事件。
- 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 會回應如下:
- MFT 會從現有的輸入數據產生盡可能多的輸出範例,針對每個輸出範例傳送 METransformHaveOutput 事件。
- 產生所有輸出之後,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,但有下列例外狀況:
- IMFTransform::GetAttributes (所有異步 MFT)
- IMFTransform::GetInputAvailableType (所有異步 MFT)
- IMFTransform::GetOutputCurrentType (僅限編碼器)
- IMFTransform::SetOutputType (僅限編碼器)
- IMFTransform::GetStreamCount (所有異步 MFT)
- IMFTransform::GetStreamIDs (所有異步 MFT)
下列程式代碼示範如何解除鎖定異步 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 可能會中斷現有的應用程式。
相關主題