TOP

D3D三层Texture纹理经像素着色器实现渲染YUV420P(一)
2017-10-13 10:22:07 】 浏览:10433
Tags:D3D 三层 Texture 纹理 像素 着色 实现 渲染 YUV420P

    简单记录一下这两天用Texture实现渲染YUV420P的一些要点。

    在视频播放的过程中,有的时候解码出来的数据是YUV420P的。表面(surface)通过设置参数是可以渲染YUV420P的,但Texture纹理似乎不支持直接渲染YUV420P。表面(surface)用法似乎比较单一,通常用来显示数据,用Texture的话就可以用上D3D的许多其他功能,做出一些效果。当然,这看个人需求,通常而言显示视频数据用表面就够了。

1.利用像素着色器把YUV420P数据转为RGB32

   视频播放过程中帧与帧之间是有固定时间间隔的。若解码解出来的是YUV420P的数据,要用Texture渲染的话,就需要把数据转为RGB32的(应该是要转成RGB32的,没做过详细调查,看到的例子中纹理所用的数据都是RGB32的),如果这个过程交给CPU去做的话,会提高CPU的占用率,用GPU来做这项工作则就释放了CPU的一部分压力。

    本文考虑的方式是用三层纹理分别存放YUV420P的Y、U、V分量(这个词不知道用对没有),然后像素着色器把三个分量的数据计算成RGB32的数据然后显示。这是本文的核心内容。

像素着色器的HLSL代码如下:

sampler YTex;
sampler UTex;
sampler VTex;


struct PS_INPUT
{
    float2 y    : TEXCOORD0;
    float2 u    : TEXCOORD1;
    float2 v    : TEXCOORD2;
};


float4 Main(PS_INPUT input):COLOR0
{      
    float y = tex2D(YTex,input.y).r;
    float u = tex2D(UTex, input.u.xy / 2).r  - 0.5f;
    float v = tex2D(VTex,input.v.xy / 2).r  - 0.5f;            
                
    float r = y + 1.14f * v;
    float g = y - 0.394f * u - 0.581f * v;
    float b = y + 2.03f * u;
                
    return float4(r,g,b, 1);
}

     HLSL代码可以直接写在txt文件中,sampler可视作标识纹理层和采样级的对象,Direct3D将把每一个sampler对象唯一地与某一纹理层关联起来。具体的HLSL语法请自行查资料,我也是粗略知道是怎么回事,就不误人子弟了。在代码中通过调用D3DXCompileShaderFromFile函数可以从文件编译像素着色器。但实际上,我个人不是很喜欢这种把代码放在一个单独文件里面的做法,这种代码应该尽可能的编进exe里面。但是我还只是初步了解D3D,不知道怎么把它编进exe里面,如果有人知道,还望指教。

ID3DXBuffer* shader      = 0;
ID3DXBuffer* errorBuffer = 0;

hr = D3DXCompileShaderFromFile(
    "ps_multitex.txt",
    0,
    0,
    "Main", // entry point function name
    "ps_2_0",
    D3DXSHADER_DEBUG, 
    &shader,
    &errorBuffer,
    &MultiTexCT);

// output any error messages
if( errorBuffer )
{
    ::MessageBox(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
    d3d::Release<ID3DXBuffer*>(errorBuffer);
}

if(FAILED(hr))
{
    ::MessageBox(0, "D3DXCompileShaderFromFile() - FAILED", 0, 0);
    return false;
}

//
// Create Pixel Shader
//
hr = Device->CreatePixelShader(
    (DWORD*)shader->GetBufferPointer(),
    &MultiTexPS);

if(FAILED(hr))
{
    ::MessageBox(0, "CreateVertexShader - FAILED", 0, 0);
    return false;
}

d3d::Release<ID3DXBuffer*>(shader);

以上代码中,D3DXCompileShaderFromFile函数从文件ps_multitex.txt编译HLSL代码;参数Main是HLSL代码的入口函数,如上一点代码中所见。这个入口函数可以是自定义的其他的,但要注意保持一致;ps_2_0表示像素着色器的版本。CreatePixelShader函数创建像素着色器。

2.sampler与纹理关联

    创建纹理层。本文实现YUV420P渲染的方法采用了三层纹理,每层纹理分别存放Y、U、V数据。

Device->CreateTexture ( Width, Height, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &YTex, NULL ) ;
Device->CreateTexture ( Width / 2, Height / 2, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &UTex, NULL ) ;
Device->CreateTexture ( Width / 2, Height / 2, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &VTex, NULL ) ;

    sampler与纹理的关联

// 
// Get Handles
//

YTexHandle      = MultiTexCT->GetConstantByName(0, "YTex");
UTexHandle        = MultiTexCT->GetConstantByName(0, "UTex");
VTexHandle        = MultiTexCT->GetConstantByName(0, "VTex");

//
// Set constant descriptions:
//

UINT count;

MultiTexCT->GetConstantDesc(YTexHandle,      &YTexDesc, &count);
MultiTexCT->GetConstantDesc(UTex  
		
D3D三层Texture纹理经像素着色器实现渲染YUV420P(一) https://www.cppentry.com/bencandy.php?fid=49&id=160844

首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇java数据类型 下一篇链表的逆置(又称反转)