winrt::Windows::Мультимедиа::Воспроизведение::Медиаплеер вызывает сбой при вызове CopyFrameToVideoSurface

#c #windows #uwp #windows-runtime #c -winrt

Вопрос:

Я хочу извлечь необработанные кадры или растровые изображения из видео, которое я воспроизводю в своем консольном приложении C , используя API C /WinRT. Я просто использую CopyFrameToVideoSurface , чтобы скопировать кадр видео в a IDirect3DSurface . Но это просто приводит к сбою моей программы (которая отлично работает, если я не настрою этот обратный вызов извлечения кадров). Моя цель состоит в том, чтобы отобразить этот буфер кадров где-нибудь в другом месте для отображения видео.

Код извлечения фрейма (см. Полный проект здесь: https://github.com/harmonoid/libwinmedia/tree/stackoverflow)

 IDirect3DSurface surface = IDirect3DSurface();
Streams::IBuffer buffer = Streams::IBuffer();


DLLEXPORT void PlayerSetFrameEventHandler(
    int32_t player_id, void (*callback)(uint8_t* buffer, int32_t size,
                                        int32_t width, int32_t height)) {
  g_media_players.at(player_id).IsVideoFrameServerEnabled(true);
  g_media_players.at(player_id)
      .VideoFrameAvailable([=](auto, const autoamp; args) -> void {
        g_media_players.at(player_id).CopyFrameToVideoSurface(surface);
        SoftwareBitmap bitmap =
            SoftwareBitmap::CreateCopyFromSurfaceAsync(surface).get();
        bitmap.CopyToBuffer(buffer);
        (*callback)(buffer.data(), buffer.Length(), bitmap.PixelWidth(),
                    bitmap.PixelHeight());
      });
}
 

Вы можете просто создать эту общую библиотеку, используя cmake --build .

Для тестирования сбоя вы можете скомпилировать следующий пример (также присутствует в репозитории ссылок): https://github.com/harmonoid/libwinmedia/blob/stackoverflow/examples/frame_extractor.cpp

 #include <cstdio>
#include "../include/internal.hpp"
int32_t main() {
  using namespace Internal;
  // Create a list of medias.
  const char* media_uris[] = {
      "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/"
      "ForBiggerJoyrides.mp4"};
  const int media_ids[] = {0};
  // Create a player instance.
  PlayerCreate(0);
  // Set frame callback (comment out the code to prevent crash from happening).
  PlayerSetFrameEventHandler(
      0, [](uint8_t*, int32_t, int32_t width, int32_t height) {
        printf("Video width: %d, Video height: %d.", width, height);
      });
  // Open list of medias.
  PlayerOpen(0, 1, media_uris, media_ids);
  // Start playing the player.
  PlayerPlay(0);
  // Prevent console from closing.
  getchar();
  return 0;
}
 

Мне действительно помогут, если я смогу получить помощь в исправлении кода или любого другого рабочего метода для извлечения кадров или растровых изображений видео с помощью winrt::Windows::Media::Playback::MediaPlayer .

Спасибо..

Ниже приведен маршрут крушения: авария

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

1. Вы копируете на нулевую поверхность surface . Вы можете видеть в окне «Локальные», что destination значение равно нулю. Обратите внимание, что вы никогда не создавали поверхность или буфер.

2. @RaymondChen большое спасибо за ваш ответ. Я понимаю, что создание экземпляра raw IBuffer , возможно, неправильно, но как я должен получить IDirect3DSurface (или что-то, что реализует IDirect3DSurface ) в консольном приложении C /WinRT. Спасибо.

3. Надеюсь, есть несколько руководств по Direct3D, которые покажут, как создать поверхность idirect3d11. Если у вас есть IDXGISurface, вы можете преобразовать его в IDirect3D11Surface с помощью CreateDirect3D11SurfaceFromDXGISurface

4. @RaymondChen большое вам спасибо, я посмотрю.

5. Пример того, как создать объект, реализующий IDirect3DSurface интерфейс, можно найти в разделе Использование MediaPlayer в режиме фрейм-сервера . В зависимости от вашего конкретного варианта использования вам может потребоваться реализовать другое решение.