pixdesc.c文件中定义的av_pix_fmt_descriptors列表定义了一帧图片在小于等于4个平面上存储方式。
成员nb_components描述每个像素点组成的元素个数。如常见的BRG格式的图片每个像素有B、G、R三种元素组成,YUV格式每个像素由Y、U、V三种元素组成。
成员log2_chroma_w和log2_chroma_h可以根据亮度的宽高来计算色度的宽高。如YUV444,每一个像素点这三个分量都采样,那么色度宽高与亮度的宽高是相同,log2_chroma_w == log2_chroma_h == 0。如下图圈表示像素点上色度采样,叉表示像素点上亮度采样。这样采样的Y有16个数据,UV也分别有16个数据。它们的宽高相同。
YUV422,每一个像素点Y都采样,UV在每一行上都是每两个采样一次,那么色度高与亮度的高是相同,但是色度的宽就比亮度的宽小1倍,所以有log2_chroma_w = 1, log2_chroma_h == 0。这样就可以根据亮度宽luma_w>>1得色度的宽。
YUV420,每一个像素点Y都采样,UV在隔行隔列采样一次,也即每四个点采样一次,那么色度宽高是亮度一半。所以有log2_chroma_w = 1, log2_chroma_h = 1。这样就可以根据亮度宽luma_w>>1得色度的宽,亮度高luma_h>>1得色度的高。
成员comp描述采样数据在内存中的存储方式。
对于采样数据既可以每一种采样数据聚焦放一起也可以选择其它交叉方式排放。comp精确的描述了这种类排布。
comp.plane成员描述元素所处的平面。
comp.depth成员描述元素使用的bit数
comp.step成员描述元素距下一个自己的跨距。step*宽度 就是行宽linesize
comp.offset成员描述元素距行首位置的偏移。在如下2*4(8像素点)图片nv12排布中,Y的plane=0, step=1, offset = 0; U的plane=1, step=2,offset=0; V的plane=1, step=2,offset=1;
log2_chroma_w = 1, log2_chroma_h = 0, nb_components = 3
每二幅图中线内存情况。一幅图像的数据放在一块连续的大内存中。在ffmpeg中常常用data[4]数组指向每个平面的起始位置,用linesize[4],表示每个平面上每一行的宽度。linesize大于等于图像的像素宽度,因为linesize包含内在对齐(没有在图中画出来)。
data[0]=linesize[0]*h,代表data[1] 与data[0] 之前的空间大小是 linesize[0]*h,即0平面的大小。data[1]=linesize[1]*(h>>log2_chroma_h)是平面2的大小。
好,基于上面基础推导av_get_bits_per_pixel和av_get_padded_bits_per_pixel计算原理
由于每个元素的采样率不同,所以像素点所占用的bit数并不等于其组成元素的depth之和。在YUV422中每两个像素共享一对UV。所以需要计算一个平均值。bits_per_pixel = 总bit/总像素
基础知识:2^x * 2^y = 2^(x+y)
x>>y ==> x/(2^y) :数x每向右移动1位,x/2;所以移动y位,所得结果z= x/(2^y)=x*(2^-y)
x<<y ==> x*2^y : 数x每向左移动1位,x*2;所以移动y位,所得结果z= x*2^y
1)av_get_bits_per_pixel计算原理:
设图片分辨率为w*h,每像素有3个元素组成且分布在0,1,2平面上,低采样率l比为log2_chroma_w ,log2_chroma_h(这两个参数与采样率l比是强相关的,前面已给出原因)。
总bit = w*h*depth + (w>>log2_chroma_w * h>>log2_chroma_h)*( chroma1_depth + chroma2_depth)
==>总bit = w*h*depth + [w*(2^-log2_chroma_w) * h*(2^-log2_chroma_h)]*( chroma1_depth + chroma2_depth)
==>总bit = w*h*depth +w* h(2^-(log2_chroma_w+log2_chroma_h)) * ( chroma1_depth + chroma2_depth)
==>(2^(log2_chroma_w+log2_chroma_h)) *总bit = (2^(log2_chroma_w+log2_chroma_h)) *w*h*depth +w* h* ( chroma1_depth + chroma2_depth)
==>(2^(log2_chroma_w+log2_chroma_h)) *总bit = w*h* ((2^(log2_chroma_w+log2_chroma_h)) *depth + chroma1_depth + chroma2_depth)
两边同除w*h
==>(2^(log2_chroma_w+log2_chroma_h)) *总bit /(w*h)=((2^(log2_chroma_w+log2_chroma_h)) *depth + chroma1_depth + chroma2_depth)
==>bits_per_pixel = 总bit /(w*h)=[((2^(log2_chroma_w+log2_chroma_h)) *depth + chroma1_depth + chroma2_depth)]/(2^(log2_chroma_w+log2_chroma_h))
所以每像素的bit数可以由luma的深度depth<<(log2_chroma_w+log2_chroma_h) + luma_U的深度 + luma_V的深度,最后再向右移动log2_chroma_w+log2_chroma_h即可得出。如下源码所示:
int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc)
{
int c, bits = 0;
int log2_pixels = pixdesc->log2_chroma_w + pixdesc->log2_chroma_h;
for (c = 0; c < pixdesc->nb_components; c++) {
int s = c == 1 || c == 2 ? 0 : log2_pixels;
bits += pixdesc->comp[c].depth << s;
}
return bits >> log2_pixels;
}
av_get_padded_bits_per_pixel计算原理
原理同上,它是利用step计算的,step是反映元素在内存上的跨距,跨距包含内存对齐产生的pading空间。
yuv采样参数资料
https://docs.microsoft.com/en-us/previous-versions/aa904813(v=vs.80)?redirectedfrom=MSDN