WPF 视频流渲染优化思路及经验总结


回顾我在wpf上渲染视频流的历程,可以分为三个阶段:

以下方案都是在ffmpeg中解码后,回调到WPF中进行渲染

1、使用WPF嵌套winform控件,在winform控件上使用GDI渲染RGB数据,这个方案拖动窗口会有严重的闪烁问题,无解。

2、使用WriteableBitmap,将一个Image控件的Sourece指定为WriteableBitmap,在C++中回调C#,通过 Marshal.Copy方法将rgb数据拷贝到WriteableBitmap,这样就能显示出视频流,但会带来以下2个问题:

(1) CPU使用率高

      因为涉及到数据的拷贝,CPU使用率会上升,何况解码也会占用一部分CPU。

(2) 内存占用大

     不断的new 一个byte数组,会使程序占用内存上升,即使定义byte数组为全局变量,只new一次,依旧没有解决内存占用高的问题,而且内存什么时候释放也不好把握。

  
 private int RenderRgb(int width, int height, IntPtr data, int len)
        {
            byte[] buffer = new byte[len];
            Marshal.Copy(data, buffer, 0, len);

            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                if (writeBmp == null)
                {
                    writeBmp = new WriteableBitmap(width, height, 0, 0, PixelFormats.Bgra32, null);
                    showRect = new Int32Rect(0, 0, writeBmp.PixelWidth, writeBmp.PixelHeight);
                    img.Source = writeBmp;
                }

                writeBmp.Lock();
                Marshal.Copy(buffer, 0, writeBmp.BackBuffer, buffer.Length);
                writeBmp.AddDirtyRect(showRect);
                writeBmp.Unlock();
            }));
            return 0;
        }

3、使用Direct3D渲染,创建一个surface,将数据拷贝到surface后台缓冲区,WPF上用D3DImage显示,目前来看这个方案效果最好,CPU占用率和内存都维持在一个比较理想的范围,尤其是使用IDirect3D9Ex后,数据直接由显卡接管,CPU占用率能减小将近20%,而且还支持YUV!

   private void RenderD3D(IntPtr surface)
        {
            this.Dispatcher.BeginInvoke(new Action(() =>
            {            
                if (d3dImage.IsFrontBufferAvailable && surface != IntPtr.Zero)
                {
                    showRect = new Int32Rect(0, 0, d3dImage.PixelWidth, d3dImage.PixelHeight);
                    d3dImage.Lock();
                    d3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface);
                   
                    d3dImage.AddDirtyRect(showRect);
                    d3dImage.Unlock();
                }
             
            }));

        }

总结:目前WPF上比较好的视频渲染方案就是采用硬解,将视频流解码后输出yuv,通过Direct3D生成surface后渲染,将指针传回给D3DImage显示。

CSDN:https://mp.csdn.net/console/editor/html/103958051

参考链接:

http://www.mamicode.com/info-detail-2890105.html

http://www.smochen.com/detail?aid=1630

参考项目:
WPFMediaKit:https://github.com/Sascha-L/WPF-MediaKit

sharpDx:http://sharpdx.org/