<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用OpenGL ES shader做RGBA轉(zhuǎn)YUV(I420)

          共 1921字,需瀏覽 4分鐘

           ·

          2021-10-24 02:06

          最近在做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)分享 || 視頻版

          OpenGL ES 學(xué)習(xí)資源分享

          開通專輯 | 細(xì)數(shù)那些年寫過的技術(shù)文章專輯

          NDK 學(xué)習(xí)進(jìn)階免費(fèi)視頻來了

          推薦幾個堪稱教科書級別的 Android 音視頻入門項(xiàng)目

          覺得不錯,點(diǎn)個在看唄~


          瀏覽 93
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  内射视频网站免费观看 | 成人国产精品秘 欧美高清 | 久久手机免费视频 | 成人久久大香蕉 | 色秘 乱码一区二区三区唱戏 |