There are generally three steps to creating an DShow application:
1. Create a Filter Graph Manager component.
Igraphbuilder * pgraph = NULL;
HRESULT hr = CoCreateInstance (Clsid_filtergraph, NULL,
Clsctx_inproc_server, Iid_igraphbuilder, (void**) &pgraph);
2. According to the actual application, create a filter chain, such as playing a local file, the simplest and fastest code is as follows:
hr = Pgraph->renderfile (L "path", NULL);
3. Call the various interfaces on the Filter Graph manager to control and complete the interaction of the filter Graph manager with the application, such as invoking the IMediaControl interface method to control the state transitions of the filter graph.
IMediaControl *pcontrol = NULL;
hr = Pgraph->queryinterface (Iid_imediacontrol, (void**) Pcontrol);
hr = Pcontrol->run ();
Common Filter Graph construction techniques:
1. Add a filter for the specified CLSID
Given the CLSID of a filter, you can call CoCreateInstance to create it. and add it to the filter graph using the Ifiltergraph::addfilter interface.
The code is as follows:
HRESULT Addfilterbyclsid ( igraphbuilder *pgraph, //Pointer to the Filter Graph Manager. Const guid& CLSID, //CLSID of the filter to create. LPCWSTR Wszname, //A name for the filter. Ibasefilter **PPF) //receives a pointer to the filter.{ if (!pgraph | |! PpF) return e_pointer; *PPF = 0; Ibasefilter *PF = 0; HRESULT hr = CoCreateInstance (CLSID, 0, Clsctx_inproc_server, Iid_ibasefilter, reinterpret_cast<void**> ( &PF)); if (SUCCEEDED (HR)) { hr = Pgraph->addfilter (PF, wszname); if (SUCCEEDED (HR)) *PPF = PF; else pf->release (); } return HR;}
To add an AVI Mux filter to the filter graph
Ibasefilter *pmux;
hr = Addfilterbyclsid (pgraph, Clsid_avidest, L "AVI Mux", &pmux);
if (SUCCEEDED (HR))
{
/*...*/
Pmux->release ();
}
2. Get the disconnected pin on the filter
When you connect a filter to a program, you first get the PIN or output pin that is not connected to the filter. The method is to enumerate all the pins on the filter and call the Ipin::querydirection to query the direction of the pin. Then call Ipin::connectedto to view the connection status of the PIN.
HRESULT Getunconnectedpin (Ibasefilter *pfilter,//Pointer to the filter. Pin_direction Pindir,//DIRECTION of the pin to find. Ipin **pppin)//receives a pointer to the PIN. {*pppin = 0; Ienumpins *penum = 0; Ipin *ppin = 0; HRESULT hr = Pfilter->enumpins (&penum); if (FAILED (HR)) {return hr; } while (Penum->next (1, &ppin, NULL) = = S_OK) {pin_direction thispindir; Ppin->querydirection (&thispindir); if (Thispindir = = Pindir) {Ipin *ptmp = 0; hr = Ppin->connectedto (&ptmp); if (SUCCEEDED (HR))//already connected, not the pin we want. {ptmp->release (); } else//unconnected, this is the pin we want. {penum->release (); *pppin = Ppin; return S_OK; }} ppin->release (); } penum->release (); // Did not find a matching pin. return E_FAIL;}
For example, now to get an output pin that is not connected
Ipin *pout = NULL;
HRESULT hr = Getunconnectedpin (PFilter, Pindir_output, &pout);
if (SUCCEEDED (HR))
{
/*...*/
Pout->release ();
}
3. Connect two filter
The functions that connect two filter in filter graph are ifiltergraph::connectdirect and ifiltergraph::connect
HRESULT connectfilters ( igraphbuilder *pgraph,//Filter Graph Manager. Ipin *pout, //Output pin on the upstream filter. Ibasefilter *pdest) //downstream filter.{ if ((pgraph = = NULL) | | (POut = = NULL) | | (PDest = = NULL)) { return e_pointer; } #ifdef Debug pin_direction pindir; Pout->querydirection (&pindir); _asserte (Pindir = = pindir_output); #endif //Find an input pin on the downstream filter. Ipin *pin = 0; HRESULT hr = Getunconnectedpin (pDest, Pindir_input, &pin); if (FAILED (HR)) { return hr; } Try to connect them. hr = Pgraph->connect (POut, pIn); Pin->release (); return HR;}
function overloads for connectfilters of different parameters:
HRESULT connectfilters ( igraphbuilder *pgraph, ibasefilter *psrc, ibasefilter *pdest) { if (pgraph = = NULL) | | (PSRC = = NULL) | | (PDest = = NULL)) { return e_pointer; } The Find an output pin is on the first filter. Ipin *pout = 0; HRESULT hr = Getunconnectedpin (PSRC, Pindir_output, &pout); if (FAILED (HR)) { return hr; } hr = Connectfilters (pgraph, POut, pDest); Pout->release (); return HR;}
For example, now add an AVI Mux filter and a file Writer filter, and then connect them together. The code is as follows:
Ibasefilter *pmux, *pwrite;
hr = Addfilterbyclsid (pgraph, Clsid_avidest, L "AVI Mux", &pmux);
if (SUCCEEDED (HR))
{
hr = Addfilterbyclsid (pgraph, Clsid_filewriter, L "File Writer", &pwrite);
if (SUCCEEDED (HR))
{
hr = Connectfilters (pgraph, Pmux, pwrite);
Pwrite->release ();
}
Pmux->release ();
}
4. Find the interface on the filter and PIN
We need to enumerate all the filter in graph, or enumerate all the pins on the filter, one for the interface.
Find an interface implemented on the filter
HRESULT findfilterinterface ( igraphbuilder *pgraph,//Pointer to the Filter Graph Manager. Refguid IID, //IID of the interface to retrieve. void **ppunk) //Receives the interface pointer.{ if (!pgraph | |!ppunk) return e_pointer; HRESULT hr = E_FAIL; Ienumfilters *penum = NULL; Ibasefilter *PF = NULL; if (FAILED (Pgraph->enumfilters (&penum))) { return e_fail; } Query every filter for the interface. while (S_OK = = Penum->next (1, &PF, 0)) { hr = Pf->queryinterface (IID, ppunk); Pf->release (); if (SUCCEEDED (HR)) {break ; } } Penum->release (); return HR;}
Finds an interface implemented on the pin of a given filter
HRESULT findpininterface ( ibasefilter *pfilter, //Pointer to the filter to search. Refguid IID, //IID of the interface. void **ppunk) //Receives the interface pointer.{ if (!pfilter | |!ppunk) return e_pointer; HRESULT hr = E_FAIL; Ienumpins *penum = 0; if (FAILED (Pfilter->enumpins (&penum))) { return e_fail; } Query every pin for the interface. Ipin *ppin = 0; while (S_OK = = Penum->next (1, &ppin, 0)) { hr = Ppin->queryinterface (IID, ppunk); Ppin->release (); if (SUCCEEDED (HR)) {break ; } } Penum->release (); return HR;}
Combined functions of two functions of Findfilterinterface and Findpininterfae
HRESULT findinterfaceanywhere ( igraphbuilder *pgraph, refguid iid, void **ppunk) { if (!pgraph | |! Ppunk) return e_pointer; HRESULT hr = E_FAIL; Ienumfilters *penum = 0; if (FAILED (Pgraph->enumfilters (&penum))) { return e_fail; } Loop through every filter in the graph. Ibasefilter *PF = 0; while (S_OK = = Penum->next (1, &PF, 0)) { hr = Pf->queryinterface (IID, ppunk); if (FAILED (HR)) { //The filter does not expose the interface, but maybe //one of its pins does. hr = Findpininterface (PF, IID, ppunk); } Pf->release (); if (SUCCEEDED (HR)) {break ; } } Penum->release (); return HR;}
For example, through the Igraphbuilder::renderfile function, a playback link of AVI file containing DV format data is constructed. We want to get a DV video decoding filter on the Iipdvdec interface to set the DV decoding output to the image size of the original image of One-fourth, the code is as follows:
hr = Pgraph->renderfile (L "C:\\example.avi", 0);
if (SUCCEEDED (HR))
{
iipdvdec* Pdvdec;
hr = Findfilterinterface (Pgraph, Iid_iipdvdec, (void**) &pdvdec);
if (SUCCEEDED (HR))
{
........
}
}
5. Traverse the filter link
Given a filter on a filter link, we can get all the other filter up or down.
HRESULT Getnextfilter (Ibasefilter *pfilter,//Pointer to the starting filter pin_direction Dir,//DIRECTION to Search (upstream or downstream) Ibasefilter **ppnext)//receives a pointer to the next filter. {if (!pfilter | |!ppnext) return e_pointer; Ienumpins *penum = 0; Ipin *ppin = 0; HRESULT hr = Pfilter->enumpins (&penum); if (FAILED (HR)) return HR; while (S_OK = = Penum->next (1, &ppin, 0)) {//See if this pin matches the specified direction. Pin_direction Thispindir; hr = Ppin->querydirection (&thispindir); if (FAILED (HR)) {//Something strange happened. hr = e_unexpected; Ppin->release (); Break } if (Thispindir = = Dir) {//Check if the pin is connected to another pin. Ipin *ppinnext = 0; hr = Ppin->connectedto (&ppinnext); if (SUCCEEDED (HR)) {// Get the filter that owns that pin. Pin_info Pininfo; hr = Ppinnext->querypininfo (&pininfo); Ppinnext->release (); Ppin->release (); Penum->release (); if (FAILED (hr) | | (Pininfo.pfilter = = NULL)) {//Something strange happened. return e_unexpected; }//This is the filter we ' re looking for. *ppnext = Pininfo.pfilter; Client must release. return S_OK; }} ppin->release (); } penum->release (); Did not find a matching filter. return E_FAIL;}
Create a DirectShow application