DXVA2解码数据用texture纹理渲染

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

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

时间: 2024-10-12 04:58:17

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

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

简单记录一下这两天用Texture实现渲染YUV420P的一些要点. 在视频播放的过程中,有的时候解码出来的数据是YUV420P的.表面(surface)通过设置参数是可以渲染YUV420P的,但Texture纹理似乎不支持直接渲染YUV420P.表面(surface)用法似乎比较单一,通常用来显示数据,用Texture的话就可以用上D3D的许多其他功能,做出一些效果.当然,这看个人需求,通常而言显示视频数据用表面就够了. 1.利用像素着色器把YUV420P数据转为RGB32 视频播放过程中帧与

CUDA Texture纹理存储器 示例程序

原文链接 1 /* 2 * Copyright 徐洪志(西北农林科技大学.信息工程学院). All rights reserved. 3 * Data: 2012-4-20 4 */ 5 // 6 // 此程序是演示了1D和2D纹理存储器的使用 7 #include <stdio.h> 8 #include <cutil_inline.h> 9 #include <iostream> 10 using namespace std; 11 12 texture<fl

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

概述 包括以下5种优化:引擎底层优化.纹理优化.渲染优化.资源缓存.内存优化 引擎优化 2.0版本比1.0版本在算法上有所优化,效率更高.2.0版本使用OpenGl ES 2.0图形库,1.0版本使用OpenGL ES 1.0. 纹理优化 纹理是最消耗内存的,而且会降低渲染速率. 二的幂次方 OpenGL在申请内存存放纹理时,是按2的幂次方申请的,即对应480*320的图片,它申请的是512*512空间.可见,会有相当多的内存被浪费.所以,我们设计的图片,最好是2的幂次方,不然OpenGL最终还

微信小程序 修改数据,并动态渲染页面;修改数组;

一.修改数据,并在页面动态渲染 this.setData({ txt: '12112' }) 二.修改数组 var rotateClassItem = 'rotateClass['+ index + ']'; that.setData({ [rotateClassItem]: !that.data.rotateClass[index] }) 原文地址:https://www.cnblogs.com/siyecao2010/p/10083896.html

Texture的渲染大图裁剪成小图并保存下来

我们今天就简单说下 cocos2d的Texture的简单用法,并将一张大图裁剪成小图并保存起来 我们先准备一张大图,如下: 只看图,表太在意内容啊. 我们的目的就是将这张大图裁剪成一张张的小图并保存下来. 首先,我们要将它裁剪成一张张的小图,小图的大小自己计算哈,我就不告诉你w=Width/5,h=(Height-108)/8的: 然后,将裁剪出来的小图一张张的绘制出来: 最后,将绘制的每一张保存起来. 我怎么这么多话啊,说了这么多,一行代码也写呢,好了,直接上代码: auto size = D

开放视频编码(H.264)编解码数据输入、输出接口

AnyChat是一套开放的音视频即时通信解决方案,早期的版本已经开放了原始数据的输入.输出接口:1.通过客户端回调函数可以输出用户原始的视频采样帧数据(YUV.RGB):视频数据回调函数2.通过外部数据输入接口可以支持将外部的视频帧传给AnyChat进行编码:如何使用外部音视频数据输入功能? 对于某些特定的场合,上层应用希望获取AnyChat内核原始的H.264编码数据,或是希望将H.264编码之后的数据传输给AnyChat,自AnyChat r4268版本开始提供了支持,该特性将给AnyCha

react之异步请求数据,render先行渲染报错,未拿到数据

import React from 'react' import {connect} from 'react-redux' import { Redirect} from 'react-router-dom' import axios from 'axios' import {login} from './Auth.redux.js' //两个reducers 每个reducers都有一个state @connect( (state)=>state.auth, {login} ) class A

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

关于,这个问题呢!一直没有在网上找到一个合适答案(可能这问题比较傻,嘿嘿).今天把自己常用几种方式说下: 第一种: 比较常见的就是直接把字符串拼接,然后插入到元素中. var html='<li>' + data.num + '</li><li>' + data.floor + '</li><li>' + data.name + '</li><li>' + data.money + '</li>'; elem.

Chromium硬件加速渲染的GPU数据上传机制分析

在Chromium中,WebGL端.Render端和Browser端通过命令缓冲区将GPU命令发送给GPU进程执行.GPU命令携带的简单参数也通过命令缓冲区发送给GPU进程,但是复杂参数,例如纹理数据,有可能太大以致命令缓冲区无法容纳,因此需要通过其它机制传递给GPU进程.本文接下来就主要以纹理数据上传为例,分析WebGL端.Render端和Browser端将GPU命令数据传递给GPU进程的机制. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! WebGL