Какой пример кода MF Play показывает правильные методы COM в Media Foundation?

Сейчас я поднимаюсь вверх по крутой кривой обучения Windows Media Foundation и сосредотачиваюсь на двух очень похожих примерах кода, которые помогут мне понять технологию. Несмотря на то, что оба используют Media Session для очень простой программы «Play», которая воспроизводит видео из файла, есть важные тонкие различия.

Первый образец - это Microsoft MF Play, расположенный по адресу:

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

Он не инициализирует COM и не выполняет блокировки критических разделов, но при этом очень хорошо воспроизводит видео. Ограничит ли отсутствие использования COM его использование другими способами, например, при обработке нескольких видеопотоков для разделения окон посредством многопоточности? Поскольку этот код находится в сети, я могу наивно предполагать, что этот код более актуален.

Второй образец взят из книги «Разработка приложений Microsoft Media Foundation - Антон Полингер». Я загрузил образец кода отсюда: https://www.microsoftpressstore.com/content/images/9780735656598/downloads/9780735656598_files.zip

Эта программа Play в папке Chapter 3 немного сложнее из-за использования этих функций инициализации COM:

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

Он также использует несколько блокировок критических разделов, используя:

CComCritSecLock<CComAutoCriticalSection> lock(m_critSec);

Но загадочным образом нет соответствующих анлочков (). Так может кто-нибудь объяснить эти потенциальные важные различия между этими двумя образцами кода и какими из них я должен использовать? Меня беспокоит, что, если я не буду использовать методы COM, у меня могут возникнуть проблемы позже, когда я попытаюсь передать несколько видео в несколько окон, или, что еще хуже, у меня могут возникнуть проблемы с надежностью.

Кстати, код Polinger работает, но не обрабатывает изменение размера окна во время воспроизведения видео. Я попытался добавить код, аналогичный тому, как это делает код MS, используя этот код после события изменения размера окна:

m_pVideoDisplay->SetVideoPosition(NULL, &rcDest)

Использование этого просто привело к зависанию программы.

Любая помощь будет принята с благодарностью!


person Gary G.    schedule 19.07.2017    source источник


Ответы (3)


О том, что «COM не инициализируется» - вы видели не весь его код - исследуйте Пример воспроизведения медиа-сеанса - вы найдете вызов MFStartup в player.cpp - этого достаточно для MediaFoundation (MF). Я прочитал книгу Полингера, и в ее коде вызывается некоторая функция, чувствительная к модели потока COM - например, DirectX. Но, исходя из моего опыта, похоже, что MF вызывает CoInitialize из контекста вызова MFStartup. Более того, в коде из книги Полингера есть вызов модели потока квартиры: hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);, но MF поддерживает выполнение из многопоточной модели - он не чувствителен к этому.

Насчет "Но загадочным образом нет соответствующих анлочков ()". - CComCritSecLock - объектно-ориентированная оболочка для блокировки раздела, а unlocks() вызывается в деструкторе CComCritSecLock - ~CComCritSecLock().

По поводу изменения размера - m_pVideoDisplay->SetVideoPosition(NULL, &rcDest) - похоже, что rcDest имеет неправильное значение - согласно метод IMFVideoDisplayControl :: SetVideoPosition

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: и WPFMediaFoundationPlayer

С уважением, Евгений Перегуда

person Evgeny Pereguda    schedule 20.07.2017
comment
Спасибо за ответ и ссылки! И особенно для выяснения того, как деструктор выполняет разблокировку. Не такая уж и загадка. - person Gary G.; 20.07.2017

В образце неточно опущена инициализация COM, и это неверно. Он должен был вызвать CoInitialize [Ex] как обычно. Вы можете проверить образцы Windows SDK 7.x для Media Foundation, и образцы показывают правильную инициализацию. Например, CComCritSecLock и CComAutoCriticalSection являются хорошо известными и задокументированными классами ATL. которые помогут вам с автоматической разблокировкой критических разделов.

Используйте этот класс для блокировки и разблокировки объектов более безопасным способом, чем с классом CComCriticalSection или CComAutoCriticalSection.

person Roman R.    schedule 20.07.2017
comment
Спасибо за пояснение! Я не исследовал MFPlayer2, поскольку он использует устаревший API IMFPMediaPlayer, но я посмотрю на него, чтобы увидеть, как он использует методы блокировки COM. - person Gary G.; 20.07.2017
comment
Несмотря на то, что MFPlayer2 может использовать устаревшее (плохой пример), правила COM применяются точно так же. - person Roman R.; 20.07.2017

Для всех, кто может работать с примером кода Polinger, о котором я упоминал в своем OP, я смог успешно добавить изменение размера окна в пример 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;
}
person Gary G.    schedule 25.07.2017