欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深入理解YUV数据格式

最编程 2024-08-15 15:35:41
...

音视频解码之YUV视频格式

前言: 由于工作的需要接触到了音视频方面的知识,在这里就行一些知识的
整理,以免后面忘记.后面我也会写一些工作中遇到的问题整理,以及在音视
频这方面的进阶,期待自己的成长.
我在音视频开发的过程中,最早接触到的就是camera了,上一篇也有讲到camera的预览拍照以及camera的相关类的介绍,在这一篇中,来总结下视频格式方面的知识.

1.YUV的介绍

YUV其实就是一种颜色的编码方式,Y表示亮度,U(Cb)V(Cr)表示色度.当
我们只显示Y数据时,那么图像信息就会显示是灰色,彩色电视采用YUV就
是为了解决黑白电视的兼容.

YUV包含YUV_444,YUV_422,YUV_420,其实这些格式只是对采样率的不同还有YUV数据存储方式的不同来分类的:

YUV 4:4:4采样,每一个Y对应一组UV分量。
YUV 4:2:2采样,每两个Y共用一组UV分量。
YUV 4:2:0采样,每四个Y共用一组UV分量。

下面分别介绍下常见的YUV的存储方式:

1.0 YUVY 格式(YUV 4:2:2)
Y0 Cb0 Y1 Cr0 Y2 Cb1 Y3 Cr1 
Y4 Cb2 Y5 Cr2 Y6 Cb3 Y7 Cr3 
YUYV为YUV422采样的存储格式中的一种,相邻的两个Y共用其相邻的两
个Cb、Cr,分析,对于像素点Y0、Y1 而言,其Cb、Cr的值均为 Cb0、Cr0,其他的像素点的
YUV取值依次类推。

2.0 UYVY 格式 (属于YUV422)
Cb0 Y0 Cr0 Y1 Cb1 Y2 Cr1 Y3
Cb2 Y4 Cr2 Y5 Cb3 Y6 Cr3 Y7
这种方式与1.0类似,只是排列方式不同而已
3.YUV422P(属于YUV422)
Y0  Y1  Y2  Y3
Y4  Y5  Y6  Y7
Cb0 Cb1
Cb2 Cb3
Cr0 Cr1
Cr2 Cr3
YUV422P也属于YUV422的一种,它是一种Plane模式,即打包模式,并不是将YUV数据交错存储,
而是先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,如上所示。
其每一个像素点的YUV值提取方法也是遵循YUV422格式
的最基本提取方法,即两个Y共用一个UV。比如,
对于像素点Y0、Y1 而言,其Cb、Cr的值均为 Cb0、Cr0。

4.0YV12,YU12格式(属于YUV420)
Y0  Y1  Y2  Y3
Y4  Y5  Y6  Y7
Cb0 Cb1
Cr0 Cr1
YU12和YV12属于YUV420格 式,也是一种Plane模式,将Y、U、V分量分别打包,依次存储。其每一
个像素点的YUV数据提取遵循YUV420格式的提取方式,即4个Y分量共用一
组UV。注意,上图中,Y0、Y1、Y4、Y5共用Cr0、Cb0,其他
依次类推。
5.0NV21,NV12格式(属于YUV420)
Y0  Y1  Y2  Y3
Y4  Y5  Y6  Y7
Cb0 Cr0 Cb1 Cr1
V12和NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个
Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方
式与上一种类似,即Y0、Y1、Y4、Y5共用Cr0、Cb0
总结:
I420: YYYYYYYY UU VV    =>YUV420P
YV12: YYYYYYYY VV UU    =>YUV420P
NV12: YYYYYYYY UVUV     =>YUV420SP
NV21: YYYYYYYY VUVU     =>YUV420SP

2.0 YUV_420888格式介绍

Android PAI 对 YUV420_888的介绍 ,大致意思如下:
它是YCbCr的泛化格式,能够表示任何4:2:0的平面和半平面格式,每个分量用8 bits 表示。带有这种格式的图像使用3个独立的Buffer表示,每一个Buffer表示一个颜色平面(Plane),除了Buffer外,它还提供rowStride、pixelStride来描述对应的Plane。
使用Image的getPlanes()获取plane数组:
Image.Plane[] planes = image.getPlanes();
它保证planes[0] 总是Y ,planes[1] 总是U(Cb),
planes[2]总是V(Cr)。并保证Y-Plane永远不会和U/V交叉
(yPlane.getPixelStride()总是返回)。U/V-Plane总是有相同
的rowStride和 pixelStride()(即有:uPlane.getRowStride()
== vPlane.getRowStride() 和 uPlane.getPixelStride() == vPlane.getPixelStride();)。
以分辨率1280*720为例,获取相关信息如下:
 Image image = reader.acquireNextImage();
            if (image == null) {
                return;
            }
            Image.Plane[] planes = image.getPlanes();
            if (!isFrist) {
                isFrist = true;
                for (int i = 0; i < planes.length; i++) {
                    int rowStride = planes[i].getRowStride();
                    int pixelStride = planes[i].getPixelStride();
                    int remaining = planes[i].getBuffer().remaining();
                    int width = image.getWidth();
                    int height = image.getHeight();
                    Log.i(TAG, "pixelStride  " + pixelStride);
                    Log.i(TAG, "rowStride   " + rowStride);
                    Log.i(TAG, "buffersize   " + remaining);
                    Log.i(TAG, "width  " + width);
                    Log.i(TAG, "height  " + height);
                    Log.i(TAG, "Finished reading data from plane  " + i);
                }
            }
pixelStride  1
rowStride   1280
buffersize   921600
width  1280
height  720
Finished reading data from plane  0
pixelStride  2
rowStride   1280
buffersize   460799
width  1280
height  720
Finished reading data from plane  1
pixelStride  2
rowStride   1280
buffersize   460799
width  1280
height  720
Finished reading data from plane  2
  1. plane[0] 是Y数据,从rowStride是1280和 pixelStride是1,可知每行1280个像素且Y数据之间无间隔,从buffer size / rowStride = 720 Y数据有720行。 plane[1] 是U数据,rowStride 是1280, rowStride是2 ,说明每行1280个像素中每两个连续的U之间隔了一个像素,buffer中索引为: 0 , 2 , 4, 6, 8 … 是U数据,即步长为2。 每行实际的U数据只占1/2 ,buffer size / rowStride = 360 只有360行,说明纵向采样也是1/2 ,但buffer size 是 plane[0]的 1/2而不是1/4, 连续的U之间到底存储了什么数据,才使得buffer size 变为plane[0]的1/2了? 同plane[1]。
  2. 其中当pixelStride等于1的时候说明planes[1]是连续的U数据 planes[2]是连续的V数据, 当pixelStride等于2的时候说明planes[1]是非连续的U数据而是UVUV排列 planes[2]是非连续的V数据而是VUVU,不难看出当pixelStride=1时 planes[0]+planes[1]+planes[2]为I420格式 planes[0]+planes[2]+planes[1]位YV12格式, 其中当pixelStride=2的时候,planes[0]+planes[1]为NV12格式数据 planes[0]+planes[2]为NV21数据

参考文章

www.cnblogs.com/azraelly/ar… www.cnblogs.com/renhui/p/84…