C# wpf 使用d3d渲染dxva2解码数据

59 篇文章 30 订阅
本文介绍了如何在WPF应用中利用D3DImage对象,直接渲染DXVA2解码后的视频数据,避免了窗口句柄渲染的兼容性问题。通过创建RTTexture,设置D3DImage缓存,关联界面并渲染,实现了高效性能的视频显示。示例代码展示了具体实现步骤,并给出了与软解码和句柄渲染的性能对比,证明了D3DImage渲染的优越性。
摘要由CSDN通过智能技术生成

WPF视频渲染系列

第一章 使用HwndHost渲染视频
第二章 使用d3d渲染视频
第三章 使用d3d渲染dxva2数据(本章)
第四章 使用WriteableBitmap渲染视频



前言

使用dxva2解码渲染的方案是有的,通过窗口句柄关联d3d对象的方式直接渲染,性能相当好,但是在wpf中显然不太合适,嵌入hwnd窗口与wpf绘制不兼容,而且对于键盘事件也会有影响,最好的方式还是使用d3d渲染,本文主要讲述如何将dxva2解码的数据不经过转换,直接渲染到wpf的image上。


一、对象说明

1.dxva2解码Surface

对于dxva2解码,以ffmpeg使用dxva2为例,解码后的数据放在AVFrame.data[3]里面,是一个d3d9的Surface对象,里面装载着视频数据,数据格式通常为nv12。
下面是C#代码示例。

Play_VideoDisplay(IntPtr play, IntPtr[] data, int[] linesize, int width, int height, ACDll.ac_pixFormat format)
{
//data为ffmpeg的AVFrame.data
 var surface = Surface.FromPointer<Surface>(data[3]);
}

2.D3DImage

D3DImage是wpf提供与d3d互操作的对象。通常通过SetBackBuffer设置其背景缓存Surface,这个背景Surface就可以是d3d9的Surface对象,.AddDirtyRect更新前景Surface。与Image控件的source关联,显示到界面上。
在这里插入图片描述


二、如何实现?

1.创建RT Texture

需要渲染数据,必须先有一块缓存用来装载数据,因为dxva2解码出来的Surface对象数据格式通常是nv12不能直接使用,需要建立一个与设备格式兼容的缓存Texture,而且是RT类型,示例代码如下:

//data为ffmpeg的AVFrame.data,data[3]是d3d9 Surface对象
var surface = Surface.FromPointer<Surface>(data[3]);
//获取surface的device
var device = surface.Device;
//获取device的d3d对象
var d3d = device.Direct3D;
//通过device创建Texture
_texture = new Texture(device, width, height, 1, Usage.RenderTarget, d3d.GetAdapterDisplayMode(0).Format, Pool.Default);

2.设置D3DImage缓存

有了RT Texture,获取其内部的Surface作为D3DImage背景缓存。

//获取texture的surface
_textureSurface = _texture.GetSurfaceLevel(0);
//将texture的surface设置为D3DImage的背景缓存
_d3DImage = new D3DImage();
_d3DImage.Lock();
_d3DImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _textureSurface.NativePointer);
_d3DImage.Unlock();

3.关联界面

因为D3DImage是ImageSource的子类,可以直接作为Image控件的Source。

//img_display为Image控件对象
img_display.Source=_d3DImage;

4.渲染

建立好联系后,通过StretchRectangle方法拷贝Surface数据,AddDirtyRect进行界面刷新。

//surface为dxva2解码数据,_textureSurface为D3DImage的背景缓存
device.StretchRectangle(surface, _textureSurface, TextureFilter.Linear);
d3DImage.Lock();
d3DImage.AddDirtyRect(new Int32Rect(0, 0, width, height));
d3DImage.Unlock();

三、示例代码

https://download.csdn.net/download/u013113678/85160884


四、效果预览

视频框内放置控件:
在这里插入图片描述
i7 核显渲染 hevc 4k 60fps性能:
在这里插入图片描述


五、性能对比

测试视频:hevc 4k 60fps
测试设备:i7 8750h gpu使用核显
数据记录:30秒内取5次值计算均值

渲染方式cpu使用率(%)gpu使用率(%)
软解渲染24.5260.86
dxva2解码窗口句柄渲染0.7852.36
dxva2解码D3DImage渲染(本文)1.2256.04

看的出句柄渲染和D3DImage性能是比较接近的,相比之下软解渲染对性能的消耗就比较大了,所以D3DImage渲染dxva2是一个可用方案


总结

以上就是今天的内容了,曾以为dxva2解码渲染最佳性能方式只能通过窗口句柄渲染实现,但是经过尝试发现了通过D3DImage渲染也能够达到非常接近的性能,这样就很好的解决了在wpf中的绘制兼容问题,而且使用方式非常简单。


附录

1、C#操作d3d对象的库

通过nuget的方式获取,本文涉及到的库如下所示:
在这里插入图片描述

评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeOfCC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值