设置去交错首选项

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

(VMR) 的视频混合呈现器支持硬件加速的去交错,从而提高交错视频的呈现质量。 可用的确切功能取决于基础硬件。 应用程序可以通过 IVMRDeinterlaceControl 接口 (VMR-7) 或 IVMRDeinterlaceControl9 接口 (VMR-9) 来查询硬件去隔行功能并设置去交错首选项。 按流执行去交错。

VMR-7 和 VMR-9 之间的交错行为有一个重要区别。 在图形硬件不支持高级去交错的系统上,VMR-7 可以回退到硬件覆盖层,并指示它使用 BOB 样式的去交错。 在这种情况下,尽管 VMR 报告了 30fps,但视频实际上以每秒 60 次翻转的速度呈现。

除使用硬件覆盖的 VMR-7 的情况外,由 VMR 的混音器执行去交错。 混音器使用 DirectX 视频加速 (DXVA) 去交错设备驱动程序接口 (DDI) 来执行去交错。 应用程序不可调用此 DDI,并且应用程序无法替换 VMR 的反交错功能。 但是,应用程序可以选择所需的去交错模式,如本部分所述。

注意

本部分介绍 IVMRDeinterlaceControl9 方法,但 VMR-7 版本几乎相同。

 

若要获取视频流的去隔行功能,请执行以下操作:

  1. 使用视频流的说明填充 VMR9VideoDesc 结构。 稍后会提供有关如何填充此结构的详细信息。
  2. 将 结构传递给 IVMRDeinterlaceControl9::GetNumberOfDeinterlaceModes 方法。 调用方法两次。 第一个调用返回硬件支持的指定格式的反交错模式数。 分配此大小的 GUID 数组,然后再次调用 方法,传入数组的地址。 第二次调用使用 GUID 填充数组。 每个 GUID 标识一个去交错模式。
  3. 若要获取特定模式的值,请调用 IVMRDeinterlaceControl9::GetDeinterlaceModeCaps 方法。 传入相同的 VMR9VideoDesc 结构,以及数组中的一个 GUID。 方法使用 模式功能填充 VMR9DeinterlaceCaps 结构。

以下代码演示了这些步骤:

VMR9VideoDesc VideoDesc; 
DWORD dwNumModes = 0;
// Fill in the VideoDesc structure (not shown).
hr = pDeinterlace->GetNumberOfDeinterlaceModes(&VideoDesc, 
    &dwNumModes, NULL);
if (SUCCEEDED(hr) && (dwNumModes != 0))
{
    // Allocate an array for the GUIDs that identify the modes.
    GUID *pModes = new GUID[dwNumModes];
    if (pModes)
    {
        // Fill the array.
        hr = pDeinterlace->GetNumberOfDeinterlaceModes(&VideoDesc, 
            &dwNumModes, pModes);
        if (SUCCEEDED(hr))
        {
            // Loop through each item and get the capabilities.
            for (int i = 0; i < dwNumModes; i++)
            {
                VMR9DeinterlaceCaps Caps;
                hr = pDeinterlace->GetDeinterlaceModeCaps(pModes + i, 
                    &VideoDesc, &Caps);
                if (SUCCEEDED(hr))
                {
                    // Examine the Caps structure.
                }
            }
        }
        delete [] pModes;
    }
}

现在,应用程序可以使用以下方法设置流的去隔行模式:

方法参考页提供了详细信息。

使用 VMR9VideoDesc 结构

在前面给出的过程中,第一步是使用视频流的说明填充 VMR9VideoDesc 结构。 首先获取视频流的媒体类型。 为此,可以在 VMR 筛选器的输入引脚上调用 IPin::ConnectionMediaType 。 然后确认视频流是否交错。 只能隔行扫描 VIDEOINFOHEADER2 格式。 如果格式类型为FORMAT_VideoInfo,则它必须是渐进式帧。 如果格式类型为FORMAT_VideoInfo2,检查AMINTERLACE_IsInterlaced标志的 dwInterlaceFlags 字段。 此标志的存在指示视频是交错的。

假设变量 pBMI 是指向格式块中 BITMAPINFOHEADER 结构的指针。 在 VMR9VideoDesc 结构中设置以下值:

  • dwSize:将此字段设置为 sizeof(VMR9VideoDesc)

  • dwSampleWidth:将此字段设置为 pBMI->biWidth

  • dwSampleHeight:将此字段设置为 abs(pBMI->biHeight)

  • SampleFormat:此字段描述媒体类型的交错特征。 检查 VIDEOINFOHEADER2 结构中的 dwInterlaceFlags 字段,并将 SampleFormat 设置为等效VMR9_SampleFormat标志。 下面提供了用于执行此操作的帮助程序函数。

  • InputSampleFreq:此字段提供输入频率,可通过 VIDEOINFOHEADER2 结构中的 AvgTimePerFrame 字段计算。 在一般情况下,将 dwNumerator 设置为 10000000,并将 dwDenominator 设置为 AvgTimePerFrame。 但是,还可以针对某些已知帧速率检查:

    每帧的平均时间 帧速率 (fps) 分子 分母
    166833 59.94 (NTSC) 60000 1001
    333667 29.97 (NTSC) 30000 1001
    417188 23.97 (NTSC) 24000 1001
    200000 50.00 (PAL) 50 1
    400000 25.00 (PAL) 25 1
    416667 24.00 (电影) 24 1

     

  • OutputFrameFreq:此字段提供输出频率,该频率可以根据 InputSampleFreq 值和输入流的交错特征进行计算:

    • OutputFrameFreq.dwDenominator 设置为 InputSampleFreq.dwDenominator
    • 如果输入视频是交错的,请将 OutputFrameFreq.dwNumerator 设置为 2 x InputSampleFreq.dwNumerator。 (取消交错后,帧速率为双倍。) 否则,将值设置为 InputSampleFreq.dwNumerator
  • dwFourCC:将此字段设置为 pBMI->biCompression

以下帮助程序函数将 AMINTERLACE_X 标志转换为 VMR9_SampleFormat 值:

#define IsInterlaced(x) ((x) & AMINTERLACE_IsInterlaced)
#define IsSingleField(x) ((x) & AMINTERLACE_1FieldPerSample)
#define IsField1First(x) ((x) & AMINTERLACE_Field1First)

VMR9_SampleFormat ConvertInterlaceFlags(DWORD dwInterlaceFlags)
{
    if (IsInterlaced(dwInterlaceFlags)) {
        if (IsSingleField(dwInterlaceFlags)) {
            if (IsField1First(dwInterlaceFlags)) {
                return VMR9_SampleFieldSingleEven;
            }
            else {
                return VMR9_SampleFieldSingleOdd;
            }
        }
        else {
            if (IsField1First(dwInterlaceFlags)) {
                return VMR9_SampleFieldInterleavedEvenFirst;
             }
            else {
                return VMR9_SampleFieldInterleavedOddFirst;
            }
        }
    }
    else {
        return VMR9_SampleProgressiveFrame;  // Not interlaced.
    }
}