Шаг 6. Добавление поддержки COM

[Функция, связанная с этой страницей, DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngineи аудио- и видеозахватом в технологии Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать новый код MediaPlayer, IMFMediaEngine и аудио-видеозахват в Media Foundation вместо DirectShowпо возможности. Корпорация Майкрософт предлагает, что существующий код, использующий устаревшие API, будет перезаписан для использования новых API, если это возможно.]

Это шаг 6 руководства по созданию фильтров преобразования.

Последний шаг — добавить поддержку COM.

Подсчет ссылок

Вам не нужно реализовать IUnknown::AddRef или IUnknown::Release. Все классы фильтров и закреплений являются производными от CUnknown, которая обрабатывает подсчет ссылок.

QueryInterface

Все классы фильтров и привязок реализуют IUnknown::QueryInterface для любых наследуемых COM-интерфейсов. Например, CTransformFilter наследует IBaseFilter (через CBaseFilter). Если фильтр не предоставляет никаких дополнительных интерфейсов, вам не нужно ничего делать.

Чтобы предоставить дополнительные интерфейсы, переопределите метод CUnknown::NonDelegatingQueryInterface. Например, предположим, что фильтр реализует пользовательский интерфейс с именем IMyCustomInterface. Чтобы предоставить этот интерфейс клиентам, сделайте следующее:

  • Наследуйте класс фильтра из этого интерфейса.
  • Поместите макрос DECLARE_IUNKNOWN в раздел общедоступного объявления.
  • Переопределите NonDelegatingQueryInterface, чтобы проверить IID вашего интерфейса и вернуть указатель на ваш фильтр.

В следующем коде показаны следующие действия.

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);
}

Дополнительные сведения см. в разделе How to Implement IUnknown.

Создание объекта

Если вы планируете упаковать фильтр в библиотеку DLL и сделать его доступным для других клиентов, необходимо поддерживать CoCreateInstance и другие связанные функции COM. Библиотека базовых классов реализует большую часть этого. Вам просто нужно предоставить некоторые сведения о фильтре. В этом разделе представлен краткий обзор действий. Дополнительные сведения см. в статье Как создать DLL-фильтр DirectShow.

Сначала напишите метод статического класса, который возвращает новый экземпляр фильтра. Вы можете присвоить этому методу любое имя, но подпись должна соответствовать той, что показана в следующем примере:

CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
    CRleFilter *pFilter = new CRleFilter();
    if (pFilter== NULL) 
    {
        *pHr = E_OUTOFMEMORY;
    }
    return pFilter;
}

Затем объявите глобальный массив экземпляров классов CFactoryTemplate с именем g_Templates. Каждый класс CFactoryTemplate содержит сведения о реестре для одного фильтра. Несколько фильтров могут находиться в одной библиотеке DLL. Просто добавьте дополнительные записи CFactoryTemplate. Вы также можете объявить другие COM-объекты, такие как страницы свойств.

static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] = 
{
  { 
    g_wszName,
    &CLSID_RLEFilter,
    CRleFilter::CreateInstance,
    NULL,
    NULL
  }
};

Определите глобальное целое число с именем g_cTemplates, значение которого равно длине массива g_Templates:

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);  

Наконец, реализуйте функции регистрации DLL. В следующем примере показана минимальная реализация этих функций:

STDAPI DllRegisterServer()
{
    return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
    return AMovieDllRegisterServer2( FALSE );
}

Фильтрация записей реестра

В предыдущих примерах показано, как зарегистрировать CLSID фильтра для COM. Для многих фильтров это достаточно. Затем клиент должен создать фильтр с помощью CoCreateInstance и добавить его в граф фильтров путем вызова IFilterGraph::AddFilter. Однако в некоторых случаях может потребоваться предоставить дополнительные сведения о фильтре в реестре. Эта информация выполняет следующие действия.

В следующем примере регистрируется фильтр кодировщика RLE в категории видеокомпрессора. Дополнительные сведения см. в разделе Регистрация фильтров DirectShow. Обязательно ознакомьтесь с разделом руководства по регистрации фильтров, в котором описаны рекомендуемые методики регистрации фильтров.

// 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;
}

Кроме того, фильтры не должны упаковываться в библиотеки DLL. В некоторых случаях можно написать специализированный фильтр, предназначенный только для конкретного приложения. В этом случае можно скомпилировать класс фильтра непосредственно в приложении и создать его с помощью оператора new, как показано в следующем примере:

#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;
}

Intelligent Connect

написание фильтров DirectShow

Написание фильтров преобразования