简介
这里真的是浅析,后面在做更新
version | name | date | update commont |
---|---|---|---|
v0.01 | zhangwei | 2018-10-29 | realese |
v0.02 | zhangwei | 2020-08-25 | realese |
这里首先明白两个点
- YUV是对图像采样规则;我们平时看到的YV12,NV21等,是采样后的存储格式
- YUV420P存储为YU12和YV12格式,YU12在Android平台下也叫I420
- YUV420SP存储为NV21或者NV12格式
YUV采样,主要用来描述图像的Y,U,V三个分量,这三个分量的排列常用有三种:YUV4:4:4,YUV4:2:2,YUV4:2:0。
YUV4:4:4采样,每一个Y对应一组UV分量。
YUV4:2:2采样,每两个Y共用一组UV分量。
YUV4:2:0采样,每四个Y共用一组UV分量。
数据格式 | 排列方式 | 图像格式 |
---|---|---|
YU12/I420 | YYYYYYYY UU VV | YUV420P |
YV12 | YYYYYYYY VV UU | YUV420P |
NV12 | YYYYYYYY UVUV | YUV420SP |
NV21 | YYYYYYYY VUVU | YUV420SP |
ffprobe查看视频width!=coded_width
如图,我们可能查看到的数据是这样的,什么原因导致的呢
YUV’420SP数据大小的计算公式是: size = width * heigh * 1.5;
下面内容会做额外补充:
YUV420P数据大小的计算公式是:
size = stride * height
stride = width + padding = width + ALIGN(width /2, 16)
static int ALIGN(int x, int y) {
return (x + y - 1) & ~(y - 1); // y must be a power of 2.
}
** 带入以上公司计算分辨率1280*720,640*480,568*320 的数据大小**
1280*720:
Stride = 1280 + Padiing = 1280 + 640 = 1920
Padiing = ALIGN(1280/2,16) = 640
YUV420P:size =Stride * Height = 1920 * 720 =1382400
YUV420SP:size = width * heigh * 1.5 = 1280 * 720 *1.5 =1382400
640*480:
YUV420P:size =Stride * Height = 960 * 480 = 460800
YUV420SP:size = width * heigh * 1.5 = 640*480*1.5 =460800
568*320:
Stride = 568 + Padiing = 568+ 288 = 856
Padiing = ALIGN(568/2,16) = 288 //这里应该是568/2=284,但是284不能整除16,所以用288进行16位补齐
YUV420P:size =Stride * Height = 856*320 = 273920
YUV420SP:size = width * heigh * 1.5 = 568*320*1.5 =272640
所以coded_width是进行16位补齐后的视频宽度288*2:320=576:320
##什么是16位补齐
简单用文字描述一下:
如果cpu是32位运算,cpu与内存地址交换分别是0-7,8-15,16-23,24-31分配;一个int数据占4bytes,即32bits,如果它的起始地址在0-31中,不包含0和31,那么它只能被cpu一次读取到一半,另外一部分在32-63当中,还需要被二次读取;而如果这个int数据的起始位置是0,就只需要一次就能读取完这个int;显然,前者是占用cpu资源的,内存数据的正确摆放是很重要的;