步驟 6. 新增 COM 的支援
[與此頁面相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議使用舊版 API 的現有程式碼盡可能重寫為使用新的 API。
這是 撰寫轉換篩選教學課程的步驟 6。
最後一個步驟是新增 COM 的支援。
參考計數
您不需要實作 IUnknown::AddRef 或 IUnknown::Release。 所有篩選和釘選類別都衍生自 CUnknown,其會處理參考計數。
QueryInterface
所有篩選和釘選類別都會針對繼承的任何 COM 介面實作 IUnknown::QueryInterface 。 例如,CTransformFilter會透過CBaseFilter) 繼承 IBaseFilter (。 如果您的篩選未公開任何其他介面,您就不需要執行任何其他動作。
若要公開其他介面,請覆寫 CUnknown::NonDelegatingQueryInterface 方法。 例如,假設您的篩選實作名為 IMyCustomInterface 的自訂介面。 若要將此介面公開給用戶端,請執行下列動作:
- 從該介面衍生您的篩選類別。
- 將 DECLARE_IUNKNOWN 宏放在公用宣告區段中。
- 覆寫 NonDelegatingQueryInterface 以檢查介面的 IID,並傳回篩選準則的指標。
下列程式碼顯示這些步驟:
CMyFilter : public CBaseFilter, public IMyCustomInterface
{
public:
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID iid, void **ppv);
};
STDMETHODIMP CMyFilter::NonDelegatingQueryInterface(REFIID iid, void **ppv)
{
if (riid == IID_IMyCustomInterface) {
return GetInterface(static_cast<IMyCustomInterface*>(this), ppv);
}
return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
}
如需詳細資訊,請參閱 如何實作 IUnknown。
建立物件
如果您打算在 DLL 中封裝篩選,並使它可供其他用戶端使用,則必須支援 CoCreateInstance 和其他相關的 COM 函式。 基類庫會實作大部分的專案;您只需要提供有關篩選準則的一些資訊。 本節提供要執行的簡短概觀。 如需詳細資訊,請參閱 如何建立 DirectShow 篩選 DLL。
首先,撰寫靜態類別方法,以傳回您篩選的新實例。 您可以將此方法命名為您想要的任何專案,但簽章必須符合下列範例所示的簽章:
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
接下來,宣告名為 g_Templates 的 CFactoryTemplate類別實例全域陣列。 每個 CFactoryTemplate 類別都包含一個篩選的登錄資訊。 數個篩選準則可以位於單一 DLL 中;只要包含其他 CFactoryTemplate 專案即可。 您也可以宣告其他 COM 物件,例如屬性頁。
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
定義名為 g_cTemplates 的全域整數,其值等於 g_Templates 陣列的長度:
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
最後,實作 DLL 註冊函式。 下列範例顯示這些函式的最小實作:
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
篩選登錄專案
上述範例示範如何註冊篩選的 COM CLSID。 對於許多篩選準則而言,這已足夠。 然後,用戶端應該使用 CoCreateInstance 建立篩選,並藉由呼叫 IFilterGraph::AddFilter將它新增至篩選圖形。 不過,在某些情況下,您可能會想要提供登錄中篩選的其他資訊。 這項資訊會執行下列動作:
下列範例會在影片壓縮類別中註冊 RLE 編碼器篩選準則。 如需詳細資訊,請參閱 如何註冊 DirectShow 篩選。 請務必閱讀 註冊篩選的指導方針一節,其中說明篩選註冊的建議做法。
// Declare media type information.
FOURCCMap fccMap = FCC('MRLE');
REGPINTYPES sudInputTypes = { &MEDIATYPE_Video, &GUID_NULL };
REGPINTYPES sudOutputTypes = { &MEDIATYPE_Video, (GUID*)&fccMap };
// Declare pin information.
REGFILTERPINS sudPinReg[] = {
// Input pin.
{ 0, FALSE, // Rendered?
FALSE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudInputTypes // Media types.
},
// Output pin.
{ 0, FALSE, // Rendered?
TRUE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudOutputTypes // Media types.
}
};
// Declare filter information.
REGFILTER2 rf2FilterReg = {
1, // Version number.
MERIT_DO_NOT_USE, // Merit.
2, // Number of pins.
sudPinReg // Pointer to pin information.
};
STDAPI DllRegisterServer(void)
{
HRESULT hr = AMovieDllRegisterServer2(TRUE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->RegisterFilter(
CLSID_RLEFilter, // Filter CLSID.
g_wszName, // Filter name.
NULL, // Device moniker.
&CLSID_VideoCompressorCategory, // Video compressor category.
g_wszName, // Instance data.
&rf2FilterReg // Filter information.
);
pFM2->Release();
}
return hr;
}
STDAPI DllUnregisterServer()
{
HRESULT hr = AMovieDllRegisterServer2(FALSE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory,
g_wszName, CLSID_RLEFilter);
pFM2->Release();
}
return hr;
}
此外,篩選不需要封裝在 DLL 內。 在某些情況下,您可能會撰寫專為特定應用程式設計的特製化篩選。 在此情況下,您可以直接在應用程式中編譯篩選類別,並使用 運算子加以建立 new
,如下列範例所示:
#include "MyFilter.h" // Header file that declares the filter class.
// Compile and link MyFilter.cpp.
int main()
{
IBaseFilter *pFilter = 0;
{
// Scope to hide pF.
CMyFilter* pF = new MyFilter();
if (!pF)
{
printf("Could not create MyFilter.\n");
return 1;
}
pF->QueryInterface(IID_IBaseFilter,
reinterpret_cast<void**>(&pFilter));
}
/* Now use pFilter as normal. */
pFilter->Release(); // Deletes the filter.
return 0;
}
相關主題