步骤 4: 设置分配器属性

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

这是 编写转换筛选器教程的步骤 4。

注意

对于从 CTransInPlaceFilter 派生的筛选器,不需要此步骤。

 

在两个引脚就媒体类型达成一致后,它们为连接选择一个分配器,并协商分配器属性,例如缓冲区大小和缓冲区数。

CTransformFilter 类中,有两个分配器,一个用于上游引脚连接,一个用于下游引脚连接。 上游筛选器选择上游分配器,并选择分配器属性。 输入引脚接受上游筛选器决定的任何内容。 如果需要修改此行为,请重写 CBaseInputPin::NotifyAllocator 方法。

转换筛选器的输出引脚选择下游分配器。 它执行以下步骤:

  1. 如果下游筛选器可以提供分配器,则输出引脚使用该分配器。 否则,输出引脚会创建新的分配器。
  2. 如果有任何) ,则输出引脚通过调用 IMemInputPin::GetAllocatorRequirements 获取下游筛选器的分配器要求 (。
  3. 输出引脚调用转换筛选器的 CTransformFilter::D ecideBufferSize 方法,该方法是纯虚拟的。 此方法的参数是指向分配器的指针,以及具有下游筛选器要求的 ALLOCATOR_PROPERTIES 结构。 如果下游筛选器没有分配器要求,则结构将被清零。
  4. DecideBufferSize 方法中,派生类通过调用 IMemAllocator::SetProperties 来设置分配器属性。

通常,派生类会根据输出格式、下游筛选器的要求和筛选器自身的要求来选择分配器属性。 尝试选择与下游筛选器的请求兼容的属性。 否则,下游筛选器可能会拒绝连接。

在以下示例中,RLE 编码器设置缓冲区大小、缓冲区对齐方式和缓冲区计数的最小值。 对于前缀,它使用下游筛选器请求的任何值。 前缀通常为零字节,但某些筛选器需要它。 例如, AVI Mux 筛选器使用 前缀来写入 RIFF 标头。

HRESULT CRleFilter::DecideBufferSize(
    IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp)
{
    AM_MEDIA_TYPE mt;
    HRESULT hr = m_pOutput->ConnectionMediaType(&mt);
    if (FAILED(hr))
    {
        return hr;
    }

    ASSERT(mt.formattype == FORMAT_VideoInfo);
    BITMAPINFOHEADER *pbmi = HEADER(mt.pbFormat);
    pProp->cbBuffer = DIBSIZE(*pbmi) * 2; 
    if (pProp->cbAlign == 0)
    {
        pProp->cbAlign = 1;
    }
    if (pProp->cBuffers == 0)
    {
        pProp->cBuffers = 1;
    }
    // Release the format block.
    FreeMediaType(mt);

    // Set allocator properties.
    ALLOCATOR_PROPERTIES Actual;
    hr = pAlloc->SetProperties(pProp, &Actual);
    if (FAILED(hr)) 
    {
        return hr;
    }
    // Even when it succeeds, check the actual result.
    if (pProp->cbBuffer > Actual.cbBuffer) 
    {
        return E_FAIL;
    }
    return S_OK;
}

分配器可能无法完全匹配你的请求。 因此, SetProperties 方法以单独的 ALLOCATOR_PROPERTIES 结构 (Actual 参数返回实际结果,在前面的示例中) 。 即使 SetProperties 成功,也应检查结果,以确保它们满足筛选器的最低要求。

自定义分配器

默认情况下,所有筛选器类对其分配 器使用 CMemAllocator 类。 此类使用 VirtualAlloc) 从客户端进程的虚拟地址空间 (分配内存。 如果筛选器需要使用某种其他类型的内存(如 DirectDraw 图面),则可以实现自定义分配器。 可以使用 CBaseAllocator 类或编写全新的分配器类。 如果筛选器具有自定义分配器,请重写以下方法,具体取决于哪个引脚使用分配器:

如果另一个筛选器拒绝使用自定义分配器进行连接,则筛选器可能会使连接失败,或者与其他筛选器的分配器进行连接。 在后一种情况下,可能需要设置指示分配器类型的内部标志。 有关此方法的示例,请参阅 CDrawImage 类

下一 步:步骤 5。转换图像

编写 DirectShow 筛选器