Passaggio 6. Aggiungere il supporto per COM
[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation invece di DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.
Questo è il passaggio 6 dell'esercitazione Scrittura di filtri di trasformazione.
Il passaggio finale consiste nell'aggiungere il supporto per COM.
Conteggio riferimenti
Non è necessario implementare IUnknown::AddRef o IUnknown::Release. Tutte le classi di filtro e pin derivano da CUnknown, che gestisce il conteggio dei riferimenti.
QueryInterface
Tutte le classi di filtro e pin implementano IUnknown::QueryInterface per tutte le interfacce COM che ereditano. Ad esempio, CTransformFilter eredita IBaseFilter (tramite CBaseFilter). Se il filtro non espone interfacce aggiuntive, non è necessario eseguire altre operazioni.
Per esporre interfacce aggiuntive, eseguire l'override del metodo CUnknown::NonDelegatingQueryInterface . Si supponga, ad esempio, che il filtro implementi un'interfaccia personalizzata denominata IMyCustomInterface. Per esporre questa interfaccia ai client, eseguire le operazioni seguenti:
- Derivare la classe di filtro da tale interfaccia.
- Inserire la macro DECLARE_IUNKNOWN nella sezione dichiarazione pubblica.
- Eseguire l'override di NonDelegatingQueryInterface per verificare la presenza dell'IID dell'interfaccia e restituire un puntatore al filtro.
Il codice seguente illustra questi passaggi:
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);
}
Per altre informazioni, vedere Come implementare IUnknown.
Creazione di oggetti
Se si prevede di creare un pacchetto del filtro in una DLL e renderlo disponibile per altri client, è necessario supportare CoCreateInstance e altre funzioni COM correlate. La libreria di classi di base implementa la maggior parte di questo; è sufficiente fornire alcune informazioni sul filtro. Questa sezione offre una breve panoramica delle operazioni da eseguire. Per informazioni dettagliate, vedere Come creare una DLL del filtro DirectShow.
In primo luogo, scrivere un metodo di classe statico che restituisce una nuova istanza del filtro. È possibile assegnare un nome a questo metodo, ma la firma deve corrispondere a quella illustrata nell'esempio seguente:
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
Dichiarare quindi una matrice globale di istanze della classe CFactoryTemplate denominata g_Templates. Ogni classe CFactoryTemplate contiene informazioni sul Registro di sistema per un filtro. Diversi filtri possono risiedere in una singola DLL; includere semplicemente voci CFactoryTemplate aggiuntive. È anche possibile dichiarare altri oggetti COM, ad esempio le pagine delle proprietà.
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
Definire un numero intero globale denominato g_cTemplates il cui valore è uguale alla lunghezza della matrice g_Templates :
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
Infine, implementare le funzioni di registrazione dll. L'esempio seguente illustra l'implementazione minima per queste funzioni:
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
Filtrare le voci del Registro di sistema
Negli esempi precedenti viene illustrato come registrare il CLSID di un filtro per COM. Per molti filtri, questo è sufficiente. Il client dovrebbe quindi creare il filtro usando CoCreateInstance e aggiungerlo al grafo del filtro chiamando IFilterGraph::AddFilter. In alcuni casi, tuttavia, potrebbe essere necessario fornire informazioni aggiuntive sul filtro nel Registro di sistema. Queste informazioni sono le seguenti:
- Consente ai client di individuare il filtro usando filtro mapper o l'enumeratore del dispositivo di sistema.
- Consente a Filter Graph Manager di individuare il filtro durante la compilazione automatica del grafico.
Nell'esempio seguente viene registrato il filtro del codificatore RLE nella categoria compressore video. Per informazioni dettagliate, vedere Come registrare i filtri DirectShow. Assicurarsi di leggere la sezione Linee guida per la registrazione dei filtri, che descrive le procedure consigliate per la registrazione dei filtri.
// 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;
}
Inoltre, i filtri non devono essere inseriti all'interno di DLL. In alcuni casi, è possibile scrivere un filtro specializzato progettato solo per un'applicazione specifica. In tal caso, è possibile compilare la classe di filtro direttamente nell'applicazione e crearla con l'operatore new
, come illustrato nell'esempio seguente:
#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;
}
Argomenti correlati