FFmpeg DXVA2解码得到的数据使用surface来承载的,surface限制很多,如果能用纹理来渲染的话,那我们就可以充分开发D3D,比如可以用坐标变换来实现电子放大的功能,还可以用坐标变换来实现视频图像任意角度的旋转等功能。而对于我来说,最重要的是纹理渲染可以使得解码后的数据能够用像素着色器来做简单的视频图像处理,如果是用的是D3D11,对于更为复杂的视频图像处理算法也是有望可以用Compute Shader实现,以便充分利用显卡来加速和释放CPU。

DXVA2解码数据用纹理渲染的方法其实就是D3D中的渲染到纹理,只是有几个参数需要注意一下。

1.纹理设置

纹理设置与常规的纹理使用流程一样。

static bool setup_texture(IDirect3DDevice9* Device, int Width, int Height,D3DFORMAT format)
{
if (!Device)
{
return false ;
} HRESULT hr = 0; hr = Device->CreateVertexBuffer(
4 * sizeof(Dxva2TexVertex),
D3DUSAGE_WRITEONLY,
Dxva2TexVertex::FVF,
D3DPOOL_MANAGED,
&QuadVB,
0); Dxva2TexVertex* v = 0;
QuadVB->Lock(0, 0, (void**)&v, 0);
v[0] = Dxva2TexVertex(-20.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[1] = Dxva2TexVertex( 20.0f, 20.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
v[2] = Dxva2TexVertex( 20.0f, -20.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
v[3] = Dxva2TexVertex(-20.0f, -20.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
QuadVB->Unlock(); D3DXMATRIX P;
D3DXMatrixPerspectiveFovLH(&P,
D3DX_PI * 0.5f,
1.0f,
1.0f, //近裁减面到坐标原点的距离
1000.0f //远裁减面到原点的距离
);
Device->SetTransform(D3DTS_PROJECTION, &P);
Device->SetRenderState(D3DRS_LIGHTING, false); D3DXVECTOR3 position( 0.0f, 0.0f, -20.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);//计算取景变换矩阵
Device->SetTransform(D3DTS_VIEW, &V);//取景变换 hr = Device->CreateTexture ( Width, Height, 1, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &g_SurfaceTexture, NULL ) ;
if (FAILED(hr)) return false; g_SurfaceTexture->GetSurfaceLevel(0, &g_OffScreenSurface); return true;
}

其中需要注意其中的以下代码:

hr = Device->CreateTexture ( Width, Height, 1, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &g_SurfaceTexture, NULL ) ;
if (FAILED(hr)) return false; g_SurfaceTexture->GetSurfaceLevel(0, &g_OffScreenSurface);

CreateTexture的第四个参数注意设置为D3DUSAGE_RENDERTARGET,第五个参数format与设置D3D时的参数中的  d3dpp.BackBufferFormat = d3ddm.Format;  保持一致,详见工程源码。GetSurfaceLevel能够拿到具体某个level的mipmap的surface,我获取的是g_SurfaceTexture在level为0的surface,即g_OffScreenSurface。

2.渲染到纹理

渲染过程是先把DXVA2解码的数据先渲染到纹理,然后通过纹理来显示数据的。

static int dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame)
{
LPDIRECT3DSURFACE9 surface = (LPDIRECT3DSURFACE9)frame->data[3];
InputStream *ist = (InputStream *)s->opaque;
DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx; HRESULT hr ;
int ret = 0 ; EnterCriticalSection(&cs); if (ctx->d3d9device && g_OffScreenSurface)
{
ctx->d3d9device->SetRenderTarget(0, g_OffScreenSurface);
ctx->d3d9device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(200, 200, 200), 1.0f, 0);
ctx->d3d9device->BeginScene();
ctx->d3d9device->SetTexture(0, NULL);
GetClientRect(d3dpp.hDeviceWindow, &m_rtViewport);
ctx->d3d9device->StretchRect(surface, NULL, g_OffScreenSurface, NULL, D3DTEXF_LINEAR);
ctx->d3d9device->EndScene(); ctx->d3d9device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackBuffer);
ctx->d3d9device->SetRenderTarget(0, m_pBackBuffer); ctx->d3d9device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0); ctx->d3d9device->BeginScene();
ctx->d3d9device->SetTexture(0, g_SurfaceTexture);
ctx->d3d9device->SetFVF(Dxva2TexVertex::FVF);
ctx->d3d9device->SetStreamSource(0, QuadVB, 0, sizeof(Dxva2TexVertex));
ctx->d3d9device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2); ctx->d3d9device->EndScene();
hr = ctx->d3d9device->Present(NULL, NULL, NULL, NULL);
if (FAILED(hr)) {
if (ctx->d3d9device->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
{
printf("Failed to Present !") ;
ret = -1 ;
}
}
else
{
ret = 0 ;
}
} LeaveCriticalSection(&cs); return ret;
}

可以看到代码中有两组

ctx->d3d9device->BeginScene();
····
ctx->d3d9device->EndScene();

第一组通过  ctx->d3d9device->SetRenderTarget(0, g_OffScreenSurface);  把渲染目标设置为纹理的surface,把DXVA2解码得到的数据渲染到前面准备好的纹理的surface中;第二组则把渲染目标设为后台缓存,直接把纹理渲染出来即可。做这一层折腾的原因在于StretchRect函数的一个限制,

大意就是如果源或者目的surface是个纹理surface,就需要查看驱动是否支持,而

详见https://msdn.microsoft.com/en-us/library/windows/desktop/bb174471(v=vs.85).aspx

所以我在前面强调创建纹理的第四个参数注意设置为D3DUSAGE_RENDERTARGET。起初我也是因为这个参数设错了,一直没法成功,后来突然想到RT texture可能是指设为D3DUSAGE_RENDERTARGET的texture,RT可能是RENDERTARGET的缩写,然后才成功的。Off-screen plain指离屏表面,我对D3D的一些概念不是特别清楚,不知道承载DXVA2解码数据的surface是不是离屏表面,但我试了许多方法,只有这样才最后成功。如果这一块的理解有问题,欢迎拍砖指教。

对于FFmpeg DXVA2硬解有疑问的,可以参考http://www.cnblogs.com/betterwgo/p/6125507.html。对于D3D有疑问的,请自行上网查询,我懂的也不多,可以相互交流一下。

完整工程源码:http://download.csdn.net/download/qq_33892166/9742467

运行工程的时候注意修改代码中视频文件的路径。

DXVA2解码数据用texture纹理渲染的更多相关文章

  1. D3D三层Texture纹理经像素着色器实现渲染YUV420P

    简单记录一下这两天用Texture实现渲染YUV420P的一些要点. 在视频播放的过程中,有的时候解码出来的数据是YUV420P的.表面(surface)通过设置参数是可以渲染YUV420P的,但Te ...

  2. SDL 开发实战(五): SDL 纹理渲染

    本文我们讲一下如何使用SDL_Texture将视频纹理渲染出来. 1. SDL 视频渲染相关对象 SDL 视频渲染主要涉及到四个对象:SDL_Window.SDL_Render.SDL_Texture ...

  3. CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探

    CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...

  4. [Android]使用AdapterTypeRender对不同类型的item数据到UI的渲染

    以下内容为原创,转载请注明: 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3992843.html 本文讲的工具均放在AndroidBucket开源 ...

  5. 使用AdapterTypeRender对不同类型的item数据到UI的渲染

    要实现聊天功能中的发送不同类型的信息,比如纯文本.图片.语音.图文混排多媒体的数据等(具体效果看微信). 这里使用AdapterTypeRender在BaseTypeAdapter(这个之后会讲到)中 ...

  6. Vue2.0源码学习(1) - 数据和模板的渲染(上)

    准备 一.首先去GitHub上把vue源码download下来,传送门:https://github.com/vuejs/vue 二.搭建一个vue-cli跑起来,用于代码调试,不看着代码动起来只看源 ...

  7. 转 cocos2d-x 优化(纹理渲染优化、资源缓存、内存优化)

    概述 包括以下5种优化:引擎底层优化.纹理优化.渲染优化.资源缓存.内存优化   引擎优化 2.0版本比1.0版本在算法上有所优化,效率更高.2.0版本使用OpenGl ES 2.0图形库,1.0版本 ...

  8. CUDA Texture纹理存储器 示例程序

    原文链接 /* * Copyright 徐洪志(西北农林科技大学.信息工程学院). All rights reserved. * Data: 2012-4-20 */ // // 此程序是演示了1D和 ...

  9. ajax获取数据后怎么去渲染到页面?

    $.ajax({ url:"apiAttachmentAction_uploadAttachment.action", type:"post", data:fo ...

随机推荐

  1. C++学习笔记--友元

    C++控制对类对象私有部分的访问,在外部无法直接访问类的私有或保护成员.通常,公有类方法提供唯一的访问途径.有时这种限制太严格,不适合特定的编程问题.所以C++提供了友元这种形式,通过让函数或类成为类 ...

  2. 长网址 短网址(http://www.zhihu.com/question/19852154?rf=21975802)

    短网址(Short URL),顾名思义就是在形式上比较短的网址.通常用的是asp或者php转向,在Web 2.0的今天,不得不说,这是一个潮流.目前已经有许多类似服务,借助短网址您可以用简短的网址替代 ...

  3. vue工程权限怎么配置?

    vue工程权限怎么配置? router.beforeEach((to, from, next) => { }):方法的to参数能拿到router设置的对象信息,如: { path: " ...

  4. 验证APNS证书的有效性

    openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert xxx.pem

  5. 【c++ primer, 5e】函数声明 & 分离式编译

    p186~p188: 函数声明1.函数只能定义一次,但是可以声明多次. 2.函数的接口:返回类型 + 函数名 + 形参类型 3.为什么要在头文件中进行函数声明???在源文件中定义?暂时理解到,这么做可 ...

  6. Python3.x:打包为exe执行文件(window系统)

    Python3.x:打包为exe执行文件(window系统) window系统下发布: 一.安装pyinstaller(PyInstaller 3.3.1) cmd安装命令: pip install ...

  7. crontab + rsyncd同步方案

    目的主机: rsync --daemon [root@iZ23ohdbxmrZ ~]# vim /etc/rsyncd.conf #global settingsport = 873pid file= ...

  8. 2017年4月16日 一周AnswerOpenCV佳作赏析

    2017年4月16日 一周AnswerOpenCV佳作赏析 1.HelloHow to smooth edge of text in binary image, based on threshold. ...

  9. # 20145314《信息安全系统设计基础》期中复习总结 Part B

    20145314<信息安全系统设计基础>期中复习总结 Part B 学习知识点内容总结 复习线索:http://group.cnblogs.com/topic/73069.html 本周的 ...

  10. Apache ab 测试结果的分析

    以前安装好APACHE总是不知道该如何测试APACHE的性能,现在总算找到一个测试工具了.就是APACHE自带的测试工具AB(apache benchmark).在APACHE的bin目录下.格式: ...