步骤 4: 设置分配器属性
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
这是 编写转换筛选器教程的步骤 4。
注意
对于从 CTransInPlaceFilter 派生的筛选器,不需要此步骤。
在两个引脚就媒体类型达成一致后,它们为连接选择一个分配器,并协商分配器属性,例如缓冲区大小和缓冲区数。
在 CTransformFilter 类中,有两个分配器,一个用于上游引脚连接,一个用于下游引脚连接。 上游筛选器选择上游分配器,并选择分配器属性。 输入引脚接受上游筛选器决定的任何内容。 如果需要修改此行为,请重写 CBaseInputPin::NotifyAllocator 方法。
转换筛选器的输出引脚选择下游分配器。 它执行以下步骤:
- 如果下游筛选器可以提供分配器,则输出引脚使用该分配器。 否则,输出引脚会创建新的分配器。
- 如果有任何) ,则输出引脚通过调用 IMemInputPin::GetAllocatorRequirements 获取下游筛选器的分配器要求 (。
- 输出引脚调用转换筛选器的 CTransformFilter::D ecideBufferSize 方法,该方法是纯虚拟的。 此方法的参数是指向分配器的指针,以及具有下游筛选器要求的 ALLOCATOR_PROPERTIES 结构。 如果下游筛选器没有分配器要求,则结构将被清零。
- 在 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 类或编写全新的分配器类。 如果筛选器具有自定义分配器,请重写以下方法,具体取决于哪个引脚使用分配器:
- 输入引脚: CBaseInputPin::GetAllocator 和 CBaseInputPin::NotifyAllocator。
- 输出引脚: CBaseOutputPin::D ecideAllocator。
如果另一个筛选器拒绝使用自定义分配器进行连接,则筛选器可能会使连接失败,或者与其他筛选器的分配器进行连接。 在后一种情况下,可能需要设置指示分配器类型的内部标志。 有关此方法的示例,请参阅 CDrawImage 类。
下一 步:步骤 5。转换图像。
相关主题