【问题标题】:Fast Video Display WPF快速视频显示 WPF
【发布时间】:2013-05-15 23:11:50
【问题描述】:

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

更多细节:

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

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

谢谢!

【问题讨论】:

    标签: c# wpf performance video frame-rate


    【解决方案1】:

    任何正在寻找解决方案的人,我们使用 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;
        }
    

    【讨论】:

    • 您能否详细介绍一下您是如何将副本优化到显存中的?
    • @Thomas 我刚刚更新了复制方法的完整代码
    • 对您的解决方案感兴趣...可以发给我吗? linusang{at}yahoo{dot}com
    • 您好,您可以给我一些代码或示例项目吗? arman.salehi@gmail.com,谢谢你
    猜你喜欢
    • 2015-12-17
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 2020-12-17
    相关资源
    最近更新 更多