因为最近项目中有需求通过unity3D接入很多路rtsp视频流,为了更大的利用GPU,所以对每路rtsp视频流进行硬解码后变成NV12的视频帧,使用unity3D shader对其进行显示。
笔者对opengl和opengles比较熟悉,所以对于大同小异的unity3D的shader,基本也可以很快上手。
直奔主题吧,首先使用unity3D创建Unlit shader,创建RowImage,创建Material,shader绑定Material,Material绑定RowImage。
NV12根据其视频的内存布局格式,我们需要定义2个2D的纹理,一个去存放Y数据,其数据大小为视频的height*width,一个存放UV格式,其大小为height*width/2,如下:
private Texture2D texY, texU;
texY = new Texture2D(width, height, TextureFormat.Alpha8, false);
texU = new Texture2D(width/2, height/2, TextureFormat.RG16, false);
因为texU 纹理存放的实uv交替数据,所以,我们用TextureFormat.RG16,表示一个单元里存放一个u分量和一个V分量。
在update里加载数据显示,代码如下:
texY.LoadRawTextureData(rawdata.ydata);
texY.Apply();
texU.LoadRawTextureData(rawdata.uvdata);
texU.Apply();
rawImage.texture = texY;
rawImage.material.SetTexture("_UTex", texU);
以上是关键的c#代码,shader就很简单了,同样定义2个2D纹理。代码如下:
sampler2D _MainTex;
sampler2D _UTex;
然后再fragment着色器里通过2个纹理把Y和UV数据采样出来,转化为RGB即可,代码如下:
fixed4 frag (v2f i) : SV_Target
{
fixed4 col;
float y = tex2D(_MainTex, i.uv).a;
fixed4 uvs = tex2D(_UTex, i.uv);
float u = uvs.r - 0.5;
float v = uvs.g - 0.5;
float r = y + 1.403 * v;
float g = y - 0.344 * u - 0.714 * v;
float b = y + 1.770 * u;
col.rgba = float4(r, g, b, 1.0f);
return col;
}
最后实现效果如下:
太忙,稍后我会把demo发布。
这是我们的网站 www.founu.com,欢迎大家交流合作。