Конвертировать YUV в RGB на DeckLink, используя оборудование
В настоящее время я принимаю видео HD1080p со скоростью 59,94 FPS с видеокамеры через вход HDMI на DeckLink 4K Extreme.
Моя цель - скопировать входящее изображение в элемент пользовательского интерфейса WPF. Для этого я использую DeckLink SDK в приложении C# WPF.
В этой программе я реализовал обратный вызов VideoInputFrameArrived. В этом обратном вызове я копирую байты из каждого фрейма в WriteableBitmap, который я установил в качестве источника для изображения.
Все это работает как надо, и когда я запускаю программу, изображение действительно обновляется в реальном времени по мере поступления кадров.
Моя проблема в том, что только два поддерживаемых пиксельных формата для видеовхода - это 8BitYUV и 10BitYUV, ни один из которых не может быть отображен на мониторах компьютера.
WriteableBitmap может принимать только различные форматы RGB, Black and White и CMYK.
Вот что я пробовал до сих пор.
Я пытался преобразовать каждый кадр, используя IDeckLinkVideoConversion::ConvertFrame()
Проблема: ConvertFrame () требует, чтобы целевой кадр отображался на DeckLink с использованием IDeckLinkOutput::CreateVideoFrame(). Насколько я понимаю, DeckLink не может действовать как вход (для захвата видеопотока) и выход (для рендеринга целевого кадра).
Я установил входящий поток на 8BitYUV и скопировал каждый кадр в WriteableBitmap в формате BGR32.
Проблема: как я упоминал ранее, это будет отображать изображение, но цвет будет неправильным, и изображение будет только вдвое меньше, чем должно быть.
Причина этого заключается в том, что входящий поток 8BitYUV имеет размер 16 бит / пиксель, тогда как растровое изображение ожидает 32 бита / пиксель, и поэтому растровое изображение обрабатывает каждый входящий макропиксель (4 байта) как один пиксель вместо двух пикселей, которыми он на самом деле является.
В настоящее время я использую пиксельный шейдер для исправления цвета и RenderTransform для масштабирования изображения по горизонтали с коэффициентом 2, чтобы "исправить" соотношение сторон. Проблема в том, что у меня половина оригинального разрешения.
Я не верю, что это аппаратное ограничение, потому что, когда я подключаю другой монитор к выходу HDMI на DeckLink, входящее изображение отображается в полном 1080p в идеальном цвете. Возможно ли захватить этот исходящий поток где-нибудь в памяти?
TL; DR Как лучше всего конвертировать 4:2:2 YUV (UYVY) в пиксельный формат RGB или CMYK в режиме реального времени? (1080p при 59,94 FPS)
Желательно аппаратное решение, т.е. DeckLink или GPU.
1 ответ
У вас есть несколько вариантов здесь.
Прежде всего, вы можете отобразить UYVY напрямую. Большинство видеоадаптеров будут принимать данные UYVY через DirectDraw, DirectShow, DirectX версии до 9 API, и вам не потребуется конвертация видеокадров в реальном времени. Интеграция этого в приложение WPF может потребовать некоторых усилий, и, возможно, наиболее популярным способом является использование DirectShow через библиотеку DirectShow.NET и WPF Media Kit. Таким образом, однако, вы также можете захватывать видео, используя фильтр DirectShow видеозахвата DeckLink. Вы можете соединить все части вместе быстрее, однако вы уже захватываете, используя DeckLink SDK, и таким образом у вас больше контроля и гибкости в процессе захвата, поэтому вы можете не захотеть возвращаться в DirectShow.
Второй вариант - конвертировать в RGB, как вы хотели. Я не думаю, что DeckLink может сделать это за вас, и преобразование на основе GPU определенно существует (формула преобразования хорошо известна, проста и легко распараллеливается), однако зависит от аппаратного обеспечения или не доступна сразу. Вместо этого Microsoft поставляет Color Converter DSP, который может выполнять преобразование (из 8 бит, но не из 10) очень эффективным способом. API является собственным, и вам может понадобиться Media Foundation .NET для доступа к нему из вашего приложения. Альтернативное эффективное преобразование программного обеспечения также может быть выполнено с помощью libswscale FFmpeg (для управляемого приложения через соответствующие оболочки).
Я только что сделал это с api Decklink, потому что карта, которая у меня есть, может действовать как входы, так и выходы. И выходам не обязательно находиться в режиме воспроизведения для доступа к этой части api:
com_ptr<IDeckLinkOutput> m_deckLinkOutput;
if (SUCCEEDED(m_deckLink->QueryInterface(IID_IDeckLinkOutput, (void **)&m_deckLinkOutput)))
{
IDeckLinkMutableVideoFrame *pRGBFrame;
if (SUCCEEDED(m_deckLinkOutput->CreateVideoFrame(videoFrame->GetWidth(), videoFrame->GetHeight(), videoFrame->GetWidth() * 4, bmdFormat8BitBGRA, videoFrame->GetFlags(), &pRGBFrame)))
{
m_deckLinkVideoConversion->ConvertFrame(pFrame, pRGBFrame);
//use the rgbFrame
pRGBFrame->Release();
}
}