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博客

參考

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