文章目录
YUV
Y: 表示明亮度(Luminance或Luma)
U和V: 色度(Chrominance或者Chroma), 作用是描述影像色彩及饱和度,用于指定像素的颜色。
YUV格式有两个大类:
planar格式:先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
packed格式:每个像素点的YUV是连续交叉存储的。
常见的YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、YUV420等。
YUV 采样
主流的采样方式有三种:
4:4:4 表示完全取样,每一个Y对应一组UV分量。
4:2:2 表示2:1的水平取样,垂直完全采样,每两个Y共用一组UV分量。
4:2:0 表示2:1的水平取样,垂直2:1采样,每四个Y共用一组UV分量。
4:1:1 表示4:1的水平取样,垂直完全采样(不常见)。
YUV 4:4:4
完全取样,每个像素都有独立的Y/U/V值
为了方便对比,我们挑画面下方横条渐变色块6x5个像素放大40倍,看像素的YUV值(其它采样也取相同位置)。
从如下图所示,可以看出相邻的像素点的Y/U/V值不相等也可以看出每个像素都有独立的U/V值
YUV 4:2:2
每两个Y共用一对U/V值
422采样,水平方向每两个像素共用一对U/V值,下如图绿色框(U channel)和蓝色框(V channel)标记的一个框在内存中只有一个值。
YUV 4:2:0
每四个Y共用一对U/V值
420采样,因为是相邻的4个像素共用一对U/V,所以会出现如下图所示,每四个相邻的像素就出现4个相同的UV值。
planar format
Packed(or Interleaved)
将YUV三个分量的素数值放在同一个阵列中,存储为单个阵列宏像素
将每个像素点的Y/U/V连续交叉存储
UYVY格式 (属于YUV422)
U0Y0V0Y1 U2Y2V2Y3 U4Y4V4Y5 U6Y6V6Y7 …
UYVY格式也是YUV422采样的存储格式中的一种,只不过与YUYV不同的是UV的排列顺序不一样而已,还原其每个像素点的YUV值的方法与上面一样。
YUYV格式 (属于YUV422)
Y0U0Y1V0 Y2U2Y3V2 Y4U4Y5V4 Y6U6Y7V6 …
YUYV为YUV422采样的存储格式中的一种,相邻的两个Y共用其相邻的两个Cb、Cr,分析,对于像素点Y’00、Y’01 而言,其Cb、Cr的值均为 Cb00、Cr00,其他的像素点的YUV取值依次类推。
Planar
每个分量存储为单独的数组,最终图像是三个单独平面的整合
以I420为例Y/U/V排列如下:
width:图像分辨率宽
height:图像分辨率高
n = width * height
m = width * height/4
Y0Y1Y2Y3Y4Y5…Yn U0U1U2U3…Um V0V1V2V3…Vm
YUV422P(属于YUV422)
YUV422P 也属于YUV422的一种,它是一种Plane模式,即平面模式,并不是将YUV数据交错存储,而是先存放所有的Y分量,然后存储所有的U(Cb)分量, 最后存储所有的V(Cr)分量,如上图所示。其每一个像素点的YUV值提取方法也是遵循YUV422格式的最基本提取方法,即两个Y共用一个UV。比如, 对于像素点Y’00、Y’01 而言,其Cb、Cr的值均为 Cb00、Cr00。
YV12,YU12格式(属于YUV420)
YU12和YV12属于YUV420格 式,也是一种Plane模式,将Y、U、V分量分别打包,依次存储。其每一个像素点的YUV数据提取遵循YUV420格式的提取方式,即4个Y分量共用一 组UV。注意,上图中,Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00,其他依次类推。
Semi-Planar
介于Pakced和Planar之间,即Y分量为一个阵列,UV交叉存储
NV12
width: 图像分辨率的宽
height: 分辨率高
n = width * height
m = width * height / 4
Y0Y1Y2Y3Y4Y5…Yn U0V0U1V1U2V2U3V3…UmVm
NV12、NV21(属于YUV420)
NV12和NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00
:::info
Note:
格式的名称以“ p”结尾的一般都是planar格式,如在ffmpeg 中的yuvj420p格式
格式的名称以“ sp”结尾的一般都是semi-planar格式, 如
:::
格式转换
YUYV转I420(YUV420P)
void YUYVConvertI420(int width,int hight,char *pYUYV,char *pI420)
{
char *u = pI420+hight*width;
char *v = u+hight*width/4;
int i=0,j=0;
for (i = 0; i <hight/2;i++) {
char *src_l1=(pYUYV+width*2*2*i);
char *src_l2=(src_l1+width*2);
char *y_l1=pI420+width*2*i;
char *y_l2=y_l1+width;
for(j=0;j<width/2;j++)
{
*y_l1++=src_l1[0];
*u++=src_l1[1];
*y_l1++=src_l1[2];
*v++=src_l1[3];
*y_l2++=src_l2[0];
*y_l2++=src_l2[2];
src_l1+=4;
src_l2+=4;
}
}
}
I420转NV12
void I420ConvertNV12(unsigned char* pI420, unsigned char* pNV12, int width, int height)
{
int i, j;
int y_size = width * height;
unsigned char* y = pI420;
unsigned char* u = pI420 + y_size;
unsigned char* v = pI420 + y_size * 5 / 4;
unsigned char* y_tmp = pNV12;
unsigned char* uv_tmp = pNV12 + y_size;
// y
memcpy(y_tmp, y, y_size);
// u
for (j = 0, i = 0; j < y_size/2; j+=2, i++)
{
// 此处可以调整UV位置,根据需要调整为NV12或NV21
uv_tmp[j] = u[i];
uv_tmp[j+1] = v[i];
// 下面是转NV21的
// uv_tmp[j] = v[i];
// uv_tmp[j+1] = u[i];
}
}
NV21转NV12
void NV21ConvertNV12(int width,int height,char *pNV21,char *pNV12)
{
memcpy(pNV12, pNV21, width*height);//y分量
int i;
for(i=0; i<width*height/2; i++){
memcpy(pNV12+width*height+i+1, pNV21+width*height+i, 1);//u分量
memcpy(pNV12+width*height+i, pNV21+width*height+i+1, 1);//v分量
}
}
关系图
如下图,树的第四层只是列举部分并非全部,理论上树的第4层可以通过YUV的排列、位深、色彩范围(full range和limited range)等自由组合出来非常多的格式。
计算
由于YUV格式是未经压缩并且只存储了Y/U/V三个通道的数据,播放或编码必须要知道分辨率和YUV具体的格式(如nv12/i420/yuvj420ple), 因此在YUV文件命名时建议名字包含YUV格式名称和分辨率信息。
YUV计算文件大小
已知YUV采样率、分辨率、和帧数
文件大小=宽 * 高 * 采样率 * 向上取整(位深/8) * 帧数
file size(byte) = width * height * rate * Ceil(bitdepth/8) * frames
以最常用的nv12/i420等8bit位深的420为例
文件大小 = 宽 * 高 * 1.5 * 帧数
SYUV计算帧数
YUV帧数的计算和文件大小的计算类似
要求已知文件大小、采样率、分辨率
YUV帧数=文件大小/(宽 * 高 * 采样率 * 向上取整(位深/8))
YUV frames = file size(byte) / (width * height * rate * Ceil(bitdepth/8))
sample map
sample | rate |
---|---|
4:4:4 | 3 |
4:2:2 | 2 |
4:2:0 | 1.5 |
4:1:1 | 1.5 |
大小端序(字节序)
当位深超过8bit时存在大小端模式的情况
big-edian(大端序): 低地址存放高位
little-endian(小端序): 低地址存放低位
格式名称以le为小端序,格式名称以be为小端序
相同名称只是后缀不一样的两种格式YUV排列是完全一样的, 如,yuv420p10le与yuv420p10b
一些常用格式
YUV格式关系
YUV格式名称比较多在不同的地方不同的名称有可能代表的是同一种格式,如在ffmpeg中的yuyv422与gstreamer 中的yuy2,以及其它不它的格式名称YUY2/YUYV/YUNV, 都是代表同一种YUV格式
ffmpeg pix_fmt | gstreamer format | Duplicate formats | number of components | Bits per pixel | remark |
---|---|---|---|---|---|
yuvj420p | i420 | IYUV/YU12 | 3 | 12 | full range |
yuv420p | - | 3 | 12 | limited range , 排列方式与yuvj420p完全一致,只是像素颜色范围是[16,235], 16表示黑色,235表示白色; UV范围[16,240] | |
nv12 | nv12 | 3 | 12 | - | |
nv21 | nv21 | 3 | 12 | - | |
yuyv422 | yuy2 | YUY2/YUYV/YUNV | 3 | 16 | YUYV 4:2:2 |
uyvy422 | uyvy | UYVY/IUYV/HDYC/ UYNV/Y422 | 3 | 16 | UYVY 4:2:2 |
yuv420p10le | i420-10le | 3 | 15 | 10 bit yuv | |
p010le | p010-10le | 3 | 15 | 10 bit yuv | |
yv12 | - | 3 | 12 | YV12 (3-planar) ——These formats are identical to YU12 except that the U and V plane order is reversed. |
常见YUV格式存储排列方式
Define:
s = width * height
n = width * height / 4
m = width * height / 2
:::info
-
I420/IYUV/YU12: yuv420 planar 的一种, 排列方式: y1y2y3…ysu1u2u3…unv1v2v3…vn
-
nv12: 8bit YUV420 Semi-Planar的一种格式, 排列方式: y1y2y3…ysu1v1u2v2u3v3…unvn
-
nv21: 8bit YUV420 Semi-Planar的一种格式, 排列方式: y1y2y3…ysv1u1v2u2…vnun
-
i420-10le: 10bit YUV420 Planar的一种格式, 排列方式与i420一样, 只是每个值都用10bit低字节序来存储
-
p010-10le: 10bit YUV420 Semi-Planar的一种格式, 排列方式与nv12一样, 只是每个值都用高10bit低字节序来存储
-
YUY2/YUYV/YUNV: 8bit YUV 4:2:2格式, 排列方式: y1u1y2v1 y3u2y4v2 y5u3y6v3…yn-1umynvm
-
UYVY/IUYV/HDYC/UYNV/Y422: 8bit YUV 4:2:2格式, 排列方式: u1y1v1Y2 u2y3v2y4 u3y5v3y6…umyn-1vmyn
-
yv12: YUV420 Planar的一种,UV的顺序与i420相反, 排列方式: y1y2y3y…ynv1v2v3…vnu1u2u3…un
-
YUV422P/I422: y1y2y3…ysu1u2u3…umv1v2v3…vm
-
nv16: yuv422 Semi-Planar的一种: y1y2y3…ys u1v1u2v2u3v3…umvm
-
nv61: 与nv16类似,只是u/v的位置互换(V前U后)
-
yv16: yuv422 Planar的一种: y1y2y3…ysu1u2u3…umv1v2v3…vm
-
yuvj444p: Planar的一种: y1y2y3y…ys u1u2u3…us v1v2v3…vs
:::
其它4:1:1采样的格式一般不太常见
:::info -
Y41P: 是一种4:1:1packed格式,其中U和V每四个像素水平采样一次。每个宏像素在三个字节中包含8个像素,并具有以下字节布局:U0 Y0 V0 Y1 U4 Y2 V4 Y3 Y4 Y5 Y6 Y7
-
Y41T与Y41P相同,除了每个Y样本的最低有效位指定色度键(0 =透明,1 =不透明)。
-
AI44是一种已标准化的YUV格式,每个样本8位。每个样本在4个最高有效位(MSB)中包含一个索引,在4个最低有效位(LSB)中包含一个alpha值。索引引用YUV调色板条目的数组,必须在该格式的媒体类型中定义。此格式主要用于子图片图像。
:::