YUV笔记

YUV笔记

  • 做过视频编解码的对YUV肯定比较熟悉,而YUV有多种采样,如下图,在我们实际开发当中遇到最多的就是YUV420
    在这里插入图片描述

YUV420P

  • yuv420就是每4个y共享一组uv,也就是说每个像素点都有一个y与之对应,每4个像素点共用同一组uv,了解了这个就可以很容易计算出图像的yuv的大小为 size(yuv)=width*height*3/2,就是宽高大小的1.5倍
  • 对图像的处理一般都是以行为单位,对y分量来说,行数等于高度(height),列数等于宽度(不存在内存对齐情况下)
  • 对uv分量来说,行数等于高度的一半,列数等于宽度的一半(这个很好理解吧,由于4个y共享一组uv,因此相当于宽度和高度都减半了)
  • 如果没有对齐的问题,那么存放yuv的大小就是上面的公式了 size(yuv)=width*height*3/2,但我们在开发时有可能遇到实际长度是大于size(yuv)=width*height*3/2这个公式的,为什么会这样呢
  • 其实原因已经说了,内存对齐的问题,先看看下面的分析
  • 假设图像分辨率为width*height=4*4(先不考虑对齐的情况),那么yuv在内存中就是这样存的
连续内存存储:
data[0]: 	yyyy yyyy yyyy yyyy uuuu vvvv

格式化一下:
data[0]:	y y y y
			y y y y
			y y y y
			y y y y
data[1]:	u u
			u u
data[2]:	v v
			v v
  • 此时长度刚好等于size(yuv)=width*height*3/2=24,我们也可以很容易计算出

    • data[1]=data[0]+width*height=data[0]+16,
    • data[2]=data[1]+width/2*height/2=data[1]+width*height/4=data[1]+4
  • 知道首地址和长度其实yuv各个分量已经能分隔开了

  • 然后假设分辨率变为width*height=6*4,并假设内存是以4来对齐的,那么我们看看这次yuv数据在内存中会如何存储

连续内存存储:
data[0]:	yyyyyy00 yyyyyy00 yyyyyy00 yyyyyy00 uuu0 uuu0 vvv0 vvv0

格式化一下:
data[0]:	y y y y y y 0 0
   			y y y y y y 0 0
   			y y y y y y 0 0
   			y y y y y y 0 0
data[1]:	u u u 0
   			u u u 0
data[2]:	v v v 0
   			v v v 0

剔除对齐产生的多余空间后:
yyyyyy yyyyyy yyyyyy yyyyyy uuu uuu vvv vvv
  • 我们看到后面会多出一些0(不一定是0,反正就是多出了一些字节,这些字节存是什么我们其实并不关心;这里为了方便说明,用0来表示),这些0是为了对齐而增加的,多了这些0虽然对cpu处理来说有性能的提升(可以减少数据读取的次数),但真实数据是没有这些0的,我们如果不管三七二十一,直接根据上面的公式去计算分离各分量数据,那么就会发生错误,从而产生花屏
  • 于是就需要有一个变量来表示每行的行宽,这个变量在ffmpeg中就叫linesize
  • 我们知道ffmpeg中对这帧数据的描述除了data外,还有linesize,这个data比较好理解,他是一个指针数组,data[0]存放的就是y分量数据的首地址,data[1]存放的就是u分量数据的首地址,data[2]存放的就是v分量数据的首地址
  • 而linesize也是一个数组,linesize[0]就表示y分量每一行的长度,在我们的例子中就是y分量有4行(跟宽度相等),每行的长度为linesize[0];u分量有2行(是宽度的一半),每行的长度为linesize[1];v分量有2行(是宽度的一半),每行的长度为linesize[2];在yuv420中linesize[1]和linesize[2]是相等的
  • 到这里也可以看出,在yuv420中,u与v的计算结果是一致的,因此在实际当中只要计算u的相关数值后v与u一致即可
  • 从上图我们可以知道linesize[0]=8,linesize[1]=linesize[2]=4,有了这个linesize,我们就可以计算出任意一行的首地址,比如y分量第三行的首地址为(data[0]+linesize[0]*2),u分量第二行首地址为(data[1]+linesize[1]*1),知道首地址后就可以根据宽度获得对应的数据,从而把后面多余的0剔除,最后得到有效的数据
  • 最后总结一下,在yuv420p中,假如图像分辨率为w*h,那么y分量有h行linesize[0]列,u和v分量一样,都是h/2行linesize[1]列,其中linesize[0]大于等于w,linesize[1]大于等于w/2
  • 了解这些东西对于了解ffmpeg的相关api设计和参数有很大帮助作用
  • 看到这里如果你也在使用ffmpeg,那么也可以看看这篇文章:FFmpeg简单分析系列----内存对齐简要说明_huweijian5的专栏-CSDN博客

参考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章