在 DMO 上设置媒体类型

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

在 DMO 可以处理任何数据之前,客户端必须为每个流设置媒体类型。 (此规则有一个小例外;请参阅 Optional Streams.) 若要查找流的数量,请调用 IMediaObject::GetStreamCount 方法:

DWORD cInput = 0, cOutput = 0;
pDMO->GetStreamCount(&cInput, &cOutput);

此方法返回两个值,即输入数和输出数。 这些值在 DMO 的生存期内是固定的。

首选类型

对于每个流,DMO 会按优先顺序分配可能媒体类型的列表。 例如,首选类型可能是 32-RGB、24 位 RGB 和 16 位 RGB,按顺序排列。 当客户端设置媒体类型时,它可以使用这些列表作为提示。 若要检索流的首选类型,请调用 IMediaObject::GetInputType 方法或 IMediaObject::GetOutputType 方法。 指定从零) 开始的类型 (的流号和索引值。 例如,以下代码从第一个输入流中检索第一个首选类型:

DMO_MEDIA_TYPE mt
hr = pDMO->GetInputType(0, 0, &mt)
if (SUCCEEDED(hr))
{
    // Examine this media type (not shown).
    /* ... */

    // Free the format block.
    MoFreeMediaType(&mt);
}

若要枚举给定流上的所有首选媒体类型,请使用递增类型索引的循环,直到方法返回DMO_E_NO_MORE_ITEMS,如以下示例所示:

DMO_MEDIA_TYPE mt;
DWORD dwType = 0;
while (hr = pDMO->GetInputType(0, dwType, &mt), SUCCEEDED(hr))
{
    // Examine this media type (not shown).
    /* ... */

    // Free the format block.
    MoFreeMediaType(&mt);
    ++dwType;
}

关于首选类型,应注意以下几点:

  • DMO 可能会返回没有格式块的类型。 例如,DMO 可以指定视频类型,例如 24 位 RGB,而不提供图像的宽度和高度。 但是,在设置类型时,必须提供完整的格式块。 (某些媒体类型(如 MIDI)从不需要格式块,在这种情况下,此注释不适用。)
  • DMO 不需要支持它返回的每种首选类型的组合。 例如,如果 DMO 有两个流,并且每个流都有四个首选类型,则有 16 个可能的组合,但并非所有组合都保证有效。
  • 当客户端为一个流设置媒体类型时,DMO 可能会更新其他流的首选类型以反映新状态。 但是,不需要这样做。
  • 对于某些流,DMO 可能不提供任何首选类型。 通常,DMO 应在某些流上至少提供一些首选类型。
  • DMO 不需要提供它可以接受的媒体类型的完整列表。 可能存在 DMO 支持但未作为首选类型提供的“非意外”类型。

简而言之,客户端应仅将首选类型视为准则。 要知道某些支持哪些类型,唯一的方法是测试它们,如下一部分所述。

在流上设置媒体类型

使用 IMediaObject::SetInputTypeIMediaObject::SetOutputType 方法设置每个流的类型。 必须提供包含媒体类型的完整说明 的DMO_MEDIA_TYPE 结构。 以下示例使用 44.1-kHz 16 位立体声 PCM 音频在输入流 0 上设置媒体类型:

DMO_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(DMO_MEDIA_TYPE));
// Allocate memory for the format block.
HRESULT hr = MoInitMediaType(&mt, sizeof(WAVEFORMATEX));
if (SUCCEEDED(hr))
{
    // Set the type GUIDs.
    mt.majortype  = MEDIATYPE_Audio;
    mt.subtype    = MEDIASUBTYPE_PCM;
    mt.formattype = FORMAT_WaveFormatEx;

    // Initialize the format block.
    WAVEFORMATEX *pWave = reinterpret_cast<WAVEFORMATEX*>(mt.pbFormat);
    pWave->wFormatTag = WAVE_FORMAT_PCM;
    pWave->nChannels = 2;
    pWave->nSamplesPerSec = 44100;
    pWave->wBitsPerSample = 16;
    pWave->nBlockAlign = (pWave->nChannels * pWave->wBitsPerSample) / 8;
    pWave->nAvgBytesPerSec = pWave->nSamplesPerSec * pWave->nBlockAlign;
    pWave->cbSize = 0;

    // Set the media type.
    hr = pDMO->SetInputType(0, &mt, 0); 

    // Release the format block.
    MoFreeMediaType(&mt);
}

若要在不设置媒体类型的情况下测试媒体类型,请使用DMO_SET_TYPEF_TEST_ONLY标志调用 SetInputTypeSetOutputType 。 如果类型可接受,该方法返回S_OK,否则S_FALSE:

if (S_OK == pDMO->SetInputType(0, &mt, DMO_SET_TYPEF_TEST_ONLY)
{
    // Media type is OK.
}

由于一个流上的设置可能会影响另一个流,因此可能需要清除流的媒体类型。 为此,请使用DMO_SET_TYPEF_CLEAR标志调用 SetInputTypeSetOutputType

对于解码器 DMO,客户端通常会先设置输入类型,然后选择输出类型。 对于编码器 DMO,客户端将首先设置输出类型,然后设置输入类型。

直接托管 DMO