tanvon++

September 7, 2008

Enum the backbone of DirectShow Graph Building

Filed under: DirectShow, DirectShow Filters, Enum, Filters, Filters Enumeration — Tags: , — tanvon malik @ 4:32 pm

As a few last post are about enumeration, wether enumerating the Filter Categories or enumerating the filters in those categories or enumerating the filters pins.

Now comes another enumeration related post but this time we will enumerate all the filters in a given graph, this can be useful.

  • if you want to find some kind of info about all the filters.
  • want to find a specific interface but don’t know which filter implements that interface.
  • want to release all the filters in the filter graph.
here is the code about finding info about filter
HRESULT EnumFilters (IFilterGraph *pGraph)
{
    IEnumFilters *pEnum = NULL;
    IBaseFilter *pFilter;
    ULONG cFetched;

    HRESULT hr = pGraph->EnumFilters(&pEnum);
    if (FAILED(hr)) return hr;

    while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
    {
        FILTER_INFO FilterInfo;
        hr = pFilter->QueryFilterInfo(&FilterInfo);
        if (FAILED(hr))
        {
            MessageBox(NULL, TEXT("Could not get the filter info"),
                TEXT("Error"), MB_OK | MB_ICONERROR);
            continue;  // Maybe the next one will work.
        }

#ifdef UNICODE
        MessageBox(NULL, FilterInfo.achName, TEXT("Filter Name"), MB_OK);
#else
        char szName[MAX_FILTER_NAME];
        int cch = WideCharToMultiByte(CP_ACP, 0, FilterInfo.achName,
            MAX_FILTER_NAME, szName, MAX_FILTER_NAME, 0, 0);
        if (chh > 0)
            MessageBox(NULL, szName, TEXT("Filter Name"), MB_OK);
#endif

        // The FILTER_INFO structure holds a pointer to the Filter Graph
        // Manager, with a reference count that must be released.
        if (FilterInfo.pGraph != NULL)
        {
            FilterInfo.pGraph->Release();
        }
        pFilter->Release();
    }

    pEnum->Release();
    return S_OK;
}

here is the code to find a specific interface on a 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;
}

here is the code which releases all the filters in the DirectShow Filter
Graph
// Stop the graph.
pControl->Stop();

// Enumerate the filters in the graph.
IEnumFilters *pEnum = NULL;
HRESULT hr = pGraph->EnumFilters(&pEnum);
if (SUCCEEDED(hr))
{
    IBaseFilter *pFilter = NULL;
    while (S_OK == pEnum->Next(1, &pFilter, NULL))
     {
         // Remove the filter.
         pGraph->RemoveFilter(pFilter);
         // Reset the enumerator.
         pEnum->Reset();
         pFilter->Release();
    }
    pEnum->Release();
}

Enumerating the DirectShow Filter Pin

When it comes the time of connecting the DirectShow filters manually in DirectShow Filter Graph, at that time we admire the benefits of the Intelligent Connect. To connect a filter manually we have to built the entire filter graph with coding.

First of all a source filer have to be created the filter graph

IGraphBuilder *  pGB;
CoCreateInstance(CLSID_FilterGraph,NULL,
               CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&pGB);

then a Source Filter have to be added the filter graph, wether with CoCreateInstance() or with System Device Enumerator, All filters can’t be created with CoCreateInstance, Normally the filters which are wrapper to devices have to be created with the System Device Enumerator. But here a source filter is being added that will read the media data from a file from the disk.

IBaseFilter * pSF;
    pGB->AddSourceFilter(L"c:\\media\\video\\ruby.avi", L"Source Filter",
                                                                  &pSF);
    IEnumPins * pEP;
    pSF->EnumPins(&pEP);
    IPin * pOutPin;
    while(pEP->Next(1,&pOutPin,0) == S_OK)
    {
        PIN_DIRECTION pDir;
        pOutPin->QueryDirection(&pDir);
        if(pDir == PINDIR_OUTPUT)
            break;// success
        pOutPin->Release();
    }
    pEP->Release();

Now how to enumerate the pins, IBaseFilter has a method which makes it easy to enumerate the pins a filter have.

HRESULT EnumPins(
  IEnumPins **ppEnum
);

which gives us IEnumPins interface, with this interface you can easily enumerate the pins a filter have wether these are input pins or output pins. you first call Next then check for the pin direction.

HRESULT QueryDirection(
  PIN_DIRECTION *pPinDir
);

For direction checking  QueryDirection is called this method tells us the pin direction.

Now you can call IGraphBuilder::Render to built the entire graph.

HRESULT Render(
  IPin *ppinOut
);
this method takes the output pin to be rendered.
or you can call IGraphBuilder::Connect to directly connect the 
output pin to a downstream filters input pin.
HRESULT Connect(
  IPin *ppinOut,
  IPin *ppinIn
);

August 30, 2008

Enumerating DirectShow Filters

Filed under: DirectShow, DirectShow Filters, Enum, Filters, Filters Enumeration, System Device Enumerator — Tags: , , — tanvon malik @ 11:06 am

System Device Enumerator

Wether you locating for a particular filter or want to enumerate all the filters on a system. The System Device Enumerator is a big help. Enumeration of DirectShow filters can be achieved with the help of System Device Enumerator. It is COM object. which expose ICreateDevEnum interface. It means first you have to create the System Device Enumerator object, then you will grab its interface ICreateDevEnum , this interface exposes just one method CreateClassEnumerator this method actually creates  enumerator, which can be used to enumerate the filters in a specific Filter Category, or can be used to enumerate all the Filter Categories on a users system.

Filter Categories

Filter in DirectShow are divided in the categories . Every category has its own class identifier called a CLSID. With the help of this CLSID it is easy to enumerate the filters of that specific class.

But first of all how to enumerate those categories, for this purpose there is a CLSID_ActiveMovieCategories CLSID. With it one can easily enumerate the categories which has filters in them.

HRESULT hr;
    ICreateDevEnum *pSysDevEnum = NULL;
    hr = CoCreateInstance(CLSID_SystemDeviceEnum,
                           NULL, CLSCTX_INPROC_SERVER,
                           IID_ICreateDevEnum, (void **)&pSysDevEnum);
    if (FAILED(hr))
    {
        return hr;
    }
    IEnumMoniker *pEnumCat = NULL;
    hr = pSysDevEnum->CreateClassEnumerator(
                       (GUID)CLSID_ActiveMovieCategories, &pEnumCat, 0);
    if (hr == S_OK)
    {
        // Enumerate the monikers.
        IMoniker *pMoniker = NULL;
        ULONG cFetched;
        while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
        {
            IPropertyBag *pPropBag;
            hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
                (void **)&pPropBag);
            if (SUCCEEDED(hr))
            {
                VARIANT varName, varCLSID;
                VariantInit(&varName);
                VariantInit(&varCLSID);
                hr = pPropBag->Read(L"FriendlyName", &varName, 0);
                if (SUCCEEDED(hr))
                {
                    hr = pPropBag->Read(L"CLSID", &varCLSID, 0);
                    if (SUCCEEDED(hr))
                    {
                        GUID clsid;
                        if (SUCCEEDED(CLSIDFromString(varCLSID.bstrVal,
                                                               &clsid)))
                        {
                            EnumFilters(clsid, hparent);

 

this snippet of code shows how to enumerate all the filter categories. Now you have all the filter categories it is time to enumerate the filters in those filter categories.

bool CEnumFiltersDlg::EnumFilters(GUID clsid, HTREEITEM hparent)
{
        // Create the System Device Enumerator.
    HRESULT hr;
    ICreateDevEnum *pSysDevEnum = NULL;
    hr = CoCreateInstance(CLSID_SystemDeviceEnum,
                           NULL, CLSCTX_INPROC_SERVER,
                           IID_ICreateDevEnum, (void **)&pSysDevEnum);
    if (FAILED(hr))
    {
        return hr;
    }
    IEnumMoniker *pEnumCat = NULL;
    hr = pSysDevEnum->CreateClassEnumerator((GUID)clsid, &pEnumCat, 0);
    if (hr == S_OK)
    {
        IMoniker *pMoniker = NULL;
        ULONG cFetched;
        while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
        {
            IPropertyBag *pPropBag;
            hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
                (void **)&pPropBag);
            if (SUCCEEDED(hr))
            {
            // To retrieve the filter's friendly name, do the following:
                VARIANT varName;
                VariantInit(&varName);
                hr = pPropBag->Read(L"FriendlyName", &varName, 0);
                if (SUCCEEDED(hr))
                {
                    // Display the name in your UI somehow.
                    TVINSERTSTRUCT tvInsert;
                    tvInsert.hParent = hparent;
                    tvInsert.hInsertAfter = NULL;
                    tvInsert.item.mask = TVIF_TEXT;
                    CString str(varName.bstrVal);
                    tvInsert.item.pszText = str.GetBuffer();
                    str.ReleaseBuffer();
                    mFiltersTree.InsertItem(&tvInsert);
                }

                VariantClear(&varName);
                pPropBag->Release();
            }
            pMoniker->Release();
        }
        pEnumCat->Release();
    }
    pSysDevEnum->Release();

    mFiltersTree.SortChildren(hparent);
    return true;
}

Here clsid parameter passed is the CLSID of the filter category whom  to enumerate.

NOTEenumerate DirectShow Filters

       this sample don’t enumerate the DMOs on a system as the Graph Edit utility enumerates in its insert filter function. I will try to add it later.

code can be found here

August 16, 2008

System Device Enumerator

Filed under: DirectShow, DirectShow Filters — Tags: , — tanvon malik @ 6:21 pm

Another interesting question on tanvon Yahoo Group is,
” Could any one tell me how to go about listing all the DirectShow
Filter Categories so that i can list the filters under each category.”
There are two ways to enumerate the filters the Filter Mapper way and the System Device Enumerator way.
Here I will explain the System Device Enumerator.
The System Device Enumerator is a COM object, which implements the ICreateDevEnum interface,
this intreface exposes only a single method CreateClassEnumerator. This is the method which creates the enumerator object and returns its IEnumMoniker interface, but enumerate what
HRESULT CreateClassEnumerator(
  REFCLSID clsidDeviceClass,
  IEnumMoniker **ppEnumMoniker,
  DWORD dwFlags
);
The first parameter is the class identifier (CLSID) of the device category. these categories are defined in the Dshow.h header file. (e.g. CLSID_LegacyAmFilterCategory , CLSID_AudioRendererCategory ). This is the place to notice that you have to specify which category you want to enumerate.
Once you have the IEnumMoniker, now you can use its methods to easily enumerate the device category. Just call IEnumMoniker::Next  method, this will return an IMoniker interface with this interface you can get the “Friendly Name” of the filter or you can instanciate the filter itself.
For an example see http://msdn.microsoft.com/en-us/library/ms787871(VS.85).aspx

For the URDU version see http://directshow.wordpress.com/2008/08/16/system-device-enumerator/

Blog at WordPress.com.