Конвертировать 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();
    }
}

Другие вопросы по тегам