Schritt 6: Hinzufügen von Support für COM
[Das dieser Seite zugeordnete Feature DirectShow ist ein Legacyfeature. Es wurde durch MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation ersetzt. Diese Features wurden für Windows 10 und Windows 11 optimiert. Microsoft empfiehlt dringend, dass neuer Code nach Möglichkeit MediaPlayer, IMFMediaEngine und Audio/Video Capture in Media Foundation anstelle von DirectShow verwendet. Microsoft schlägt vor, vorhandenen Code, der die Legacy-APIs verwendet, um nach Möglichkeit die neuen APIs zu verwenden.]
Dies ist Schritt 6 des Tutorials Schreiben von Transformationsfiltern.
Der letzte Schritt besteht darin, Unterstützung für COM hinzuzufügen.
Sie müssen IUnknown::AddRef oder IUnknown::Release nicht implementieren. Alle Filter- und Pinklassen stammen von CUnknown ab, das die Verweiszählung verarbeitet.
Alle Filter- und Pinklassen implementieren IUnknown::QueryInterface für alle COM-Schnittstellen, die sie erben. Beispielsweise erbt CTransformFilterIBaseFilter (über CBaseFilter). Wenn Ihr Filter keine zusätzlichen Schnittstellen verfügbar macht, müssen Sie nichts anderes tun.
Um zusätzliche Schnittstellen verfügbar zu machen, überschreiben Sie die CUnknown::NonDelegatingQueryInterface-Methode . Angenommen, Ihr Filter implementiert eine benutzerdefinierte Schnittstelle namens IMyCustomInterface. Gehen Sie wie folgt vor, um diese Schnittstelle für Clients verfügbar zu machen:
- Leiten Sie Ihre Filterklasse von dieser Schnittstelle ab.
- Platzieren Sie das makro DECLARE_IUNKNOWN im Abschnitt öffentliche Deklaration.
- Überschreiben Sie NonDelegatingQueryInterface , um nach der IID Ihrer Schnittstelle zu suchen und einen Zeiger auf Ihren Filter zurückzugeben.
Diese Schritte sind im folgenden Code dargestellt:
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);
}
Weitere Informationen finden Sie unter Implementieren von IUnknown.
Wenn Sie planen, Ihren Filter in einer DLL zu packen und für andere Clients verfügbar zu machen, müssen Sie CoCreateInstance und andere verwandte COM-Funktionen unterstützen. Die Basisklassenbibliothek implementiert das meiste davon. Sie müssen nur einige Informationen zu Ihrem Filter angeben. Dieser Abschnitt bietet einen kurzen Überblick über die zu tunden Aufgaben. Ausführliche Informationen finden Sie unter Erstellen einer DirectShow-Filter-DLL.
Schreiben Sie zunächst eine statische Klassenmethode, die eine neue instance Ihres Filters zurückgibt. Sie können diese Methode beliebig benennen, aber die Signatur muss mit der im folgenden Beispiel gezeigten übereinstimmen:
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
Deklarieren Sie als Nächstes ein globales Array von CFactoryTemplate-Klasseninstanzen mit dem Namen g_Templates. Jede CFactoryTemplate-Klasse enthält Registrierungsinformationen für einen Filter. Mehrere Filter können sich in einer einzelnen DLL befinden. Fügen Sie einfach zusätzliche CFactoryTemplate-Einträge hinzu. Sie können auch andere COM-Objekte deklarieren, z. B. Eigenschaftenseiten.
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
Definieren Sie eine globale ganze Zahl namens g_cTemplates deren Wert der Länge des g_Templates-Arrays entspricht:
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
Implementieren Sie schließlich die DLL-Registrierungsfunktionen. Das folgende Beispiel zeigt die minimale Implementierung für diese Funktionen:
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
Die vorherigen Beispiele zeigen, wie Sie die CLSID eines Filters für COM registrieren. Für viele Filter ist dies ausreichend. Anschließend wird erwartet, dass der Client den Filter mithilfe von CoCreateInstance erstellt und dem Filterdiagramm durch Aufrufen von IFilterGraph::AddFilter hinzugefügt wird. In einigen Fällen können Sie jedoch zusätzliche Informationen zum Filter in der Registrierung bereitstellen. Diese Informationen führen folgendes aus:
- Ermöglicht Clients, den Filter mithilfe der Filterzuordnung oder des Systemgeräte-Enumerators zu ermitteln.
- Ermöglicht dem Filtergraph-Manager, den Filter während der automatischen Grapherstellung zu ermitteln.
Im folgenden Beispiel wird der RLE-Encoderfilter in der Kategorie Videokompressor registriert. Ausführliche Informationen finden Sie unter Registrieren von DirectShow-Filtern. Lesen Sie unbedingt den Abschnitt Richtlinien zum Registrieren von Filtern, in dem die empfohlenen Methoden für die Filterregistrierung beschrieben werden.
// 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;
}
Außerdem müssen Filter nicht in DLLs gepackt werden. In einigen Fällen können Sie einen spezialisierten Filter schreiben, der nur für eine bestimmte Anwendung konzipiert ist. In diesem Fall können Sie die Filterklasse direkt in Ihrer Anwendung kompilieren und mit dem new
Operator erstellen, wie im folgenden Beispiel gezeigt:
#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;
}