Как я могу зеркально отразить видео в DirectShow? - PullRequest
2 голосов
/ 08 апреля 2020

Мне нужно отобразить поток локальной веб-камеры на экране, перевернутый горизонтально, чтобы экран выглядел как зеркало. У меня есть график DirectShow, который делает все это, кроме зеркального отображения изображения. Я пробовал несколько подходов для зеркального отображения изображения, но ни один из них не работал.

Подход A: VideoControlFlag_FlipHorizontal

Я пытался установить флаг VideoControlFlag_FlipHorizontal на выходе вывод фильтра веб-камеры, например, так:

IAMVideoControl* pAMVidControl;
IPin* pWebcamOutputPin;
// ...
// Omitting error-handing for brevity
pAMVidControl->SetMode(pWebcamOutputPin, VideoControlFlag_FlipHorizontal);

Однако это не имеет никакого эффекта. Действительно, фильтр веб-камеры утверждает, что не имеет этой возможности или каких-либо других возможностей:

long supportedModes;
hr = pAMVidControl->GetCaps(pWebcamOutputPin, &supportedModes);

// Prints 0, i.e. no capabilities
printf("Supported modes: %ld\n", supportedModes);

Подход B: SetVideoPosition

Я попытался перевернуть изображение, перевернув прямоугольники, переданные SetVideoPosition. (Я использую фильтр Enhanced Video Renderer в режиме без окон.) Есть два прямоугольника: исходный прямоугольник и целевой прямоугольник. Я попробовал оба. Вот подход B (i), переворачивающий исходный прямоугольник:

MFVideoNormalizedRect srcRect;
srcRect.left = 1.0;  // note flipped
srcRect.right = 0.0; // note flipped
srcRect.top = 0.0;
srcRect.bottom = 0.5;

return m_pVideoDisplay->SetVideoPosition(&srcRect, &destRect);

В результате ничего не отображается. Это работает в других конфигурациях, но, кажется, не нравится srcRect.left > srcRect.right.

Вот подход B (ii), переворачивающий прямоугольник назначения:

RECT destRect;
GetClientRect(hwnd, &destRect);

LONG left = destRect.left;
destRect.left = destRect.right;
destRect.right = left;

return m_pVideoDisplay->SetVideoPosition(NULL, &destRect);

Это также приводит к тому, что ничего не отображается. Это работает в других конфигурациях, но, кажется, не нравится destRect.left > destRect.right.

Подход C: IMFVideoProcessorControl::SetMirror

IMFVideoProcessorControl::SetMirror(MF_VIDEO_PROCESSOR_MIRROR) звучит так, как я хочу. Этот IMFVideoProcessorControl интерфейс реализован Видеопроцессором MFT . К сожалению, это Media Foundation Transform, и я не понимаю, как использовать его в DirectShow.

Подход D: Video Resizer DSP

Video Resizer DSP это «COM-объект, который может действовать как DMO», поэтому теоретически я мог бы использовать его в DirectShow. К сожалению, у меня нет опыта работы с DMO, и в любом случае, документы для Video Resizer не говорят, поддерживает ли он переворачивание изображения.

Подход E: IVMRMixerControl9::SetOutputRect

Я нашел IVMRMixerControl9::SetOutputRect, который явно говорит:

Поскольку этот прямоугольник существует в композиционном пространстве, не существует такого понятия, как «недопустимый» прямоугольник. Например, установите влево больше, чем вправо, чтобы отразить видео в направлении х.

Однако IVMRMixerControl9 представляется устаревшим, и я использую EVR, а не VMR, и нет никаких документов о том, как получить IVMRMixerControl9 в любом случае.

Подход F: Напишите мой собственный фильтр DirectShow

Я не хочу пробовать этот, если мне не нужно. Это будет серьезная инвестиция, и я не уверен, что она все равно будет достаточно эффективной.

Подход G: начните заново с Media Foundation

Media Foundation, возможно, позволит мне решить эту проблему , потому что это обеспечивает "Преобразование Фонда СМИ". Но даже не ясно, соответствует ли Media Foundation всем моим требованиям.

Я очень удивлен, что смотрю на такие радикальные решения для преобразования, которое кажется настолько стандартным. Какие еще существуют подходы? Есть ли что-то, что я упустил из виду в своих попытках? Как я могу зеркально отразить видео в DirectShow?

1 Ответ

1 голос
/ 08 апреля 2020

Если вариант E не работает (см. Комментарий выше; ни исходный, ни целевой прямоугольник не допускает зеркалирование), и учитывая, что это DirectShow, я бы предложил рассмотреть вариант F.

Однако написание полного фильтра может быть не так тривиально, если ты никогда не делал этого раньше. Здесь есть несколько ярлыков. Вам не нужно разрабатывать полный фильтр: подобная функциональность может быть достигнута, по крайней мере, двумя альтернативными методами:

  1. Sample Grabber Filter с обратным вызовом ISampleGrabberCB::SampleCB. Вы найдете много упоминаний об этой технике c: при вставке в график ваш код может получить обратный вызов для каждого обработанного кадра. Если вы переставите пиксели в кадровом буфере внутри обратного вызова, изображение будет зеркальным.
  2. Реализация DMO и вставка его в график фильтра с помощью DMO Wrapper Filter. У вас будет возможность подобным образом переставить пиксели кадров с большей гибкостью за счет большего количества кода для записи.

Обе упомянутые задачи будут проще выполнить, поскольку вам не нужно используйте DirectShow BaseClasses, которые, как известно, устарели в 2020 году.

Оба упомянутых не потребуют понимания потока данных в фильтре DirectShow. Как и разработка полного фильтра DirectShow, предполагается, что ваш код поддерживает перегруппировку в ограниченном наборе форматов пикселей. Вы можете go с 24-битным RGB, например, или с типичными форматами веб-камер, такими как NV12 (в настоящее время).

Если ваша перестройка пиксельных данных сделана хорошо без необходимости супероптимизации кода, вы можете игнорируйте влияние на производительность - в любом случае им можно пренебречь в большинстве случаев.

Я ожидаю, что интеграция решения Media Foundation будет более сложной и гораздо более сложной, если решение Media Foundation будет действительно хорошо оптимизировано.

Сложность проблемы в первую очередь заключается в сочетании следующих факторов.

Во-первых, вы смешали разные решения:

  1. Зеркальное отражение прямо в веб-камере (драйвере), где ваша настройка для зеркального отображения приводит к тому, что видеокадры уже зеркалированы в самом начале.
  2. Зеркальное отображение потоков данных через конвейер. Несмотря на то, что это звучит просто, это не так: иногда кадры еще сжаты (веб-камеры довольно часто отправляют JPEG), иногда кадры могут быть поддержаны видеопамятью, существует несколько форматов пикселей и т. Д. c
  3. Зеркальное отображение как видео представлено.

Ваш подход А # 1 выше. Однако, если нет поддержки для соответствующего режима, вы не можете зеркалировать.

Зеркальное отображение в EVR рендерере № 3, по-видимому, теоретически возможно. EVR использовал Direct3D 9 и внутренне рендерит поверхность (текстуру) в сцену, поэтому абсолютно возможно настроить трехмерное положение поверхности так, чтобы она стала зеркальной. Однако проблема здесь заключается в том, что при проектировании API и проверке координат не разрешается передавать аргументы зеркального отображения.

Тогда Direct3D 9 в значительной степени устарела, а сам DirectShow и даже EVR DirectShow / Media Foundation никоим образом не совместимы с текущими Direct3D 11. Несмотря на то, что может существовать возможность зеркального отображения с помощью аппаратного обеспечения, вам может быть трудно использовать его с помощью устаревшего API.

Поскольку вы хотите простое решение, вы ограничены зеркальным отображением, поскольку данные передаются в потоковом режиме. № 2 это. Несмотря на то, что это связано с разумным влиянием на производительность, вам не нужно полагаться на конкретную c поддержку оборудования камеры или видео: вы просто меняете пиксели в каждом кадре и все.

Как я уже упоминал, самый простой Можно настроить SampleCB обратный вызов, используя 24-битный RGB и / или NV12 формат пикселей. Это зависит от того, чем еще занимается ваше приложение, но без такой информации я бы сказал, что достаточно реализовать 24-битный RGB и иметь данные видеокадра, вы просто go строка за строкой и поменяете местами трехбайтовый пиксель. ширина данных / 2 раза. Если конвейер приложения позволяет вам иметь дополнительный путь к коду для переворота NV12, который похож, но не содержит видео, которое нужно конвертировать в RGB, и поэтому он немного более эффективен. Если NV12 не может работать, RGB24 будет резервным путем кода.

См. Также: Зеркальный эффект с DirectShow. NET - Кажется, я уже объяснил нечто подобное 8 лет go.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...