技术开发 频道

如何使用3D API 进行视频的高质量回放

[IT168 技术文档]近期正在制作关于如何使用3D API搭建一个高质量的视频回放后端的项目,目前公司的Backend从开始的支持RGB24,YUV的支持。随着质量的不断提高,尤其是播放质量被SONY这样苛刻的公司接受以后,总觉得该写一些东西总结一下了。

 

    其实要在3D 环境播放视频并不是件困难的事情,如果仅仅是想做一个视频纹理,那么完全可以放心的做很多假设,并且让美术提供的视频都必须满足你的假设,可以使用RGB24的格式。并选择让DirectShow来为你完成YUV-RGBcolor space的转化。也可以不考虑播放是不是完全流畅的,因为那仅仅是整个项目中的一个小小的部分,没人会关心这个部分的视频是不是流畅。

 

     但如果你做的是个播放器,一种用来播放视频的专向工具,那么质量问题以及兼容问题显得非常重要:

     1:  需要支持YUV格式,至少要支持一种: YV12

     2:  必须考虑播放的流畅性.,不能产生Frame drop现象。

     3:  必须适应Decoder出来的frame的步调,除了保证不丢帧以外,还需要保证不会有的帧在屏幕上停留时间太长或者太短。

     4:  最后不得不考虑性能问题,因为有些视频文件是巨大的。HD的视频在1920 x 1080 这样的分辨率水准是非常常见的。Decoder会在解码的动作上耗费掉大量的CPU,留给backend的时间并不多。

        就以上问题,总结起来是两个:YUV格式的支持。并且提供性能,保证播放流畅性能。

   

下面我来说说一些解决方案:

:YUV格式的支持.

     YUV格式其实有很多种,大类分成两类Packedplannar。前者是YUV是压缩到一个int32里的(注意压缩)。另外一种是YUV三个分量的数据分开保存,等于三个数组。

     我们知道用3D API中,用来保存图象的资源就是纹理。对于以上两类YUV格式显然是第一种比较自然一些。但是必须注意的是packedYUV格式通常是交错的。比如排列方式是YUYV这样排列。 因为对视频来说,Y亮度信息明显比UV色差信号要来的重要。所以说在4个字节中压缩进去两个像素的信息,这两个像素公用一个UV值。 这种格式就称为YUYV格式。

    除此之外还有其他很多对一般应用者来说可能是千奇百怪的格式. 因此,事实上packedYUV.只是看上去比较自然,实现起来却并不是那么简单轻松.即使是比较容易实现的YUYV格式,也很难实现它的平滑滤波.

      相反来说,对于plannarYUV格式, 我们虽然没办法用一个纹理来模拟它,但是完全可以采用三个纹理的方式来模拟它,这种方式几乎不需要在Pixel Shader做很多特殊处理,无非就是三个纹理采样动作而已.非常幸运的是,现在大部分的解码器都是直接输出YV12格式的,在一个分辨率是MxN大小的YV12格式中,的一块数据是MxNY信号.接下来是一块M/2 x N/2大小的U信号,最后是M/2 x N/2V信号,也就是说,Y信号的分辨率比UV大一倍. 这样我们可以用一个MxN跟两个M/2 x N/2纹理就可以模拟出YV12格式了.并且可以自由的使用各种纹理滤波方式.

    解决了如何把YUV信号输入到3D API,接下来就可以使用Pixel Shader来对采样的YUV信号进行调整,并转化成RGB信号,这个转化是非常简单的.代码如下:

sampler2D texYPlane; sampler2D texUPlane; sampler2D texVPlane; float4 main( float2 texCoord : TEXCOORD0 , float4 fColor : COLOR) : COLOR { float4 matYUV2RGB0 = float4 (1.0 , 0.0 , 1.14 , 0.0); float4 matYUV2RGB1 = float4 (1.0 , -0.390 , -0.58 , 0.0); float4 matYUV2RGB2 = float4 (1.0 , 2.03 , 0 , 0.0); //输入的YUV必须加个偏移量.详细细节参见www.fourcc.org float4 deltaYUV = float4 (-0.00 , -0.500 , -0.500 , 0.0); float4 yuvColor; //对三个纹理进行采样 float2 newTexCoord = float2(texCoord.x , texCoord.y); yuvColor.x = tex2D( texYPlane, newTexCoord ).x; yuvColor.y = tex2D( texUPlane, newTexCoord ).x; yuvColor.z = tex2D( texVPlane, newTexCoord ).x; yuvColor.w = 1.0f; yuvColor = yuvColor + deltaYUV; //adjust color yuvColor = adjustColor(yuvColor); float4 imageColor; //YUV 到RGB的转换 imageColor.x =dot(matYUV2RGB0.xyz , yuvColor.xyz); imageColor.y =dot(matYUV2RGB1.xyz , yuvColor.xyz); imageColor.z =dot(matYUV2RGB2.xyz , yuvColor.xyz); imageColor.w = 1.0; return imageColor; }
 关于adjustColor函数,主要是用来对对比度,饱和度等进行调节的,具体算法,在数字图象处理中都可以找到.关于详细的YUV资料,可以到www.fourcc.org上去找.

0
相关文章