设置视频压缩属性

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

视频压缩筛选器可以在其输出引脚上支持 IAMVideoCompression 接口。 使用此接口可设置压缩属性,例如关键帧速率、每个关键帧预测 (P) 帧数以及相对压缩质量。

首先,调用 IBaseFilter::EnumPins 方法来查找筛选器的输出引脚,并查询接口的引脚。 某些筛选器可能根本不支持 接口。 其他可能公开 接口,但不支持每个压缩属性。 若要确定支持的属性,请调用 IAMVideoCompression::GetInfo。 此方法返回几条信息:

  • 一组功能标志
  • 描述性字符串和版本号字符串
  • 支持的关键帧速率、P 帧速率和质量 (的默认值)

方法具有以下语法:

hr = pCompress->GetInfo(pszVersion, &cbVersion, pszDesc, &cbDesc, 
         &lKeyFrame, &lPFrame, &dblQuality, &lCap);

pszVersionpszDesc 参数是接收版本字符串和说明字符串的宽字符缓冲区。 cbVersioncbDesc 参数接收所需的缓冲区大小(以字节为单位 (而不是字符) 。 lKeyFramelPFramedblQuality 参数接收关键帧速率、P 帧速率和质量的默认值。 质量表示为 0.0 到 1.0 的浮点数。 lCap 参数接收由 CompressionCaps 枚举类型定义的功能标志的按位 OR

这些参数中的任何一个都可以为 NULL,在这种情况下,方法将忽略该参数。 例如,若要为版本和说明字符串分配缓冲区,请先在第一个和第三个参数中使用 NULL 调用 方法。 使用 cbVersioncbDesc 的返回值分配缓冲区,然后再次调用 方法:

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 方法是一种帮助程序方法,用于在图中搜索筛选器和固定以查找指定接口。