2

我目前正在通过 DeckLink 4K Extreme 上的 HDMI 输入从摄像机以 59.94 FPS 的速度摄取 HD1080p 视频。

我的目标是在 WPF UI 元素中复制传入的图像。为此,我在 C# WPF 应用程序中使用了 DeckLink SDK。

在这个程序中,我实现了 VideoInputFrameArrived 回调。在这个回调中,我将每个帧中的字节复制到一个 WriteableBitmap 中,我已将其设置为图像的源。

所有这些都可以正常工作,当我运行程序时,图像确实会在帧到达时实时更新。

那么我的问题是,视频输入中仅有的两种受支持的像素格式是 8BitYUV 和 10BitYUV,这两种格式都不能在计算机显示器上原生显示。

WriteableBitmap 只能接受各种 RGB、黑白和 CMYK 格式。

这是我到目前为止所尝试的。


我尝试使用 IDeckLinkVideoConversion::ConvertFrame() 转换每一帧

问题:ConvertFrame() 需要使用 IDeckLinkOutput::CreateVideoFrame() 在 DeckLink 上渲染目标帧。据我目前了解,DeckLink 不能同时充当输入(捕获视频源)和输出(渲染目标帧)。


我已将传入流设置为 8BitYUV,并将每一帧复制到格式为 BGR32 的 WriteableBitmap 中。

问题:正如我之前提到的,这将显示一个图像,但颜色不正确,并且图片只有它需要的一半宽度。

原因是 8BitYUV 的传入流是 16 位/像素,而位图需要 32 位/像素,因此位图将每个传入的 MacroPixel(4 字节)视为一个像素,而不是实际的 2 个像素。


目前我正在使用像素着色器来修复颜色,并使用 RenderTransform 将图像水平缩放 2 倍以“修复”纵横比。问题是我有一半的原始分辨率。

我不认为这是硬件限制,因为当我将另一台显示器连接到 DeckLink 上的 HDMI 输出时,传入的图像会以完美的色彩以全 1080p 显示。是否有可能在内存中的某处捕获该传出流?

TL;DR 将 4:2:2 YUV (UYVY) 实时转换为 RGB 或 CMYK 像素格式的最佳方法是什么?(1080p @ 59.94 FPS)

最好是硬件解决方案,即 DeckLink 或 GPU。

4

2 回答 2

3

您在这里有几个选择。

首先,可以直接显示UYVY。大多数视频适配器将通过 DirectDraw、DirectShow、DirectX 版本(最多 9 个 API)接受 UYVY 数据,您不需要对视频帧进行实时转换。将其集成到 WPF 应用程序中可能需要一些努力,也许最流行的方法是通过DirectShow.NET库和WPF Media Kit使用 DirectShow 。但是,通过这种方式,您也可以使用 DeckLink 的视频捕获 DirectShow 过滤器来捕获视频。您可以更快地将所有部分连接在一起,但是您已经使用DeckLink SDK进行了捕获,这样您就可以对捕获过程有更多的控制和灵活性,因此您可能不想回到 DirectShow。

第二种选择是根据需要转换为 RGB。我不认为 DeckLink 可以为您做到这一点,并且基于 GPU 的转换肯定存在(转换公式众所周知,简单且易于并行化),但是取决于硬件或无法立即使用。相反,Microsoft 提供了Color Converter DSP,它可以以非常有效的方式进行转换(从 8 位,而不是 10 位)。API 是本机的,您可能需要Media Foundation .NET从您的应用程序访问它。也可以使用 FFmpeg 的 libswscale (通过相应的包装器用于托管应用程序)来完成另一种高效的软件转换。

于 2015-01-16T16:55:14.943 回答
1

我只是用decklink api做到了这一点,因为我拥有的卡既可以作为输入也可以作为输出。并且输出不需要处于播放模式来访问这部分 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();
    }
}

于 2019-11-27T16:21:03.637 回答