c# - 快速视频显示 WPF

标签 c# wpf performance video frame-rate

我正在开发一个 WPF 应用程序,它需要以快速帧速率(我们想要 30 fps)显示多个视频流。视频流是 1920x1080 原始 (RGB24) 帧(它们存储在 System.Drawing.Bitmap 中)。有没有人对如何实现这一目标有任何想法?

更多详情:

  • 我们之前的尝试使用了标准的 WPF 图像控件,为每个帧更改其源。这对单个流很有效,但现在我们必须渲染多个流,它正在变慢。
  • 我们还尝试使用 Direct2D 处理绘图,使用 D3D9 共享表面作为图像控件的源。虽然速度更快,但我们仍然无法从中获得稳定的 30fps(随着情况的恢复,它会在 24-32 fps 之间跳跃)。
  • 视频流进入后台线程,然后被编码(使用窗口的 Dispatcher)到适当的 UI 线程进行绘制。然后所有绘图都在 UI 线程上完成。我们还尝试为每个窗口提供自己的线程。

如果有人想看,我可以提供我们尝试过的代码示例。

谢谢!

最佳答案

任何寻求解决方案的人,我们使用 DirectX 11 编写了一个自定义 winforms 控件,并将高度优化的副本复制到图形内存中,然后将控件托管在 WinformsHost 中,我可以向任何人提供一些代码有兴趣。

优化复制到 gpu 内存

    // Using native memcpy for the fastest possible copy
    [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
    private static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count);

    /// <summary>
    /// Copies a bitmap to gpu memory
    /// </summary>
    /// <param name="frame">The image to copy to the gpu</param>
    /// <returns>A texture in gpu memory for the bitmap</returns>
    public Texture2D CopyFrameToGpuMemory(Bitmap frame)
    {
        SampleDescription sampleDesc = new SampleDescription();
        sampleDesc.Count = 1;
        sampleDesc.Quality = 0;

        Texture2DDescription texDesc = new Texture2DDescription()
        {
            ArraySize = 1,
            MipLevels = 1,
            SampleDescription = sampleDesc,
            Format = Format.B8G8R8A8_UNorm,
            CpuAccessFlags = CpuAccessFlags.Write,
            BindFlags = BindFlags.ShaderResource,
            Usage = ResourceUsage.Dynamic,
            Height = frame.Height,
            Width = frame.Width
        };

        Texture2D tex = new Texture2D(Device, texDesc);

        Surface surface = tex.AsSurface();
        DataRectangle mappedRect = surface.Map(SlimDX.DXGI.MapFlags.Write | SlimDX.DXGI.MapFlags.Discard);

        BitmapData pixelData = frame.LockBits(new Rectangle(0, 0, frame.Width, frame.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);

        unsafe //!!!
        {
            byte* pixelDataStart = (byte*)pixelData.Scan0.ToPointer();
            byte* mappedRectDataStart = (byte*)mappedRect.Data.DataPointer.ToPointer();

            for (int y = 0; y < texDesc.Height; y++)
            {
                byte* lineLocationDest = mappedRectDataStart + (y * mappedRect.Pitch);
                byte* lineLocationSrc = pixelDataStart + (y * pixelData.Stride);

                // Copy line by line for best performance
                memcpy((IntPtr)lineLocationDest, (IntPtr)lineLocationSrc, (UIntPtr)(texDesc.Width * 4));
            }
        } //!!!

        frame.UnlockBits(pixelData);

        mappedRect.Data.Dispose();

        surface.Unmap();
        surface.Dispose();

        return tex;
    }

关于c# - 快速视频显示 WPF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11906503/

相关文章:

c# - 获取堆栈面板中文本 block 的最大宽度

c# - 读取进程的 MainWindowHandle

c# - 如何从带有短语主题的 Cortana 命令中提取参数,通过文本激活?

c# - 在 C# 中处理竞争条件

c# - 你如何在 Selenium 中设置 ChromeDriver 的端口?

java - 在 JVM 上进行定期线程转储 - ThreadMXBean 与 JVMTI 代理

performance - 使用 Powershell 的进程的网络使用情况

c# - WPF 用户控制资源

Visual Studio 2012 上的 sqlschemacompare

python - 使用Python高效实现多个列表中的单词计数