Почему MediaFoundation MediaEngine может воспроизводить видео при 2-м вызове для воспроизведения, но не при первом?

#winapi #directx-11 #ms-media-foundation #directx-12

#winapi #directx-11 #ms-media-foundation #directx-12

Вопрос:

Я использую примерный класс MediaEnginePlayer DirectX от Microsoft, определенный здесь и описанный здесь в настольном приложении Win32 в Windows 10.

После вызова setSource() для аудиофайла, подобного этому:

 mePlayer->SetSource(L"c:\auddio.opus");
 

он автоматически начинает воспроизведение, потому что класс вызывает Play() после получения MF_MEDIA_ENGINE_EVENT_CANPLAY события здесь.

Но если задано видео:

 mePlayer->SetSource(L"c:\video.mp4");  //Won't play
 

он не воспроизводится. Чтобы запустить воспроизведение видео, мне нужно явно вызвать Play() либо до, либо после вызова setSource() .

 //This will play
mePlayer->SetSource(L"c:\video.mp4");
mePlayer->Play();

//And even this will play
mePlayer->Play();
mePlayer->SetSource(L"c:\video.mp4");
 

Но я не понимаю, почему это так. Вот пример, демонстрирующий проблему: https://www.mediafire.com/file/6b61sxoou94d60r/Test.zip/file

Кто-нибудь может объяснить это поведение?

Комментарии:

1. Протестировал этот образец с разными видеофайлами, и он работает для меня без mePlayer->Play() дополнительного вызова. Убедитесь, что вы добавили свой видеофайл в папку ресурсов проекта и установили для его свойств значения «Содержимое: да» и «Тип элемента: Медиа». Вы получите MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA , а затем MF_MEDIA_ENGINE_EVENT_CANPLAY , после этого, начнется воспроизведение видео.

2. Я также могу заставить образец работать. Но класс не выполняет то же самое для меня вне образца, и я не понимаю, почему. События, о которых вы упоминаете, срабатывают. Метод Play() вызывается после MF_MEDIA_ENGINE_EVENT_CANPLAY без ошибок. Я также получаю MF_MEDIA_ENGINE_EVENT_TIMEUPDATE события. Однако без моего явного вызова Play() GetCurrentTime() всегда сообщает ноль.

3. Не могли бы вы показать мини-, полный и воспроизводимый образец?

4. Я не уверен, как его загрузить. Может быть, я смогу создать небольшую программу win32, которую я мог бы вставить сюда завтра, в которую можно было бы поместить класс. На самом деле вам не нужно отображать видео для его тестирования. Если он воспроизводится, вы услышите звук.

5. Может быть, вы можете поделиться им в Github.

Ответ №1:

Я могу воспроизвести эту проблему, используя ваш пример кода.

Вызов MediaEnginePlayer::Play() при получении MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA решает эту проблему для меня. Вы можете попробовать.

О том, почему вызов MediaEnginePlayer::Play() при получении MF_MEDIA_ENGINE_EVENT_CANPLAY не работает, мне нужно провести дополнительное расследование.

Комментарии:

1. Он также воспроизводится для меня, если после вызова вызывается функция Play() MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA , что действительно интересно, поскольку я считаю, что это происходит раньше MF_MEDIA_ENGINE_EVENT_CANPLAY и не гарантирует, что было загружено достаточно данных для успешного начала воспроизведения. Загадочно, как исходный образец может работать. Возможно, возникает какая-то странная асинхронная проблема? Спасибо, что посмотрели на это.

2. @cecil Если вы закомментируете строки кода MediaEnginePlayer::TransferFrame() в примере UWP, воспроизводится та же проблема. Но если вы измените Play() с MF_MEDIA_ENGINE_EVENT_CANPLAY на MF_MEDIA_ENGINE_EVENT_LOADEDMETADATA , это сработает. В вашем примере кода Win32 C MediaEnginePlayer::TransferFrame() никогда не выполняется. Таким образом, мы можем подтвердить, что эта проблема согласуется между Win32 C и UWP-приложением.

3. Это отличное наблюдение. Я думаю, что именно это призвание IMFMediaEngine::OnVideoStreamTick() заставляет его работать и прогрессировать при воспроизведении. Вы можете закомментировать все остальное, MediaEnginePlayer::TransferFrame() и оно будет воспроизводиться. Возможно, этот вызов является требованием воспроизведения видео. Мне все еще странно, что один вызов MediaEnginePlayer::Play() в определенное время все равно приводит к его воспроизведению.

4. Согласно MSDN : MF_MEDIA_ENGINE_EVENT_CANPLAY означает, что воспроизведение может начаться, но медиа-движку может потребоваться остановка для буферизации большего количества данных. Таким образом, исходя из понимания документа, он может быть не в состоянии воспроизводиться из-за буферизации данных. После тестирования, я думаю, вы можете использовать MF_MEDIA_ENGINE_EVENT_LOADEDDATA флаг, в документе говорится: Медиа-движок загрузил достаточно данных для отображения некоторого контента (например, видеокадра). И у меня это работает нормально.