我是靠谱客的博主 狂野萝莉,最近开发中收集的这篇文章主要介绍D3d/opengl texture yuv yuv420p nv12 yv12 等等 显示 以及传入shaderresource,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

msdn中关于yuv的详细介绍:
视频渲染推荐的 8 位 YUV 格式 - Win32 apps | Microsoft Learn
里面介绍nv12 yv12 只能算是一种texture array,但是又比较特殊的array

为何要用nv12 或nv21?
官方解释是方便渲染使用。个人理解 :方便将nv12(
DXGI_FORMAT_NV12)或nv21(DXGI_FORMAT_NV21)数据放到一个texture中,然后通过shader进行渲染。nv12与nv21区别是u与v的存放空间的位置问题,一个在前一个在后。
下面是msdn中对nv12 aligned 格式的图例描述(y:width,height  ;uv:width,height/2)memory(width*height*3/2)

类似的还有DXGI_FORMAT_P010(YV12 10bit)和DXGI_FORMAT_P016(YV12 16bit),DXGI_FORMAT_420_OPAQUEY(YV12 8bit)。
下面是msdn中对yv12 aligned 格式的图例描述(y:width,height ;u:width/2,height/2 ;v:width/2,height/2)  memory(width*height*2)

从上面的截图可以看出,nv12相比于yv12的优势在空间利用率更高。因为空间都是成块的申请的,很显然上面的yv12中,在u和v的后面部分被空余了。


如果原始数据在cpu内存中是420p(YV12),一般存储是连续的,而不是aligned 的 ,如果要放到texture中,需要做aligned 操作和必要的转换。(aligned的目的是使内存块按行列对齐,使可以通过横纵坐标来访问。迎合texture的这一个基本的需求)

nv12 nv21 最终都是需要转换成rgb或rgba的。一般在自己写的shader中转换。
 

参考:
DXGI_FORMAT (dxgiformat.h) - Win32 apps | Microsoft Learn
How to read DXGI_FORMAT_NV12 or DXGI_FORMAT_P010 texture in Direct3D shader - Graphics and GPU Programming - GameDev.net
NV12 textures not working in DirectX 11.1

在D3d9中可以通过surface来显示
测试成功案例:使用D3D渲染YUV_RGB_Zoe今忆的博客-CSDN博客_d3d渲染yuv

在D3D11中可以通过ID3D11VideoDecoderOutputView 来显示。

对于想将nv12 传入shader resource的同学 ,坑定 会 遇到nv12 作为shader resource传入的问题。通过ShaderResourceView 可以巧妙的让y和uv分开显示。msdn的说法就是y和uv需要放到两个view中显示。

可通过下面方式进行操作:
一个nv12 texture 可以直接放到srv数组中。这样在shader中被当做两个纹理来使用。(可以将nv12 texture理解为一个特殊的纹理数组)

c++代码中:
void init(){
    hr = g_pd3dDevice->CreateSamplerState( &sampDesc, &g_pSamplerLinear[0] );
    if( FAILED( hr ) )
        return hr;
	hr = g_pd3dDevice->CreateSamplerState(&sampDesc, &g_pSamplerLinear[1]);
	if (FAILED(hr))
		return hr;
    SRVDesc.Format = DXGI_FORMAT_R8_UNORM;//y
    SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
    SRVDesc.Texture2D.MipLevels = 1;
    hr = g_pd3dDevice->CreateShaderResourceView(tex, &SRVDesc, &g_pTextureRV[0]);//srv[0]映射到y的地址上去了
    SRVDesc.Format = DXGI_FORMAT_R8G8_UNORM;//DXGI_FORMAT_R8G8_UNORM //uv 
    hr = g_pd3dDevice->CreateShaderResourceView(tex, &SRVDesc, &g_pTextureRV[1]); //srv[1] 映射到了uv的地址上去了
}

void update()
{
    g_pImmediateContext->PSSetShaderResources( 0, 2, g_pTextureRV ); //将srv数组传入
}



PS中
Texture2D txDiffuse : register( t0 ); //指向了srv数组的的第一个成员(实际是y)
SamplerState samLinear : register( s0 );
Texture2D txDiffuse1 : register(t1);//指向了srv数组的第二个成员(实际是uv)
SamplerState samLinear1 : register(s1);

可参考D3D11 texture 创建 NV12 YV12 YUV420 cpu 访问 内存分布 拷贝 map updateresource copyresource_丘上人的博客-CSDN博客来测试。记得设置bindflag为D3D11_BIND_SHADER_RESOURCE

yuv转换函数
float4 yuvtorgb(float y,float u,float v){
    y = y*255;u = u*255;v = v*255;
    float4 rgba;
    rgba.r = clamp((y + 1.402*(v - 128))/255.0f,0,1.0f);
    rgba.g = clamp((y - 0.34414*(u - 128) - 0.71414*(v - 128))/255.0f,0,1.0f);
    rgba.b = clamp((y + 1.772*(u - 128))/255.0f,0,1.0f);
    rgba.a = 1.0f;
    return rgba;
}

参考:How to convert DXGI_FORMAT_NV12 to DXGI_FORMAT_R8G8B8A8_UNORM?

good luck。

最后

以上就是狂野萝莉为你收集整理的D3d/opengl texture yuv yuv420p nv12 yv12 等等 显示 以及传入shaderresource的全部内容,希望文章能够帮你解决D3d/opengl texture yuv yuv420p nv12 yv12 等等 显示 以及传入shaderresource所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部