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. python爬虫中文乱码解决方法

    python爬虫中文乱码 前几天用python来爬取全国行政区划编码的时候,遇到了中文乱码的问题,折腾了一会儿,才解决.现特记录一下,方便以后查看. 我是用python的requests和bs4库来实 ...

  2. python3 爬虫之Pyquery的使用方法

    安装 pip install pyquery 官方文档: https://pythonhosted.org/pyquery/ 初始化方式(四种) 1. 直接字符串 from pyquery impor ...

  3. WebUploader 上传插件结合bootstrap的模态框使用时选择上传文件按钮无效问题的解决方法

    由于种种原因(工作忙,要锻炼健身,要看书,要学习其他兴趣爱好,谈恋爱等),博客已经好久没有更新,为这个内心一直感觉很愧疚,今天开始决定继续更新博客,每周至少一篇,最多不限篇幅. 今天说一下,下午在工作 ...

  4. Linux系统常用命令示例

    1.在跟下创建一个目录,目录的名字为data # mkdir /data2.在data目录里创建一个文件,文件名为yunjisuan.txt # touch /data/yunjisuan.txt3. ...

  5. fzu1901Period II

    地址:http://acm.fzu.edu.cn/problem.php?pid=1901 题目: Problem 1901 Period II Accept: 442    Submit: 1099 ...

  6. ARKit 研究笔记一

    软件需求:Xcode9.x .blender 硬件需求:iphone 6s + 系统:iOS 11 + 技能储备: ARKit .SceneKit(苹果提供的3d游戏库) 或 SpriteKit(苹果 ...

  7. :Linux 系统日志管理 日志转储

    Linux日志服务器设置 使用“@IP:端口”或“@@IP:端口”的格式可以把日志发送到远程主机上. 假设需要管理几十台服务器,每天的重要工作就是查看这些服务器的日志,可是每台服务器单独登录,并且查看 ...

  8. 【转】安装Vue.js的方法

    安装vue.js的方法   一.简介 Vue.js 是什么 Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量 ...

  9. linux卸载mysql

    第二.停止MYSQL运行以及卸载老版本 service mysqld stop #暂停MYSQL yum remove mysql mysql-*  #卸载老版本MYSQL 通过上面的命令,我们先停止 ...

  10. [pixhawk笔记]8-半物理仿真环境

    通过半物理仿真,可以在不试飞的情况下对飞控的软硬件进行部分验证,下面结合文档对半物理仿真环境的搭建和运行进行学习.先跑起来再说. Pixhawk支持多轴和固定翼的仿真,多轴用jMavSim,固定翼用X ...