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/