前言
通过《C# wpf 使用d3d渲染yuv视频数据》我们实现了在Image控件中显示视频,解决了控件绘制不兼容问题。但如果有时候不想依赖D3D时,还有一种方案实现视频的渲染,使用wpf的WriteableBitmap,WriteableBitmap的祖先接口有ImageSource,即可以作为Image的Source显示画面。我们只需往WriteableBitmap中写入图像数据即可实现视频的渲染。
一、如何实现?
1.创建WriteableBitmap
通过视频宽高及像素格式创建一个WriteableBitmap,PixelFormats提供的像素格式基本只有RBG形式的颜色模型,这里选择Bgra32。
var writeableBitmap= new WriteableBitmap(640, 360, 0, 0, PixelFormats.Bgra32, null);
2.关联Image
使用绑定或直接赋值的方式(取决于程序架构,mvvm就绑定)。将Image的Source赋值为WriteableBitmap对象。
下列示例是直接赋值:
<Image x:Name="Img_Diplay" Height="360" Width="640" >
Img_Diplay.Source= writeableBitmap;
3.写入数据
writeableBitmap的WritePixels可以写入像素格式数据,sourceBuffer是数据的指针,sourceBufferSize是数据大小,sourceBufferStride是一行数据长度,如果sourceBufferStride是64位对齐性能会比较好。
writeableBitmap.WritePixels(new Int32Rect(0, 0, width, height), sourceBuffer, width * height * 3, width * 3,0,0);
三、示例
1.示例代码
https://download.csdn.net/download/u013113678/42003083
2.效果预览
视频框内放置控件:
圆角视频框:
通过绑定实现多个视频框显示同一个画面:
四、像素格式的讨论
由于目前WriteableBitmap只能写入rgb,所以渲染前需要将yuv格式的数据转成rgb再渲染。通常会认为这一步会导致性能下降,且消耗cpu。但是通过查资料了解到,渲染引擎渲染画面本质上也是使用rgb渲染的,很明显的一点就是,opengl渲染yuv是通过shader将yuv转换成了rgb再渲染的。所以这两种方式的不同是在于,转换像素格式的是cpu还是gpu。
1、使用d3d渲染yuv:
2、使用WriteableBitmap渲染rgb:
还有一种方案是转换的时候使用gpu(比如ffmpeg滤镜硬件加速),接着再使用图形引擎渲染(D3D9)。但这里会有一个问题,转换的数据在显存中,显示时需要从显存中拷贝到内存,渲染是又从内存拷贝到显存,这样效率是比较低的。所以这种方案意义是不大的。
五、性能对比
测试设备cpu是I7-8750H,测试方法是使用《C# wpf 使用d3d渲染yuv视频数据》的完整代码及本文的示例代码,对不同分辨率的视频进行播放,并记录进程的cpu和cpu使用率,记录方式是30秒内取5次值计算均值。
测试结果如下:
320p
cpu使用率(%) | gpu使用率(%) | |
---|---|---|
D3D9渲染 | 1.44 | 6.16 |
WriteableBitmap渲染 | 2.42 | 4.02 |
720p
cpu使用率(%) | gpu使用率(%) | |
---|---|---|
D3D9渲染 | 3.24 | 7.82 |
WriteableBitmap渲染 | 5.68 | 4.40 |
1080p
cpu使用率(%) | gpu使用率(%) | |
---|---|---|
D3D9渲染 | 6.72 | 12.58 |
WriteableBitmap渲染 | 9.94 | 7.1 |
不同分辨率差值比较(D3D9渲染减去WriteableBitmap渲染 ):
cpu使用率差值(%) | gpu使用率差值(%) | |
---|---|---|
320p | -0.98 | 2.14 |
720p | -2.44 | 3.42 |
1080p | -3.22 | 5.48 |
可以看出测试结果基本符合上一章的讨论,D3D9渲染cpu会低一些,但gpu会高一些。而WriteableBitmap渲染正好相反cpu高一些,gpu低一些。由于测试数据较少,对于哪种方案更优不好直接下定论。因为有时候cpu下降的gpu上去了未必就是性能提升,还是要看具体的数值,以及计算速度。
总结
今天讲述的这种视频渲染方法,其优点是不依赖d3d,直接使用wpf的对象进行渲染,与wpf控件契合度高。缺点是需要在cpu中转换像素格式,cpu使用率相对使用d3d要高一些。但总的来说这种方案简单易用,还是可以适用于大部分场景的。