缩放IDirect3DSurface9

时间:2017-01-17 21:41:50

标签: performance scaling direct3d surface

我正在开发一种特殊的视频播放器,它在每个解码帧上应用“过滤器”。我目前的目标是缩放解码帧(当然除了内存限制之外没有约束)。

使用ffmpeg(av_read_frame,avcodec_send_packet,avcodec_receive_frame)完成解码部分。 Media Foundation的EVR用作视频渲染。 更准确地说,我检索一个“样本”(它只是d3d普通屏幕外表面的包装),ffmpeg使用这个缓冲区来存储解码后的帧,然后我将这个“样本”提供给缓存它的渲染器,然后将其呈现在需要时的屏幕(来自采样时间戳,播放速率和系统时钟的演示时间)。

我从可用曲面池(通过IMFVideoSampleAllocator)检索曲面(format = X8R8G8B8,type = D3DRTYPE_SURFACE,usage = 0,pool = D3DPOOL_DEFAULT,multisample = DDMULTISAMPLE_NONE)。需要使用RGB32数据,并在需要时转换解码帧。

关于缩放功能/缩放过滤器,我首先使用带有SWS_FAST_BILINEAR的libswscale(sws_scale函数),但需要大约80ms才能将我的帧从1920x800调整为1920x400(用于测试目的的固定值)。然后我尝试使用天真的双线性算法进行自我缩放,但情况更糟,需要很长时间才能完成。

我做了一个最小的测试用例,它加载一个BMP文件,对其进行扩展并将缩放后的数据写入另一个BMP。 令人惊讶的是,相同的代码需要大约15毫秒(libswcale)或大约30毫秒(天真的双线性)。

然后我修改了我的视频播放器以使用av_image_alloc和av_image_copy_to_buffer。分配不需要时间,复制需要一秒钟,缩放需要5毫秒。整个部分太慢而无法实时缩放,但它表明内存“原点”(malloc'ed或d3d表面)之间存在很大差异。

数据对齐可能是缓慢的原因,但我的测试用例在内存中使用相同的模式(stride = width * 4,自下而上),而且速度要快得多。我打印输入和输出缓冲区%16,它为0,所以对我来说似乎是安全的。

我也尝试过使用StretchRect方法,但它在屏幕外表面之间不起作用。

有什么想法吗? 注意:我计划创建表面并自己呈现它们,因此渲染器部分对我来说是一种弱依赖。 因此,如果您有一个简单的D3D样本作为参考,我会接受它。

1 个答案:

答案 0 :(得分:1)

我研究了#34; EVRPresenter sample"调用IDirect3DSwapChain9 :: Present方法时,代码和缩放是通过source / dest RECT完成的,所以我猜测IDirect3DDevice9 :: StretchRect是正确的方法。

由于它不支持屏幕外平面之间的拉伸,我用IDirect3DDevice9 :: CreateRenderTarget创建了一个渲染目标表面,现在,StretchRect调用工作。 缩放甚至足以显示4K视频而没有任何抖动! 我使用libswscale作为后退。

@VuVirt 我目前正在使用支持DXVA的EVR,所以我猜它在内部使用。我会仔细阅读API,当我写自己的演示者时,我可能会使用它。

我意识到它实际上是混合/缩放/呈现帧的渲染器工作。我当前的代码有效,但我依赖于渲染器内部。渲染器可以在某个时刻使用Direct3D10接口StrectRect is not available in Direct3D10

无论如何,感谢阅读!