非同步 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。
如果解碼器在一個執行緒上執行其所有解碼作業,則此模型可正常運作。 但假設解碼器會使用數個執行緒平行解碼畫面。 為了達到最佳效能,解碼器應該會在解碼執行緒閒置時收到新的輸入。 但是執行緒完成解碼作業的速率不會與用戶端對 ProcessInput 和 ProcessOutput的呼叫完全一致,導致執行緒等候工作。
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 介面傳送頻外事件,如下所示:
- MFT 會實作 IMFMediaEventGenerator 介面,如 媒體事件產生器中所述。
- 用戶端會在MFT 上針對 IMFMediaEventGenerator介面呼叫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:呼叫關機之後,MFT 應該傳回pStatus參數中的值MFSHUTDOWN_COMPLETED。 它不應該傳回 值MFSHUTDOWN_INITIATED。
註冊和列舉
若要註冊非同步 MFT,請呼叫MFTRegister函式,並在Flags參數中設定MFT_ENUM_FLAG_ASYNCMFT旗標。 (先前已保留此旗標。)
若要列舉非同步 MFT,請呼叫MFTEnumEx函式,並在Flags參數中設定MFT_ENUM_FLAG_ASYNCMFT旗標。 為了回溯相容性, MFTEnum 函式不會列舉非同步 MFT。 否則,在使用者的電腦上安裝非同步 MFT 可能會中斷現有的應用程式。
相關主題