音视频系列9:BGRYUV420和YUV422编码格式

Posted IE06

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了音视频系列9:BGRYUV420和YUV422编码格式相关的知识,希望对你有一定的参考价值。

视频流转码的时候遇到了点麻烦,下面分析一下。

1 BGR vs YUV

BGR格式的shape为(width, height, 3),最后的3按照blue、green、red排列。
YUV格式中的Y、UV分别代表Luma、Chroma。UV分别描述色彩和饱和度。
YUV的好处是,将亮度与颜色分离,即使丢弃UV,仍然能够正常显示黑白图片。
下面是一个例子:
在这里插入图片描述

2. 各种YUV编码方式

YUV码流的存储格式有2个关键点:
1)Y与UV的采样,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0。
YUV 4:4:4采样,每一个Y对应一组UV分量。YUV 4:2:2采样,每两个Y共用一组UV分量。 YUV 4:2:0采样,每四个Y共用一组UV分量。
2)Y与UV的编排。有两大类:planar和packed。
对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。
这里先介绍两个项目中用到的:

2.1 I420

亮度(行×列) + U(行×列/4) + V(行×列/4)
在这里插入图片描述

2.2 nv12

NV12属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00。python版本的代码如下:

# I420转为nv12
img_nv12 = list(img_I420[:w,:]) # Y
for wi in range(w//4):
    d = []
    for hi in range(h//2):
        d.append(img_I420[w+wi,hi])
        d.append(img_I420[w//4*5+wi,hi])   
    img_nv12.append(np.array(d))
    d = []
    for hi in range(h//2):
        d.append(img_I420[w+wi,h//2+hi])
        d.append(img_I420[w//4*5+wi,h//2+hi])    
    img_nv12.append(np.array(d))
img_nv12 = np.array(img_nv12)
io.imshow(img_nv12)

在这里插入图片描述
C++版本代码如下:

void swapYUV_I420toNV12(unsigned char* i420bytes, unsigned char* nv12bytes, int width, int height)
{
    int nLenY = width * height;
    int nLenU = nLenY / 4;

    memcpy(nv12bytes, i420bytes, width * height);

    for (int i = 0; i < nLenU; i++)
    {
        nv12bytes[nLenY + 2 * i] = i420bytes[nLenY + i];                    // U
        nv12bytes[nLenY + 2 * i + 1] = i420bytes[nLenY + nLenU + i];        // V
    }
}

我们可以尝试恢复成BGR格式看一下:
在这里插入图片描述
和原图一模一样

以上是关于音视频系列9:BGRYUV420和YUV422编码格式的主要内容,如果未能解决你的问题,请参考以下文章

图解YUV444、YUV422、YUV420

详解 YUV 格式(I420/YUV420/NV12/NV12/YUV422)

Qt音视频开发28-ffmpeg解码本地摄像头(yuv422转yuv420)

详解YUV系列----YUV420

几种常见的YUV格式--yuv422:yuv420

Web mp4 视频的像素格式是啥?