提供自定义分配器

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

本部分介绍如何为筛选器提供自定义分配器。 仅介绍 IMemInputPin 连接,但 IAsyncReader 连接的步骤类似。

首先,为分配器定义 C++ 类。 分配器可以从标准分配器类之一 CBaseAllocatorCMemAllocator 派生,也可以创建全新的分配器类。 如果创建新类,它必须公开 IMemAllocator 接口。

其余步骤取决于分配器是属于筛选器上的输入引脚还是输出引脚。 在分配器协商阶段,输入引脚的作用与输出引脚不同,因为输出引脚最终会选择分配器。

为输入引脚提供自定义分配器

若要为输入引脚提供分配器,请重写输入引脚的 CBaseInputPin::GetAllocator 方法。 在此方法中,检查 m_pAllocator 成员变量。 如果此变量为非 NULL,则表示已为此连接选择了分配器,因此 GetAllocator 方法必须返回指向该分配器的指针。 如果 m_pAllocatorNULL,则表示尚未选择分配器,因此 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 方法。 但是,请注意,这可能会阻止输出引脚与某些筛选器连接,因为另一个筛选器可能还需要自己的自定义分配器。 第三个选项是切换顺序:首先尝试自定义分配器,然后回退到另一个筛选器的分配器。

谈判分配器