视频YUV/RGB格式解析

2017-03-06

版权声明:本文为作者原创文章,可以随意转载,但必须在明确位置表明出处!!!

视音频格式:

RGB/YUV视频像素格式,大多数摄像头采样的像素格式都是YUV格式。PCM音频采样数据,H.264/H.265视频编码格式,AAC音频编码格式,FLV封装数据格式,UDP/RTP协议数据

音视频解码流程:

YUV格式:

YUV格式分为planar格式和packed格式

  • planar格式:首先连续存储所有的Y像素点,然后存储U像素点,最后存储V像素点。
  • packed格式:每个像素点的YUV分量是连续交叉存储的。

  • Y分量:表示明亮度即灰度值,如果我们要在一帧YUV格式的图片里得到灰度图像只需要把所有的Y分量分离出来就可以了,下面我们会讲到。

  • UV分量:表示色彩和饱和度

YUV采样

  • YUV4:4:4采样:每一个Y对应一组UV分量
  • YUV4:2:2采样:每两个Y对应一组UV分量
  • YUV4:2:0采样:每四个Y对应一组UV分量

我们以一个YUV420p格式的数据为例分析一下YUV格式是如何存储的,若有一张YUV420p格式大小为720 * 488大小的图片,那么他的存储格式为:720 * 488 * 3 / 2,因YUV420p为每4个Y共用一组UV分量,若以一个2 * 2大小的图像,那么它的存储格式就是 2 * 2 * 3 / 2 = 6正好是YYYYUV,所以对于720 * 488大小的图像其Y分量为:

  • Y: 720 * 488
  • U: 720 * 488 —-> 720 * 488 * 5 / 4 U分量是从第5个位置还是存储的。YYYYU
  • V: 720 * 488 * 5 / 4 —-> 720 * 488 * 6 / 4 = 720 * 488 * 3 / 2 V分量是从第6个位置开始存储的YYYYUV

YUV视频像素格式解析

下面我们通过一个YUV视频格式文件来分析一下YUV420p是不是按照上面所有格式存储的。下图是一个256 * 256格式为YUV420p格式的文件

通过上面的公式我们能够算出Y分量的大小为 256 * 256 = 65536 = 0x0001 0000所以Y分量的大小应该在地址0x0001 0000处也就是下图所示(这里需要主要的是地址是从0开始存储的,所以Y分量的大小是0x0000 0000 –> 0x000fff0 = 65535):

跟着Y分量存储的是U分量,U分量的大小根据公式可以知道为 256 * 256 * 5 / 4 = 81920 = 0x0001 4000所以U分量的大小应该为81920 - 65536 = 16384个字节,所以U分量应该从0x0001 0000这一行到0x0001 4000地址所在的一行为止,如下图:

跟着U分量存储的是V分量,V分量应该从地址0x00014000地址开始到文件结尾。

下面我们通过编码分离一个YUV420P格式的YUV分量分别写入到三个文件,然后跟上面的分析结果对比一下看看计算的是否正确。代码借鉴一下雷神的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
FILE *fp=fopen("lena_256x256_yuv420p.yuv","rb+");
FILE *fp1=fopen("output_420_y.y","wb+");
FILE *fp2=fopen("output_420_u.y","wb+");
FILE *fp3=fopen("output_420_v.y","wb+");
unsigned char *pic=(unsigned char *)malloc(256*256*3/2);
fread(pic,1,256*256*3/2,fp);
//Y
fwrite(pic,1,256*256,fp1);
//U
fwrite(pic+256*256,1,256*256/4,fp2);
//V
fwrite(pic+256*256*5/4,1,256*256/4,fp3);
free(pic);
fclose(fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}

首先看一下output_420_y.y文件,文件中存放的Y分量,如下图:

第一行的数据和原始文件lena_256*256_yuv420p.yuv的第一行数据是完全相同的,我们看一看output_420_y.y文件的最后一行是不是0x0000 fff0,如下图所示:

U分量的第一行应该是原始文件0x0001 0000这一行开始的数据,如下图U分量的第一行:


原始文件0x0001 0000这一行的数据:

U分量的最后一行数据应该对应原始文件0x0013ff0地址这一行的数据,源文件这一行的数据如下图:

U分量最后一行的数据如下:

V分量的第一行数据应该是原始数据地址为0x00014000这一行的数据,源文件这一行的数据如下:


V分量的第一行数据如下:

原始文件最后一行的数据应该是V分量的最后一行数据,源文件的最后一行数据如下:

V分量文件的最后一行数据:

YUV原始文件的播放效果:

Y分量文件的播放效果:

U分量文件的播放效果:

V分量文件的播放效果:

要分离YUV444P,YUV422P格式的图像都是类似的方法,如果有兴趣可以去自己去尝试一下。

RGB采样

计算机彩色显示器显示色彩的原理与彩色电视机一样,都是采用R(Red)、G(Green)、B(Blue)相加混色的原理:通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。这种色彩的表示方法称为RGB色彩空间表示(它也是多媒体计算机技术中用得最 多的一种色彩空间表示方法)。根据色度学的介绍,不同波长的单色光会引起不同的彩色感觉,但相同的彩色感觉却可以来源于不同的光谱成分组合。自然界中几乎所有的颜色都能用三种基本彩色混合配出,在彩色电视技术中选择红色、绿色、和蓝色作为三基色。其他的颜色都可以用红色、绿色和蓝色按照不同的比例混合而成。所选取的红色、绿色和蓝色三基色空间。简称为RGB颜色空间。

  • RGB565:每个像素用16位表示,RGB分量分别使用5位、6位、5位
  • RGB555:每个像素用16位表示,RGB分量都使用5位(剩下1位不用)
  • RGB24: 每个像素用24位表示,RGB分量各使用8位
  • RGB32: 每个像素用32位表示,RGB分量各使用8位(剩下8位不用)
  • ARGB32:每个像素用32位表示,RGB分量各使用8位(剩下的8位用于表示Alpha通道值)

下面以一个RGB24的格式文件为例:
RGB24每个分量各占8位也就是每个分量各占一个字节,R占一个字节,G占一个字节,B占一个字节。可以从源文件根据规则知道对于第一行的R分量为E1,E1,E0,E5,E4,E2;G分量为89,88,87,87,8A;B分量为7E,83,75,5C,7C

根据上面的规则用代码分割RGB分量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int main()
{
FILE *fp=fopen("lena_256x256_rgb24.rgb","rb+");
FILE *fp1=fopen("output_r.y","wb+");
FILE *fp2=fopen("output_g.y","wb+");
FILE *fp3=fopen("output_b.y","wb+");
unsigned char *pic=(unsigned char *)malloc(256*256*3);
fread(pic,1,256*256*3,fp);
for(int j=0;j<256*256*3;j=j+3)
{
//R
fwrite(pic+j,1,1,fp1);
//G
fwrite(pic+j+1,1,1,fp2);
//B
fwrite(pic+j+2,1,1,fp3);
}
free(pic);
fclose(fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}

其它的像RGB565,RGB555等格式按照相应的规则分割就是了。


推荐我的微信公众号:爱做饭的老谢


上一篇:运动健身
下一篇:FLV格式解析