步驟 6. 新增 COM 的支援
[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayer、IMFMediaEngine,以及媒體基礎架構中的 音訊/視訊擷取取代。 這些功能已針對 Windows 10 和 Windows 11 進行優化。 Microsoft強烈建議新程式代碼盡可能在媒體 基礎中使用 MediaPlayer、IMFMediaEngine 和 音訊/視訊擷取,而不是 DirectShow。 Microsoft建議使用舊版 API 的現有程式代碼,盡可能改寫成使用新的 API。]
這是 撰寫轉換篩選教學課程的步驟 6。
最後一個步驟是新增 COM 的支援。
參考計數
您不需要實作 IUnknown::AddRef 或 IUnknown::Release。 所有篩選和釘選類別都衍生自 CUnknown,其會處理參考計數。
QueryInterface
所有 filter 和 pin 類別都會為繼承的任何 COM 介面實作 IUnknown::QueryInterface。 例如,CTransformFilter 繼承 IBaseFilter (透過 CBaseFilter)。 如果您的篩選不會公開任何其他介面,則不需要執行任何其他動作。
若要公開其他介面,請覆寫 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;
}
相關主題