设置视频压缩属性
[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayer、 IMFMediaEngine 和 音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
视频压缩筛选器可以在其输出引脚上支持 IAMVideoCompression 接口。 使用此接口可设置压缩属性,例如关键帧速率、每个关键帧预测 (P) 帧数以及相对压缩质量。
首先,调用 IBaseFilter::EnumPins 方法来查找筛选器的输出引脚,并查询接口的引脚。 某些筛选器可能根本不支持 接口。 其他可能公开 接口,但不支持每个压缩属性。 若要确定支持的属性,请调用 IAMVideoCompression::GetInfo。 此方法返回几条信息:
- 一组功能标志
- 描述性字符串和版本号字符串
- 支持的关键帧速率、P 帧速率和质量 (的默认值)
方法具有以下语法:
hr = pCompress->GetInfo(pszVersion, &cbVersion, pszDesc, &cbDesc,
&lKeyFrame, &lPFrame, &dblQuality, &lCap);
pszVersion 和 pszDesc 参数是接收版本字符串和说明字符串的宽字符缓冲区。 cbVersion 和 cbDesc 参数接收所需的缓冲区大小(以字节为单位 (而不是字符) 。 lKeyFrame、lPFrame 和 dblQuality 参数接收关键帧速率、P 帧速率和质量的默认值。 质量表示为 0.0 到 1.0 的浮点数。 lCap 参数接收由 CompressionCaps 枚举类型定义的功能标志的按位 OR。
这些参数中的任何一个都可以为 NULL,在这种情况下,方法将忽略该参数。 例如,若要为版本和说明字符串分配缓冲区,请先在第一个和第三个参数中使用 NULL 调用 方法。 使用 cbVersion 和 cbDesc 的返回值分配缓冲区,然后再次调用 方法:
int cbVersion, cbDesc; // Size in bytes, not characters!
hr = pCompress->GetInfo(0, &cbVersion, 0, &cbDesc, 0, 0, 0, 0);
if (SUCCEEDED(hr))
{
WCHAR *pszVersion = new WCHAR[cbVersion/2]; // Wide character = 2 bytes
WCHAR *pszDesc = new WCHAR[cbDesc/2];
hr = pCompress->GetInfo(pszVersion, 0, pszDesc, 0, 0, 0, 0, 0);
}
lCap 的值指示筛选器支持的其他 IAMVideoCompression 方法。 例如,如果 lCap 包含 CompressionCaps_CanKeyFrame 标志,则可以调用 IAMVideoCompression::get_KeyFrameRate 来获取关键帧速率,并调用 IAMVideoCompression::p ut_KeyFrameRate 来设置关键帧速率。 负值表示筛选器将使用从 IAMVideoCompression::GetInfo 获取的默认值。 例如:
if (lCap & CompressionCaps_CanKeyFrame)
{
hr = pCompress->get_KeyFrameRate(&lKeyFrame);
if (FAILED(hr) || lKeyFrame < 0)
{
lKeyFrame = lDefaultKeyFrame; // From GetInfo.
}
}
下面的代码示例尝试在输出引脚上查找 IAMVideoCompression 接口。 如果成功,它将检索压缩属性的默认值和实际值:
HRESULT hr = E_FAIL;
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
IAMVideoCompression *pCompress = NULL;
// Find the pin that supports IAMVideoCompression (if any).
pFilter->EnumPins(&pEnum);
while (S_OK == pEnum->Next(1, &pPin, NULL))
{
hr = pPin->QueryInterface(IID_IAMVideoCompression, (void**)&pCompress);
pPin->Release();
if (SUCCEEDED(hr)) // Found the interface.
{
break;
}
}
if (SUCCEEDED(hr))
{
long lCap; // Capability flags
long lKeyFrame, lPFrame; // Real values
double m_Quality;
long lKeyFrameDef, lPFrameDef; // Default values
double QualityDef;
// Get default values and capabilities.
hr = pCompress->GetInfo(0, 0, 0, 0, &KeyFrameDef, &lPFrameDef,
&QualityDef, &lCap);
if (SUCCEEDED(hr))
{
// Get actual values where possible.
if (lCap & CompressionCaps_CanKeyFrame)
{
hr = pCompress->get_KeyFrameRate(&lKeyFrame);
if (FAILED(hr) || lKeyFrame < 0)
lKeyFrame = lKeyFrameDef;
}
if (lCap & CompressionCaps_CanBFrame)
{
hr = pCompress->get_PFramesPerKeyFrame(&lPFrame);
if (FAILED(hr) || lPFrame < 0)
lPFrame = lPFrameDef;
}
if (lCap & CompressionCaps_CanQuality)
{
hr = pCompress->get_Quality(&Quality);
if (FAILED(hr) || Quality < 0)
Quality = QualityDef;
}
}
}
注意
如果使用 ICaptureGraphBuilder2 接口生成图形,可以通过调用 ICaptureGraphBuilder2::FindInterface 而不是使用 IBaseFilter::EnumPins 来获取 IAMVideoCompression 接口。 FindInterface 方法是一种帮助程序方法,用于在图中搜索筛选器和固定以查找指定接口。