RGB

先说RGB,人对红绿蓝三种光敏感,可以通过不同的组合达到不同的颜色。需要保存三个数据才能表示一个颜色。忽略RGBA。

YUV

Y表示明亮度(Luminance或Luma),也就是灰度值,而U和V表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。

内存占比

RGB24一帧的大小size=width×heigth×3 Byte
RGB32一帧的大小size=width×heigth×4 Byte
YUV420一帧的大小size=width×heigth×1.5 Byte

结构分析 来源 详细

黑点表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量

  1. YUV 4:4:4采样,每一个Y对应一组UV分量。
  2. YUV 4:2:2采样,每两个Y共用一组UV分量。
  3. YUV 4:2:0采样,每四个Y共用一组UV分量。
  • YUYV(属yuv422):Y’00、Y’01 而言,其Cb、Cr的值均为 Cb00、Cr00

  • UYVY(属YUV422):同上,只是顺序不同

  • YUV422P(属YUV422):同上上,顺序不同

  • YV12、YU12(属YUV420): Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00。I420的Cr和Cb互换了。

  • NV12、NV21(属YUV420): Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00

    I420: YYYYYYYY UU VV =>YUV420P
    YV12: YYYYYYYY VV UU =>YUV420P
    NV12: YYYYYYYY UVUV =>YUV420SP
    NV21: YYYYYYYY VUVU =>YUV420SP

    存储空间

以720*480图像,yuv420

Y分量: (720×480)个字节

U(Cb)分量:(720×480>>2)个字节

V(Cr)分量:(720×480>>2)个字节

422与420相互转换

422->420:Y不变, 将U和V信号值隔行抽样。420->422:Y不变, 将U和V信号值的每一行分别拷贝一份 。

YUV与RGB相互转换

转跳1

转跳2 英文

FFmpeg中的SwsContext

yuv420p( planar )与yuv420区别

数据在内存中的排布不同:

  • yuv420p: yyyyyyyy uuuu vvvvv

    在AVFrame的data[]中 0表示Y、1表示U、2表示V

    linesize[]中 0表示Y的宽度、1表示U的宽度、2表示V的宽度

  • yuv420: yuv yuv yuv yuv

保存yuv420p

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void saveYUV420p(const AVFrame * pFrame){
int fWidth=pFrame->width;
int fHeight=pFrame->height;
int yBytes=pFrame->linesize[0];
int uBytes=pFrame->linesize[1];
int vBytes=pFrame->linesize[2];

//QFile.write((char *)pFrame->data[0],fWidth*fHeight);
//QFile.write((char *)pFrame->data[1],fWidth/2*fHeight/2);
//QFile.write((char *)pFrame->data[2].fWidth/2*fHeight/2);

for(int i=0;i<fHeight;i++){
QFile.write((char *)pFrame->data[0]+i*yBytes,fWidth);
}
for(int i=0;i<fHeight/2;i++){
QFile.write((char *)pFrame->data[1]+i*uBytes,fWidth/2);
}
for(int i=0;i<fHeight/2;i++){
QFile.write((char *)pFrame->data[2]+i*vBytes,fWidth/2);
}
}