Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
[Funkcja skojarzona z tą stroną, DirectShow, jest starszą funkcją. Został zastąpiony przez MediaPlayer, IMFMediaEngineoraz Audio/Video Capture w Media Foundation. Te funkcje zostały zoptymalizowane pod kątem systemów Windows 10 i Windows 11. Firma Microsoft zdecydowanie zaleca, aby nowy kod używał MediaPlayer, IMFMediaEngine i Audio/Video Capture w programie Media Foundation zamiast DirectShow, jeśli to możliwe. Firma Microsoft sugeruje, że istniejący kod, który używa starszych interfejsów API, należy przepisać go do korzystania z nowych interfejsów API, jeśli to możliwe.]
To jest krok 6 z samouczka Pisanie filtrów przekształceń.
Ostatnim krokiem jest dodanie obsługi modelu COM.
Zliczanie odwołań
Nie trzeba implementować IUnknown::AddRef ani IUnknown::Release. Wszystkie klasy filtrów i pinów pochodzą z CUnknown, który obsługuje zliczanie referencji.
QueryInterface
Wszystkie klasy filtrów i pinów implementują IUnknown::QueryInterface dla wszystkich dziedziczonych interfejsów COM. Na przykład CTransformFilter dziedziczy IBaseFilter (za pośrednictwem CBaseFilter). Jeśli filtr nie uwidacznia żadnych dodatkowych interfejsów, nie trzeba wykonywać żadnych innych czynności.
Aby udostępnić dodatkowe interfejsy, przesłoń metodę CUnknown::NonDelegatingQueryInterface. Załóżmy na przykład, że filtr implementuje interfejs niestandardowy o nazwie IMyCustomInterface. Aby uwidocznić ten interfejs dla klientów, wykonaj następujące czynności:
- Utwórz klasę filtru z tego interfejsu.
- Umieść makro DECLARE_IUNKNOWN w sekcji deklaracji publicznej.
- Zastąp NonDelegatingQueryInterface, aby sprawdzić IID swojego interfejsu i zwrócić wskaźnik do swojego filtra.
Poniższy kod przedstawia następujące kroki:
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);
}
Aby uzyskać więcej informacji, zobacz How to Implement IUnknown.
Tworzenie obiektu
Jeśli planujesz spakować filtr w pliku DLL i udostępnić go innym klientom, musisz obsługiwać CoCreateInstance i innych powiązanych funkcji COM. Biblioteka klas bazowych implementuje większość z nich; Wystarczy podać pewne informacje o filtrze. Ta sekcja zawiera krótkie omówienie tego, co należy zrobić. Aby uzyskać szczegółowe informacje, zobacz Jak stworzyć filtr DirectShow w postaci DLL.
Najpierw napisz metodę klasy statycznej, która zwraca nowe wystąpienie filtru. Tę metodę można nazwać, ale podpis musi być zgodny z tą pokazaną w poniższym przykładzie:
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
Następnie zadeklaruj globalną tablicę wystąpień klas CFactoryTemplate o nazwie g_Templates. Każda klasa CFactoryTemplate zawiera informacje o rejestrze dla jednego filtru. Kilka filtrów może znajdować się w jednej biblioteki DLL; wystarczy dołączyć dodatkowe wpisy CFactoryTemplate. Można również zadeklarować inne obiekty COM, takie jak strony właściwości.
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
Zdefiniuj globalną liczbę całkowitą o nazwie g_cTemplates, której wartość jest równa długości tablicy g_Templates:
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
Na koniec zaimplementuj funkcje rejestracji bibliotek DLL. W poniższym przykładzie przedstawiono minimalną implementację tych funkcji:
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
Filtrowanie wpisów rejestru
W poprzednich przykładach pokazano, jak zarejestrować CLSID filtra dla modelu COM. W przypadku wielu filtrów jest to wystarczające. Następnie oczekuje się, że klient utworzy filtr przy użyciu CoCreateInstance i dodać go do wykresu filtru, wywołując IFilterGraph::AddFilter. W niektórych przypadkach możesz jednak podać dodatkowe informacje o filtrze w rejestrze. Następujące działania wynikają z tych informacji:
- Umożliwia klientom odkrywanie filtru przy użyciu mapatora filtrów lub modułu wyliczającego urządzenia systemowego .
- Umożliwia menedżerowi filtrów programu Graph odnajdywanie filtru podczas automatycznego kompilowania grafu.
Poniższy przykład rejestruje filtr enkodera RLE w kategorii kompresora wideo. Aby uzyskać szczegółowe informacje, zobacz Jak zarejestrować filtry DirectShow. Zapoznaj się z sekcją Wytyczne dotyczące rejestrowania filtrów, w której opisano zalecane rozwiązania dotyczące rejestracji filtrów.
// 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;
}
Ponadto filtry nie muszą być pakowane wewnątrz bibliotek DLL. W niektórych przypadkach można napisać wyspecjalizowany filtr przeznaczony tylko dla określonej aplikacji. W takim przypadku możesz skompilować klasę filtru bezpośrednio w aplikacji i utworzyć ją za pomocą operatora new, jak pokazano w poniższym przykładzie:
#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;
}
Tematy pokrewne