Поделиться через


Предоставление пользовательского распределителя

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

В этом разделе описывается, как предоставить пользовательский распределитель для фильтра. Описываются только подключения IMemInputPin , но действия для подключения IAsyncReader аналогичны.

Сначала определите класс C++ для распределителя. Распределитель может быть производным от одного из стандартных классов распределителя , CBaseAllocator или CMemAllocator, или вы можете создать совершенно новый класс распределителя. При создании нового класса он должен предоставлять интерфейс IMemAllocator .

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

Предоставление пользовательского распределителя для пин-кода ввода

Чтобы предоставить распределитель для пин-кода ввода, переопределите метод CBaseInputPin::GetAllocator . В этом методе проверка переменную-член m_pAllocator. Если эта переменная не имеет значение NULL, это означает, что для этого подключения уже выбран распределитель, поэтому метод GetAllocator должен возвращать указатель на этот распределитель. Если m_pAllocator имеет значение NULL, это означает, что распределитель не выбран, поэтому метод GetAllocator должен возвращать указатель на предпочтительный распределитель входного контакта. В этом случае создайте экземпляр пользовательского распределителя и верните его указатель IMemAllocator . В следующем коде показано, как реализовать метод GetAllocator :

STDMETHODIMP CMyInputPin::GetAllocator(IMemAllocator **ppAllocator)
{
    CheckPointer(ppAllocator, E_POINTER);
    if (m_pAllocator)  
    {
        // We already have an allocator, so return that one.
        *ppAllocator = m_pAllocator;
        (*ppAllocator)->AddRef();
        return S_OK;
    }

    // No allocator yet, so propose our custom allocator. The exact code
    // here will depend on your custom allocator class definition.
    HRESULT hr = S_OK;
    CMyAllocator *pAlloc = new CMyAllocator(&hr);
    if (!pAlloc)
    {
        return E_OUTOFMEMORY;
    }
    if (FAILED(hr))
    {
        delete pAlloc;
        return hr;
    }

    // Return the IMemAllocator interface to the caller.
    return pAlloc->QueryInterface(IID_IMemAllocator, (void**)ppAllocator);
}

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

Предоставление пользовательского распределителя для выходного пин-кода

Чтобы предоставить распределитель для пин-кода вывода, переопределите метод CBaseOutputPin::InitAllocator , чтобы создать экземпляр распределителя:

HRESULT MyOutputPin::InitAllocator(IMemAllocator **ppAllocator)
{
    HRESULT hr = S_OK;
    CMyAllocator *pAlloc = new CMyAllocator(&hr);
    if (!pAlloc)
    {
        return E_OUTOFMEMORY;
    }

    if (FAILED(hr))
    {
        delete pAlloc;
        return hr;
    }

    // Return the IMemAllocator interface.
    return pAlloc->QueryInterface(IID_IMemAllocator, (void**)ppAllocator);
}

По умолчанию класс CBaseOutputPin сначала запрашивает распределитель из контактного ввода. Если этот распределитель не подходит, выходной контакт создает собственный распределитель. Чтобы принудительно использовать пользовательский распределитель, переопределите метод CBaseOutputPin::D ecideAllocator . Однако имейте в виду, что это может помешать выходному контакту подключаться к определенным фильтрам, так как для другого фильтра также может потребоваться собственный пользовательский распределитель. Третий вариант — изменить порядок. Сначала попробуйте пользовательский распределитель, а затем вернитесь к распределителю другого фильтра.

Согласование распределителей