DMO與DirectShow filter的對比
1. DMO比filter實現的功能要少很多,這使得DMO“體積”很小;
2. DMO使用起來比filter更有靈活性。DMO的使用不需要filter graph,應用程式可以直接與DMO互動。而DMO也可以通過一個DMO wrapper filter工作於DirectShow環境;
3. DMO總是同步處理數據,不像filter有獨立的數據傳送執行緒,需要考慮多執行緒編程問題;
4. 與傳統的編解碼管理器ACM、VCM相比,用DMO開發的編解碼器是基於COM的,更易於擴展。並且DMO支持多個輸入和多個輸出;
5. DMO不需要像filter一樣分配數據傳送的記憶體,而有DMO的使用者負責;
6. DMO是一個獨立功能模組,不需要像filter一樣連線成一條鏈路;
7. DMO不需要像filter一樣將數據“推”下去,數據的輸入輸出都是由DMO的使用者完成的;
所有這些優點,使得DMO成為微軟對於ENCODER和Decoder開發的重點推薦模式。DirectX 9.0 SDK中,微軟更是把DMO從DirectShow中分離出來,而對於一些transform filter,微軟也推薦用DMO的方式來替換。
使用方式
關於DMO的使用方式,目前大概有兩種:一種是應用程式直接使用DMO,另一種就是在DirectShow filter中的套用。後者比較簡單,只是使用了一個DMO wrapper filter。在DirectShow應用程式中,DMO是對用戶透明的,所有使用DMO的工作均由DMO wrapper filter來完成。參見下面的代碼。
// Create the DMO Wrapper filter. IBaseFilter *pFilter; HRESULT hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pFilter)); if (SUCCEEDED(hr)) { // Query for IDMOWrapperFilter. IDMOWrapperFilter *pDmoWrapper; hr = pFilter->QueryInterface(IID_IDMOWrapperFilter, reinterpret_cast<void**>(&pDmoWrapper)); if (SUCCEEDED(hr)) { // initialize the filter. hr = pDmoWrapper->Init(CLSID_MyDMO, DMOCATEGORY_VIDEO_EFFECT); pDmoWrapper->Release(); if (SUCCEEDED(hr)) { // Add the filter to the graph. hr = pGraph->AddFilter(pFilter, L"My DMO"); } } pFilter->Release(); } |
而對於DMO的直接使用,以下幾點是要特別注意的。
1. 在處理數據之前,必須為每條輸入輸出stream設定media type(Optional stream除外);
2. 從DMO從獲取的media type未必包含format塊,但是在給DMO設定media type時,務必帶上這部分信息(MIDI除外);
3. 應用程式必須自己負責分配數據快取。快取的大小可以通過調用DMO的IMediaObject::GetInputSizeInfo或IMediaObject::GetOutputSizeInfo得到。DMO使用的數據快取也是一個COM對象,支持ImediaBuffer接口,與DirectShow filter的Media Sample類似。
4. 一般的DMO依次調用IMediaObject::ProcessInput和IMediaObject::ProcessOutput處理數據,In-Place的DMO調用IMediaObjectInPlace::Process處理數據。兩套方法不能混用。
5. 在調用ProcessOutput時,如果返回的標記是DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE,說明數據的數據還沒有完全取出,需要再次調用ProcessOutput。
6. 所有輸入數據都已輸入完成,應該調用DMO的IMediaObject::Discontinuity方法。
7. 如果你想中斷數據處理流程,調用DMO的IMediaObject::Flush。
8. 區別兩種不同的可丟棄stream,標記分別為DMO_OUTPUT_STREAMF_OPTIONAL和DMO_OUTPUT_STREAMF_DISCARDABLE。注意,後者是要設定media type的。