使用OpenGL ES shader做RGBA轉(zhuǎn)YUV(I420)
最近在做android平臺攝像頭采集和視頻渲染,當(dāng)想要把性能做到極致的時候,總避不開使用GPU。
在視頻采集、美顏以及其他前處理之后,需要將數(shù)據(jù)轉(zhuǎn)換成I420格式,方便后續(xù)處理,如果使用CPU去做會導(dǎo)致性能瓶頸。
因?yàn)槲覀冊谇疤幚磉^程都是采用GPU去做,因此這個轉(zhuǎn)換使用GPU去做不僅方便,而且能充分利用GPU的優(yōu)勢。
在編寫OpenGL ES的shader前,先需要確定好fragment shader的輸入和輸出格式。
輸入可以是一個包含RGBA的texture,或者是分別包含Y、U、V的三個texture,也可以使包含Y和UV的兩個texture(UV分別放在texture rgba的r和a中,NV21和NV12都可以用這種方式)。
輸出的texture不僅要包含所有的YUV信息,還要方便我們一次性讀取I420格式數(shù)據(jù)(glReadPixels)。
因此輸出數(shù)據(jù)的YUV緊湊地分布:
????+---------+
????|?????????|
????|??Y??????|
????|?????????|
????|?????????|
????+----+----+
????|?U??|?V??|
????|????|????|
????+----+----+
而對于OpenGL ES來說,目前它輸入只認(rèn)RGBA、lumiance、luminace alpha這幾個格式,輸出大多數(shù)實(shí)現(xiàn)只認(rèn)RGBA格式,因此輸出的數(shù)據(jù)格式雖然是I420格式,但是在存儲時我們?nèi)匀灰凑誖GBA方式去訪問texture數(shù)據(jù)。
對于上述存儲布局,輸出的texture寬度為width/4,高度為height+height/2。這樣一張1280*720的圖,需要申請的紋理大小為:360x1080。
先看看其fragment shader代碼,一眼看去,簡介明了:
//?在x方向上,一個像素的步長(紋理已經(jīng)做過歸一化,這個步長不是像素個數(shù))
"uniform?vec2?xUnit;\n"
//?RGB?to?YUV的顏色轉(zhuǎn)換系數(shù)
+?"uniform?vec4?coeffs;\n"
+?"\n"
+?"void?main()?{\n"
//?雖然alpha通道值總是1,我們可以寫成一個vec4xvec4的矩陣乘法,但是這樣做實(shí)際
//?導(dǎo)致了較低幀率,這里用了vec3xvec3乘法。
//?tc是texture?coordinate,可以理解成輸出紋理坐標(biāo)
+?"??gl_FragColor.r?=?coeffs.a?+?dot(coeffs.rgb,\n"
+?"??????sample(tc?-?1.5?*?xUnit).rgb);\n"
+?"??gl_FragColor.g?=?coeffs.a?+?dot(coeffs.rgb,\n"
+?"??????sample(tc?-?0.5?*?xUnit).rgb);\n"
+?"??gl_FragColor.b?=?coeffs.a?+?dot(coeffs.rgb,\n"
+?"??????sample(tc?+?0.5?*?xUnit).rgb);\n"
+?"??gl_FragColor.a?=?coeffs.a?+?dot(coeffs.rgb,\n"
+?"??????sample(tc?+?1.5?*?xUnit).rgb);\n"
+?"}\n";
假設(shè)輸出圖片是1280x720大小的,那么GPU將并行地執(zhí)行1280x720次main運(yùn)算。
例如輸出紋理坐標(biāo) tc = vec2(x,y) 點(diǎn),該像素點(diǎn)有RGBA四個數(shù)值需要填充,而且都需要填充成Y(或者U、V),那么它需要知道R、G、B、A應(yīng)該取實(shí)際紋理的哪一點(diǎn),對于 Y 直接映射到紋理圖片中,取左右各兩個點(diǎn)即可。Y通道從0,0處繪制,UV按照實(shí)際的位置做左邊轉(zhuǎn)換。
作者:tkorays
來源:http://www.tkorays.com/2019/08/09/Convert-RGBA-to-YUV-by-GLES-Shader/

技術(shù)交流,歡迎加我微信:ezglumes ,拉你入技術(shù)交流群。
推薦閱讀:
音視頻開發(fā)工作經(jīng)驗(yàn)分享 || 視頻版
開通專輯 | 細(xì)數(shù)那些年寫過的技術(shù)文章專輯
NDK 學(xué)習(xí)進(jìn)階免費(fèi)視頻來了
推薦幾個堪稱教科書級別的 Android 音視頻入門項(xiàng)目
覺得不錯,點(diǎn)個在看唄~

