FOURCC是4字节代码,是一个codec中对压缩格式、颜色、像素格式等的标识。按一个字节8bit,FOURCC通常占4字节32bit。
FOURCC is short for “four character code” - an identifier for a video codec, compression format, color or pixel format used in media files.
A character in this context is a 1 byte/8 bit value, thus a FOURCC always takes up exatly 32 bits/4 bytes in a file.
Another way to write FOURCC is 4CC (4 as in “four” character code).
libva中有一个VA_FOURCC的宏定义:
#define VA_FOURCC(ch0, ch1, ch2, ch3) \((unsigned long)(unsigned char) (ch0) | ((unsigned long)(unsigned char) (ch1) << 8) | \((unsigned long)(unsigned char) (ch2) << 16) | ((unsigned long)(unsigned char) (ch3) << 24 ))
然后virglrenderer中在判断format时就使用到该VA_FOURCC宏:可以看出FOURCC是一个32bit(4字节)的变量,其中存储的时NV12这样的ASCII字符,所以FOURCC中的四个字符必须是ASCII字符表内所包含的字符。
static enum pipe_format pipe_format_from_va_fourcc(unsigned format)
{switch(format) {case VA_FOURCC('N','V','1','2'):return PIPE_FORMAT_NV12;case VA_FOURCC('P','0','1','0'):return PIPE_FORMAT_P010;case VA_FOURCC('P','0','1','6'):return PIPE_FORMAT_P016;case VA_FOURCC('I','4','2','0'):return PIPE_FORMAT_IYUV;case VA_FOURCC('Y','V','1','2'):return PIPE_FORMAT_YV12;case VA_FOURCC('Y','U','Y','V'):case VA_FOURCC('Y','U','Y','2'):return PIPE_FORMAT_YUYV;case VA_FOURCC('U','Y','V','Y'):return PIPE_FORMAT_UYVY;case VA_FOURCC('B','G','R','A'):return PIPE_FORMAT_B8G8R8A8_UNORM;case VA_FOURCC('R','G','B','A'):return PIPE_FORMAT_R8G8B8A8_UNORM;case VA_FOURCC('B','G','R','X'):return PIPE_FORMAT_B8G8R8X8_UNORM;case VA_FOURCC('R','G','B','X'):return PIPE_FORMAT_R8G8B8X8_UNORM;default:return PIPE_FORMAT_NONE;}
}
YUV pixel formats
YUV pixel formats有两种方式,packed formats 和 planer formats。
-
Packed formats:Y, U(Cb), V(Cr) 三个采样值是打包在一个macropixels,存放在一个数组内。
-
Planer formats:Y,U,V分别存放在三个数组内,最终的image是该三个planes的fusing(定影熔合)而成。
Packed YUV Formats
FOURCC,16进制 | bits/pixel | ||
---|---|---|---|
UYVY | 0x59565955 | 16 | YUV 4:2:2 (Y sample at every pixel, U and V sampled at every second pixel horizontally on each line). A macropixel contains 2 pixels in 1 u_int32 |
YUV2 | 0x32595559 | 16 | YUV 4:2:2 as for UYVY but with different component ordering within the u_int32 macropixel |
YVYU | 0x55595659 | 16 | YUV 4:2:2 as for UYVY but with different component ordering within the u_int32 macropixel |
Y42T | 0x54323459 | 16 | Format as for UYVY but the lsb of each Y component is used to signal pixel transparency |
YUVP | 0x50565559 | 24? | YCbCr 4:2:2 extended precision 10-bits per component in Y0U0Y1V0 order. Registered by Rich Ehlers of Evans & Sutherland |
V0,Y3,U0的理解:
In the diagrams below, the numerical suffix attached to each Y, U or V sample indicates the sampling position across the image line, so, for example, V0 indicates the leftmost V sample and Yn indicates the Y sample at the (n+1)th pixel from the left.
U0表示最左边的U采样,Un表示从U0的像素位置起(包含)数第(n+1)个像素pixel中的U采样。
UYVY
UYVY可能是最流行的4:2:2格式的一种了,通常是MPEG codecs第二个常用格式(第一个常用格式是YV12)。
Y422和UYNV通常也是指UYVY格式。16bits/pixel。
Horizontal | Vertical | |
---|---|---|
Y Sample Period | 1 | 1 |
V Sample Period | 2 | 1 |
U Sample Period | 2 | 1 |
这个地方的扫描间隔和排列到底该如何理解?我的理解是
UYUV的每个像素是16bits,一个macropixels包含2个pixels是32bits。
Y的水平采样是每个pixel中都一个,V的水平采样是每2个pixel中才有一个,U的水平采样也是每2个pixel中有一个;
Y的垂直采样是每个pixel中有一个,V的垂直采样是每个pixel中有一个,U的垂直采样也是每个pixel中有一个。
所以其采样排列应该是如下:我这每行就写4个pixel就换行作示意理解用,实际采样时应该每行有weight个像素
U0, Y0, V0, Y1
U2, Y2, V2, Y3
U4, Y4, V4, Y5
U6, Y6, V6, Y7
...
...
与UYVV等同性质的formats有: IUYV HDYC UYNV Y422
UYVY的子类formats有: YUY2 YVYU Y42T
YUY2
YUY2是4:2:2的一种格式,其与UYVY很类似,只在macropixels中的构成有所不同。
Horizontal | Vertical | |
---|---|---|
Y Sample Period | 1 | 1 |
V Sample Period | 2 | 1 |
U Sample Period | 2 | 1 |
按照我上面对UYVY的分析理解,也可以画一个YUY2的排列:
Y0, U0, Y1, V0
Y2, U2, Y3, V2
Y4, U4, Y5, V4
Y6, U6, Y7, V6
...
...
与YUY2同样的formats有:YUYV,YUNV
YUY2的子类formats有:YUVP
YVYU
YVYU其实和YUY2很类似,不同之处也是在于macropixels中的排列不同。
Horizontal | Vertical | |
---|---|---|
Y Sample Period | 1 | 1 |
V Sample Period | 2 | 1 |
U Sample Period | 2 | 1 |
我还是按照自己的理解来写一遍排列:
Y0, V0, Y1, U0
Y2, V2, Y3, U2
Y4, V4, Y5, U5
Y6, V6, Y7, U6
...
...
Y42T
This format is identical to UYVY except for the fact that the least significant bit of each Y component forms a chromakey channel. If this bit is set, the YUV image pixel is displayed, if cleared, the pixel is transparent (and the underlying graphics pixel is shown).
YUVP
This is another format similar to YUY2 and it’s aliases. The difference here is that each Y, U and V samples is 10 bits rather than 8. I am still waiting to hear how the samples are packed - is a macropixel just 5 bytes long with all the samples packed together or is there more to it than this?
Planer YUV Formats
Planer formats:Y,U,V分别存放在三个数组内,最终的image是该三个planes的fusing(定影熔合)而成。
FOURCC,16进制 | bits/pixel | ||
---|---|---|---|
NV12 | 0x3231564E | 12 | 8-bit Y plane followed by an interleaved U/V plane with 2x2 subsampling |
NV21 | 0x3132564E | 12 | As NV12 with U and V reversed in the interleaved plane |
YV12 | 0x32315659 | 12 | 8 bit Y plane followed by 8 bit 2x2 subsampled V and U planes |
I420
Horizontal | Vertical | |
---|---|---|
Y Sample Period | 1 | 1 |
V Sample Period | 2 | 2 |
U Sample Period | 2 | 2 |
I420格式特征如下:
-
Y luma plane排在前面,然后是U chroma plane,最后是V chroma plane
-
Y在水平和垂直放行都是每个pixel都采样一次,U和V在水平方向和垂直方向都是每2个pixel中才出现一次,也就是2x2的pixels中,U和V各采样一次,这样算下来2x2的pixels中,Y采样4次,U和V个采样一次
-
所以2x2的pixels中,总bits数=4 x 8 + 8 + 8 = 48bits,一共是2x2=4个pixels,所以每个pixels的bits平均就是12bits
YV12
YV12和I420极其类似,YV12这里的YV指的是plane的顺序,Y plane在前,接着V plane,最后U plane,12指的12bits/pixel。
Horizontal | Vertical | |
---|---|---|
Y Sample Period | 1 | 1 |
V Sample Period | 2 | 2 |
U Sample Period | 2 | 2 |
所以,按照这个间隔我们来画一个采样排列:
相当于每2x2 pixels中采样了4个Y分量,1个V分量和1个U分量,然后Y luma plane是一个plane,V chroma plane是一个plane, U chroma plane也是一个plane。
把上面这3个plane示意图在内存字节序中的排序顺一下就是:
NV12
NV12也和I420相似,不同的是Y plane在前,然后是U/V交叉的plane。
NV12中chroma plane也是水平和垂直方向都每2个pixel采样,所以2x2个pixel中有4个Y,各一个U和V,其也是12bits/pixel。
Horizontal | Vertical | |
---|---|---|
Y Sample Period | 1 | 1 |
V Sample Period | 2 | 2 |
U Sample Period | 2 | 2 |
还是按照我的理解根据这个间隔来画个采样排列:
把Y plane和 U/V plane在内存中的分布就是:
NV21
NV21和NV12其实一样,不同之处在于U和V的顺序,NV21中先是V再是U。
排列汇总如下:
libva中FOURCC和YUV
FOURCC | Pixel format | value | YUV | bit-depth | bpp |
---|---|---|---|---|---|
VA_FOURCC_NV12 | planer(2 plane) | 0x3231564E | 4:2:0 | 8-bit | 12bpp |
VA_FOURCC_NV21 | planer(2 plane) | 0x3132564E | 4:2:0 | 8-bit | 12bpp |
VA_FOURCC_RGBA | packed | 0x41424752 | 8-bit | 32bpp | |
VA_FOURCC_UYVY | packed | 0x59565955 | 4:2:2 | 8-bit | 16bpp |
VA_FOURCC_YUY2 | packed | 0x32595559 | 4:2:2 | 8-bit | 16bpp |
VA_FOURCC_YV12 | planer(3 plane) | 0x32315659 | 4:2:0 | 8-bit | 12bpp |
VA_FOURCC_I420 | planer(3 plane) | 0x30323449 | 4:2:0 | 8-bit | 12bpp |
VA_FOURCC_444P | planer(3 plane) | 0x50343434 | 4:4:4 | 8-bit | 24bpp |
VA_FOURCC_P010 | planer(2 plane) | 0x30313050 | 4:2:0 | 10-bit | 15bpp |
VA_FOURCC_P012 | planer(2 plane) | 0x32313050 | 4:2:0 | 12-bit | 18bpp |
VA_FOURCC_P016 | planer(2 plane) | 0x36313050 | 4:2:0 | 16-bit | 24bpp |
这里的value的计算方法是通过VA_FOURCC()宏定义计算出来的,比如NV12的ASCII字符算下来就是0x3231564E。
libva中定义了一些VAConfigAttributeRTFormat值:
Attributre | value | YUV | bit-depth |
---|---|---|---|
VA_RT_FORMAT_YUV420 | 0x00000001 | 4:2:0 | 8-bit |
VA_RT_FORMAT_YUV422 | 0x00000002 | 4:2:2 | 8-bit |
VA_RT_FORMAT_YUV444 | 0x00000004 | 4:4:4 | 8-bit |
VA_RT_FORMAT_YUV411 | 0x00000008 | 4:1:1 | 8-bit |
VA_RT_FORMAT_YUV400 | 0x00000010 | Greyscale | 8-bit |
VA_RT_FORMAT_YUV420_10 | 0x00000100 | 4:2:0 | 10-bit |
VA_RT_FORMAT_YUV422_10 | 0x00000200 | 4:2:2 | 10-bit |
VA_RT_FORMAT_YUV444_10 | 0x00000400 | 4:4:4 | 10-bit |
VA_RT_FORMAT_YUV420_12 | 0x00001000 | 4:2:0 | 12-bit |
VA_RT_FORMAT_YUV422_12 | 0x00002000 | 4:2:2 | 12-bit |
VA_RT_FORMAT_YUV444_12 | 0x00004000 | 4:4:4 | 12-bit |
VA_RT_FORMAT_RGB16 | 0x00010000 | Packed RGB | 16bpp |
VA_RT_FORMAT_RGB32 | 0x00020000 | Packed RGB | 32bpp |
VA_RT_FORMAT_RGBP | 0x00100000 | Planer RGB | 8bit per sample |
VA_RT_FORMAT_RGB32_10 | 0x00200000 | Planer RGB | 32bpp |
VA_RT_FORMAT_RGB32_10BPP | 已被VA_RT_FORMAT_RGB32_10代替 | ||
VA_RT_FORMAT_YUV420_10BPP | 已被VA_RT_FORMAT_YUV420_10代替 |
那么VAProfile中hevc的main10这里的10的含义是10bit-depth还是10bpp呢?
根据mesa和libva以及virglrenderer中的代码看,VAProfileHEVCMain10中的10是代表10bit-depth,不过VAProfileHEVCMain10只是一个入口,其下面具体的处理还需要看mesa或virglrenderer各自自己的处理。