哪个 MF Play 示例代码显示了 Media Foundation 中正确的 COM 技术?

Which MF Play sample code shows proper COM techniques in Media Foundation?

我现在正在爬 Windows Media Foundation 的陡峭学习曲线,我专注于两个非常相似的代码示例,以帮助我理解这项技术。尽管两者都将 Media Session 用于从文件播放视频的非常简单的“播放”程序,但仍存在重要的细微差别。

第一个示例是 Microsoft 的 MF Play,位于:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd979592(v=vs.85).aspx

它不初始化 COM,也不执行任何关键部分锁定,但它可以很好地播放视频。不使用 COM 是否会限制它在其他方面的使用,例如在处理多个视频流以通过多线程分离 windows 时?由于此代码在线,我可能天真地假设此代码更新。

第二个示例来自“Developing Microsoft Media Foundation Applications - Anton Polinger”一书。我从这里下载了示例代码: https://www.microsoftpressstore.com/content/images/9780735656598/downloads/9780735656598_files.zip

Chapter 3 文件夹中的这个 Play 程序由于使用了这些 COM 初始化函数而稍微复杂一些:

// initialize COM
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
...
// uninitialize COM
CoUninitialize();

它还使用了几个临界区锁:

CComCritSecLock<CComAutoCriticalSection> lock(m_critSec);

但奇怪的是没有对应的unlocks()。那么有人可以解释这两个代码示例之间潜在的重要区别以及我应该使用哪些吗?我担心如果我不使用 COM 方法,我可能会在以后尝试将多个视频流式传输到多个 windows 时遇到问题,或者更糟的是我可能会遇到可靠性问题。

附带说明一下,Polinger 代码可以工作,但无法在播放视频时处理 window 调整大小。我试图通过在 window 调整大小事件后使用此代码来添加类似于 MS 代码的代码:

m_pVideoDisplay->SetVideoPosition(NULL, &rcDest)

使用这个只会导致程序冻结。

如有任何帮助,我们将不胜感激!

关于 "It does not initialize COM" - 你没有看到它的所有代码 - 研究 Media Session Playback Example - 你会在 player.cpp 中找到调用 MFStartup - 这对 MediaFoundation 来说已经足够了(中频)。我读过 Polinger 的书,在代码中它调用了一些 COM 线程模型敏感函数——例如,DirectX。但是,根据我的经验,MF 似乎是从 MFStartup 调用的上下文中调用 CoInitialize。此外,在 Polinger 书中的代码中有调用单元线程模型:hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);,但 MF 支持从多线程模型执行 - 它对此不敏感。

关于 "But mysteriously there are no corresponding unlocks()." - CComCritSecLock 是面向对象的节锁包装器,unlocks()CComCritSecLock 的析构函数中调用 - ~CComCritSecLock().

关于调整大小 - m_pVideoDisplay->SetVideoPosition(NULL, &rcDest) - 看起来 rcDest 的值有误 - 根据 IMFVideoDisplayControl::SetVideoPosition method

The destination rectangle defines a rectangle within the clipping window where the video appears. It is specified in pixels, relative to the client area of the window. To fill the entire window, set the destination rectangle to {0, 0, width, height},

我可以建议在 CodeProject 网站上研究我的项目:NativeMediaFoundationPlayer: and WPFMediaFoundationPlayer

此致, 叶夫根·佩雷古达

示例不准确地省略了 COM 初始化,这是不正确的。它应该以通常的方式调用 CoInitialize[Ex]。您可以检查 Windows SDK 7.x Media Foundation 示例,示例显示正确的初始化。例如,thisTranscode 样本的做法。

正如 Evgeny 所提到的,CComCritSecLockCComAutoCriticalSection 是众所周知的并且有文档记录的 ATL 类 可以帮助您自动解锁关键部分。

Use this class to lock and unlock objects in a safer way than with the CComCriticalSection Class or CComAutoCriticalSection Class.

对于可能正在使用我在 OP 中提到的 Polinger 代码示例的任何其他人,我能够通过执行以下操作成功地将 window 调整大小添加到 Polinger 示例:

在winmain.cpp文件中,WndProc回调函数,我添加了:

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
...
    case WM_SIZE:
        OnResize(LOWORD(lParam), HIWORD(lParam));
        break;

然后将此函数添加到 winmain.cpp 文件中:

//  Handler for WM_SIZE messages.
void OnResize(WORD width, WORD height)
{
    if (g_pPlayer)
    {
        g_pPlayer->ResizeVideo(width, height);
    }
}

然后将此函数添加到 Player.cpp 文件中:

HRESULT CPlayer::ResizeVideo(WORD width, WORD height)
{
    HRESULT hr = S_OK;

    CComCritSecLock<CComAutoCriticalSection> lock(m_critSec);

    if (m_pVideoDisplay)
    {
        // Set the destination rectangle.
        RECT rcDest = { 0, 0, width, height };
        hr = m_pVideoDisplay->SetVideoPosition(NULL, &rcDest);
    }

    return hr;
}