Unity 工具之 YUV(YUV420 :I420,YV12,NV12,NV21)使用 shader 转为 RGB 显示 封装 YUV420ToRGBWrapper
目录
Unity 工具之 YUV(YUV420 :I420,YV12,NV12,NV21)使用 shader 转为 RGB 显示 封装 YUV420ToRGBWrapper
2、在工程中,新建几个脚本和shader(以及对应的Material),并导入yuv 数据资源
4、搭建场景,新建plane ,添加 3D Text,布置场景如图
5、把shader 材质赋给 plane,并把脚本挂载游戏物体上
6、运行场景,分别按下 N 键,或 I 键,就会解析 yuv 为 rgb,效果如上
一、简单介绍
Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发。
本节介绍如果把对应的YUV数据转为RGB,然后再 Unity中显示出来。
二、YUV相关知识
1、什么是 YUV
YUV是被欧洲电视系统所采用的一种颜色编码方法(属于PAL),是PAL和SECAM模拟彩色电视制式采用的颜色空间。在现代彩色电视系统中,通常采用三管彩色摄影机或彩色CCD摄影机进行取像,然后把取得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号B-Y(即U)、R-Y(即V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。采用YUV色彩空间的重要性是它的亮度信号Y和色度信号U、V是分离的。
Y分量主管亮度的(其实就是灰度图),U和V分量主管色彩的。所以即使没有U和V分量,一样可以看到图像,只是没有颜色罢了(只有黑白色)。如果不理解,想想我们小时候的黑白电视机和彩电,黑白电视机就是只有Y分量的图像,而彩电就是有三个分量的图像。所以YUV格式的视频数据也是当时美国用来适配黑白电视机和彩电的一种方案。
2、YUV 数据格式解析(YUV420 I420)
由图可见,I420格式的YUV数据的三个分量Y/U/V被分离在了3个连续的内存块中,而每个Y都会对应一个像素,每4个像素共用一组UV。所以一张 s = width x height 的图片,就会有 s 个像素,s 个Y,s / 4 个U和V。这张图片占用的内存 m = width * height * 1.5 byte 。
3、YUV 分类
这里以 YUV420 为例:
主要分为I420 , YV12,,NV12,,NV21,具体布局如下:
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
NV12: YYYYYYYY UV UV =>YUV420SP
NV21: YYYYYYYY VU VU =>YUV420SP
I420 图示:
YV12 图示:
NV12 图示:
NV21 图示:
4、YUV 转 RGB 公式
R = Y + 1.4022 *(V-128)
G = Y – 0.3456 *(U –128) –0.7145 *(V –128)
B = Y + 1.771 *(U – 128)
YUV2RGB的转换公式本身是很简单的,但是牵涉到浮点运算,所以,如果要实现快速算法,算法结构本身没什么好研究的了,主要是采用整型运算或者查表来加快计算速度。以上是在CPU里做的转换,本文将会把这种转换放到GPU里去做,毕竟GPU很擅长并行计算,对于这种粗鲁的运算,GPU是很快的。
在Unity 的 shader 中 RGB 表示范围是 [0,1],而不是[0,255],所以上面公式略作修改
R = Y + 1.4022 *(V-0.5)
G = Y –0.3456 *(U –0.5) – 0.7145 *(V –0.5)
B = Y + 1.771 *(U – 0.5)
三、实现原理
1、首先根据 YUV 对应格式的 YUV 的排列方式,拆分 YUV;
2、然后,在通过 YUV 与 RGB 转换对应公式,进行转换;
3、最后,shader 方式显示出来;
4、调用接口,YUV420ToRGBWrapper.YUV420ToRGB(YUV420 yuv420_Format, byte[] data, int width, int height, Renderer renderer),设定YUV 格式,数据,宽、高、以及目标的渲染的 Renderer ,即可实现 YUV 转 RGB
四、注意实现
1、如果解析出来的画面翻转颠倒,可以直接在shader 中调整 uv 的 x y 转正;
2、注意区分 YUV 的格式,每种YUV 排列会略有不同,对应解析才能出来画面原版本效果;
3、在Unity 的 shader 中 RGB 表示范围是 [0,1],而不是[0,255];