<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 實現(xiàn)視頻編輯中的轉(zhuǎn)場效果

          共 3899字,需瀏覽 8分鐘

           ·

          2021-10-15 16:31


          轉(zhuǎn)場介紹

          轉(zhuǎn)場效果是什么?

          轉(zhuǎn)場效果,簡單來說就是兩段視頻之間的銜接過渡效果。

          現(xiàn)在拍攝 vlog 的玩家越來越多,要是視頻沒有一兩個炫酷的轉(zhuǎn)場效果,都不好意思拿出來炫酷了。

          那么如何在視頻編輯軟件中實現(xiàn)轉(zhuǎn)場效果呢?

          這里提供使用 OpenGL 實現(xiàn)視頻轉(zhuǎn)場的一個小示例,我們可以通過自定義 GLSL 來實現(xiàn)不同的轉(zhuǎn)場效果。

          以在 Android 平臺上作為演示,但其實不管是 Android 還是 iOS,實現(xiàn)的原理都是一樣的。

          首先要有兩段視頻,視頻 A 和視頻 B,先播放視頻 A 后播放視頻 B,中間有一段過程稱為 C ,C 就是視頻 A、B 做轉(zhuǎn)場動畫的時間段。

          如下所示:

          播放器按照時間順序,從 A -> C -> B 的播放,這樣就有了轉(zhuǎn)場的效果。


          視頻轉(zhuǎn)場,首先就得有視頻,直接從視頻 A、B 中解碼出當前幀并通過 OpenGL 顯示到屏幕上就好了,如果你對這個操作不熟悉的話,可以查看我的公眾號【紙上淺談】歷史文章,都有寫過相關(guān)內(nèi)容。

          這里以圖片來替代視頻 A、B 中解碼出來的幀。

          最終效果如下:

          實現(xiàn)講解

          模擬視頻渲染播放

          模擬 fps 為 30 的視頻,用 RxJava 每間隔 30 ms 就觸發(fā)一次 OpenGL 渲染。

          Observable
          .interval(30, TimeUnit.MILLISECONDS)
          .subscribeOn(AndroidSchedulers.mainThread())
          .subscribe {
          mGLSurfaceView.requestRender()
          }

          另外,如果在視頻 A 播放階段不斷地改變圖片,也就是更新紋理內(nèi)容,就相當于在真實的解碼視頻進行播放了。

          當然這些操作只是為了讓這個小例子更加貼近真正的視頻轉(zhuǎn)場,重要的還是在于如何實現(xiàn)轉(zhuǎn)場的 Shader 效果。

          首先轉(zhuǎn)場的時候要有兩個紋理作為輸入,那么肯定要定義兩個 sampler2D 進行采樣了。

          varying vec2 vTextureCoord;//接收從頂點著色器過來的參數(shù)
          uniform sampler2D sTexture1;
          uniform sampler2D sTexture2;

          其中 sTexture1 對應(yīng)于視頻 A 內(nèi)容,sTexture2 對應(yīng)于視頻 B 內(nèi)容。

          vTextureCoord 對應(yīng)于頂點著色器傳遞過來的紋理坐標,視頻 A 和 視頻 B 都需要用到這個紋理坐標。

          這個時候,只要調(diào)用 texture2D 方法就能得到視頻 A 和 視頻 B 的內(nèi)容了。

          // 得到視頻 A 的內(nèi)容
          texture2D(sTexture1,vTextureCoord)
          // 得到視頻 B 的內(nèi)容
          texture2D(sTexture2,vTextureCoord)

          要注意的是這里說得到視頻 A/B 的內(nèi)容,是得到紋理坐標對應(yīng)的圖像內(nèi)容。也就是說如果紋理坐標是 [0,1] 范圍內(nèi),那么可以得到視頻 A/B 的全部圖像內(nèi)容。如果坐標是 [-0.5,0.5] 那么只能采樣得到一半內(nèi)容了。

          轉(zhuǎn)場效果實現(xiàn)

          混合函數(shù) mix

          由于轉(zhuǎn)場效果是需要視頻 A 和視頻 B 進行疊加混合的,而 GLSL 內(nèi)嵌了 mix 函數(shù)進行調(diào)用。

          對于 GLSL 中有哪些內(nèi)嵌的函數(shù)可以直接調(diào)用的,可以參考寫過的文章記錄:

          OpenGL ES 2.0 著色器語言 GLSL 學習https://glumes.com/post/opengl/opengl-glsl-2-mark

          mix 函數(shù)的聲明如下:

          genType mix(genType x,genType y,float a) // 其中 genType 泛指 GLSL 中的類型定義

          它的主要功能是使用因子 a 對 x 與 y 執(zhí)行線性混合,既返回 x * (1-a) + y * a

          現(xiàn)在,通過 texture2D 能得到視頻幀內(nèi)容,通過 mix 能進行視頻幀混合疊加,那么就可以得到最后轉(zhuǎn)場視頻幀了。

          vec4 color = mix(texture2D(sTexture1,vTextureCoord),texture2D(sTexture2,vTextureCoord),a);

          渲染進度控制

          似乎到這里就可以大功告成了,實際上才剛剛完成了一半~~~

          要知道轉(zhuǎn)場效果是隨著時間來播放的,就上面的例子中,轉(zhuǎn)場時間內(nèi),一開始都是視頻 A 的內(nèi)容,然后視頻 A 逐漸減少,視頻 B 逐漸增多,到最后全是視頻 B 內(nèi)容,在我們的 Shader 中也要體現(xiàn)這個時間變化的概念。

          在 Shader 中定義 progress 變量,代表轉(zhuǎn)場的播放進度,進度為 0 ~ 1.0 之間。

          uniform float progress;

          同時在每一次渲染時更新 progress 變量的值。

          GLES20.glUniform1f(muProgressHandle, mProgress);

          progress 為 0 時代表轉(zhuǎn)場剛剛開始,當 progress 為 1 時代表轉(zhuǎn)場已經(jīng)結(jié)束了。

          if (mProgress >= 1.0f) {
          mProgress = 0.0f;
          } else {
          mProgress += 0.01;
          }

          這里 progress 每次遞增 0.01,完成一次轉(zhuǎn)場就需要 100 次渲染,每次渲染間隔 30ms,那么一次轉(zhuǎn)場動畫就是 3000ms 了,當然這個可以自己調(diào)節(jié)的。

          畫面繪制

          再回到 mix 函數(shù)的參數(shù) a ,這個參數(shù)起到了隨時間調(diào)節(jié)轉(zhuǎn)場混合程度的作用。當 a = 0 時,全是視頻 A 的內(nèi)容, 當 a = 1 時,全是視頻 B 的內(nèi)容。

          如上圖所示,在轉(zhuǎn)場動畫的某一幀,左側(cè)是視頻 A 的內(nèi)容,因為此時 a = 0,右側(cè)是視頻 B 的內(nèi)容,此時 a = 1 。

          可以看到在一次渲染繪制內(nèi) a 既要能等于 0 ,還要能等于 1 ,這個是怎么實現(xiàn)的呢?

          事實上我們說的一次渲染繪制,通常指 OpenGL draw 方法的一次調(diào)用,但是在這一次調(diào)用里,還是有很多步驟要執(zhí)行的。

          OpenGL 渲染管線會先執(zhí)行頂點著色器,然后光柵化,再接著就是片段著色器,片段著色器會根據(jù)紋理坐標采樣紋理貼圖上的像素內(nèi)容進行著色,因此片段著色器在管線中會多次執(zhí)行,針對每個像素都要進行著色。

          上面圖像的小方塊就好比一個像素,每個像素都要執(zhí)行一個片段著色器。

          首先,肯定所有的像素都要進行著色的。左側(cè)方塊采樣視頻 A 的紋理進行著色,右側(cè)方塊采樣視頻 B 的紋理進行著色。

          回到如下代碼:

          mix(texture2D(sTexture1,vTextureCoord),texture2D(sTexture2,vTextureCoord),a);

          只要保證繪制左側(cè)時 a = 0,繪制右側(cè)時 a = 1 就行了。這里可以通過移動紋理坐標來控制 a 的值。

          vec2 p = vTextureCoord + progress * sign(direction);
          float a = step(0.0,p.y) * step(p.y,1.0) * step(0.0,p.x) * step(p.x,1.0);

          OpenGL 中定義紋理坐標范圍是 [0 ~ 1] ,可以將范圍右移 0.5 ,從而變成 [0.5 ~ 1.5] ,此時紋理坐標一半位于規(guī)定范圍內(nèi),一半超出界外了。

          這樣就可以通過對當前像素小方格對應(yīng)的紋理坐標的 x,y 值運用 step 函數(shù)進行判斷是否在界內(nèi),就可以決定是采樣視頻 A 還是視頻 B 的圖像了。

          當每次刷新 progress 時,就向右移一小段距離,視頻 A 隨著右移而變少,視頻 B 變多,這樣就是實現(xiàn)了轉(zhuǎn)場效果。


          聯(lián)想和總結(jié)

          不知道這個簡單的例子有沒有讓你想到些什么?

          對的,沒錯,就是升職加薪,走向巔峰必備的 PPT 技能,這種視頻轉(zhuǎn)場的實現(xiàn)效果就和我們在編輯 PPT 動畫時添加的一樣。

          而且這還是比較簡單的,想要做一些花里胡哨的轉(zhuǎn)場特效,缺少靈感就可以參考 PPT 里面的動畫了。

          另外,我們還可以對轉(zhuǎn)場效果做一些總結(jié)分類,比如示例中用的是圖片,可以理解成視頻 A 的最后一幀顯示與視頻 B 的第一幀顯示做轉(zhuǎn)場效果,這種轉(zhuǎn)場效果實際使用的人比較少,大多數(shù)是視頻 A 的最后一幀與視頻 B 的前一段時間的視頻做轉(zhuǎn)場效果。

          因此也可以對轉(zhuǎn)場效果做個分類:

          • 視頻 A 最后一幀與視頻 B 第一幀做轉(zhuǎn)場動畫
          • 視頻 A 最后一幀與視頻 B 前一段時間視頻做轉(zhuǎn)場動畫
          • 視頻 A 最后一段時間視頻 與視頻 B 第一幀做轉(zhuǎn)場動畫
          • 視頻 A 最后一段時間視頻 與視頻 B 前一段時間視頻做轉(zhuǎn)場動畫

          這四個分類的實現(xiàn)原理其實都差不多,如果是一段視頻的話,那么就在視頻播放時更新對應(yīng)紋理。

          以上就在關(guān)于使用 OpenGL 在視頻編輯中實現(xiàn)轉(zhuǎn)場效果的講解,通過這篇文章希望大家可以掌握轉(zhuǎn)場的基本實現(xiàn)原理。

          文中用到的代碼示例,可以關(guān)注我的微信公眾號【紙上淺談】,回復(fù) “轉(zhuǎn)場” 即可~~~

          推薦閱讀

          干貨分享 | Shader 實現(xiàn) PPT 轉(zhuǎn)場效果(附源碼)



          技術(shù)交流,歡迎加我微信:ezglumes ,拉你入技術(shù)交流群。

          掃碼關(guān)注公眾號【音視頻開發(fā)進階】,一起學習多媒體音視頻開發(fā)~~~


          喜歡就點個「在看」?▽
          瀏覽 69
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  国产AV无码成人精品一区 | 色婷婷在线免费视频 | 国产精品一卡二卡在线观看 | 国产一级操逼片 | 啪啪啪网站免费看 |