阿里P6P7【安卓】進階資料分享+加薪跳槽必備面試題
轉場效果是什麼?面試
轉場效果,簡單來講就是兩段視頻之間的銜接過渡效果。函數
如今拍攝 vlog 的玩家愈來愈多,要是視頻沒有一兩個炫酷的轉場效果,都很差意思拿出來炫酷了。post
那麼如何在視頻編輯軟件中實現轉場效果呢?學習
這裏提供使用 OpenGL 實現視頻轉場的一個小示例,咱們能夠經過自定義 GLSL 來實現不一樣的轉場效果。動畫
以在 Android 平臺上做爲演示,但其實不論是 Android 仍是 iOS,實現的原理都是同樣的。spa
首先要有兩段視頻,視頻 A 和視頻 B,先播放視頻 A 後播放視頻 B,中間有一段過程稱爲 C ,C 就是視頻 A、B 作轉場動畫的時間段。code
以下所示:orm
播放器按照時間順序,從 A -> C -> B 的播放,這樣就有了轉場的效果。視頻
視頻轉場,首先就得有視頻,直接從視頻 A、B 中解碼出當前幀並經過 OpenGL 顯示到屏幕上就行了,若是你對這個操做不熟悉的話,能夠查看個人公衆號【紙上淺談】歷史文章,都有寫過相關內容。圖片
這裏以圖片來替代視頻 A、B 中解碼出來的幀。
最終效果以下:
模擬 fps 爲 30 的視頻,用 RxJava 每間隔 30 ms 就觸發一次 OpenGL 渲染。
Observable .interval(30, TimeUnit.MILLISECONDS) .subscribeOn(AndroidSchedulers.mainThread()) .subscribe { mGLSurfaceView.requestRender() }
另外,若是在視頻 A 播放階段不斷地改變圖片,也就是更新紋理內容,就至關於在真實的解碼視頻進行播放了。
固然這些操做只是爲了讓這個小例子更加貼近真正的視頻轉場,重要的仍是在於如何實現轉場的 Shader 效果。
首先轉場的時候要有兩個紋理做爲輸入,那麼確定要定義兩個 sampler2D
進行採樣了。
varying vec2 vTextureCoord;//接收從頂點着色器過來的參數 uniform sampler2D sTexture1; uniform sampler2D sTexture2;
其中 sTexture1
對應於視頻 A 內容,sTexture2
對應於視頻 B 內容。
vTextureCoord
對應於頂點着色器傳遞過來的紋理座標,視頻 A 和 視頻 B 都須要用到這個紋理座標。
這個時候,只要調用 texture2D 方法就能獲得視頻 A 和 視頻 B 的內容了。
// 獲得視頻 A 的內容 texture2D(sTexture1,vTextureCoord) // 獲得視頻 B 的內容 texture2D(sTexture2,vTextureCoord)
要注意的是這裏說獲得視頻 A/B 的內容,是獲得紋理座標對應的圖像內容。也就是說若是紋理座標是 [0,1] 範圍內,那麼能夠獲得視頻 A/B 的所有圖像內容。若是座標是 [-0.5,0.5] 那麼只能採樣獲得一半內容了。
因爲轉場效果是須要視頻 A 和視頻 B 進行疊加混合的,而 GLSL 內嵌了 mix
函數進行調用。
對於 GLSL 中有哪些內嵌的函數能夠直接調用的,能夠參考寫過的文章記錄:
OpenGL ES 2.0 着色器語言 GLSL 學習 https://glumes.com/post/openg...
mix
函數的聲明以下:
genType mix(genType x,genType y,float a) // 其中 genType 泛指 GLSL 中的類型定義
它的主要功能是使用因子 a 對 x 與 y 執行線性混合,既返回 x * (1-a) + y * a
。
如今,經過 texture2D 能獲得視頻幀內容,經過 mix 能進行視頻幀混合疊加,那麼就能夠獲得最後轉場視頻幀了。
vec4 color = mix(texture2D(sTexture1,vTextureCoord),texture2D(sTexture2,vTextureCoord),a);
彷佛到這裏就能夠大功告成了,實際上纔剛剛完成了一半~~~
要知道轉場效果是隨着時間來播放的,就上面的例子中,轉場時間內,一開始都是視頻 A 的內容,而後視頻 A 逐漸減小,視頻 B 逐漸增多,到最後全是視頻 B 內容,在咱們的 Shader 中也要體現這個時間變化的概念。
在 Shader 中定義 progress
變量,表明轉場的播放進度,進度爲 0 ~ 1.0 之間。
uniform float progress;
同時在每一次渲染時更新 progress
變量的值。
GLES20.glUniform1f(muProgressHandle, mProgress);
當 progress
爲 0 時表明轉場剛剛開始,當 progress
爲 1 時表明轉場已經結束了。
if (mProgress >= 1.0f) { mProgress = 0.0f;} else { mProgress += 0.01;}
這裏 progress
每次遞增 0.01,完成一次轉場就須要 100 次渲染,每次渲染間隔 30ms,那麼一次轉場動畫就是 3000ms 了,固然這個能夠本身調節的。
再回到 mix
函數的參數 a
,這個參數起到了隨時間調節轉場混合程度的做用。當 a = 0 時,全是視頻 A 的內容, 當 a = 1 時,全是視頻 B 的內容。
如上圖所示,在轉場動畫的某一幀,左側是視頻 A 的內容,由於此時 a = 0,右側是視頻 B 的內容,此時 a = 1 。
能夠看到在一次渲染繪製內 a 既要能等於 0 ,還要能等於 1 ,這個是怎麼實現的呢?
事實上咱們說的一次渲染繪製,一般指 OpenGL draw 方法的一次調用,可是在這一次調用裏,仍是有不少步驟要執行的。
OpenGL 渲染管線會先執行頂點着色器,而後光柵化,再接着就是片斷着色器,片斷着色器會根據紋理座標採樣紋理貼圖上的像素內容進行着色,所以片斷着色器在管線中會屢次執行,針對每一個像素都要進行着色。
上面圖像的小方塊就比如一個像素,每一個像素都要執行一個片斷着色器。
首先,確定全部的像素都要進行着色的。左側方塊採樣視頻 A 的紋理進行着色,右側方塊採樣視頻 B 的紋理進行着色。
回到以下代碼:
mix(texture2D(sTexture1,vTextureCoord),texture2D(sTexture2,vTextureCoord),a);
只要保證繪製左側時 a = 0,繪製右側時 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] ,此時紋理座標一半位於規定範圍內,一半超出界外了。
這樣就能夠經過對當前像素小方格對應的紋理座標的 x,y 值運用 step
函數進行判斷是否在界內,就能夠決定是採樣視頻 A 仍是視頻 B 的圖像了。
當每次刷新 progress 時,就向右移一小段距離,視頻 A 隨着右移而變少,視頻 B 變多,這樣就是實現了轉場效果。
不知道這個簡單的例子有沒有讓你想到些什麼?
對的,沒錯,就是升職加薪,走向巔峯必備的 PPT 技能,這種視頻轉場的實現效果就和咱們在編輯 PPT 動畫時添加的同樣。
並且這仍是比較簡單的,想要作一些花裏胡哨的轉場特效,缺乏靈感就能夠參考 PPT 裏面的動畫了。
另外,咱們還能夠對轉場效果作一些總結分類,好比示例中用的是圖片,能夠理解成視頻 A 的最後一幀顯示與視頻 B 的第一幀顯示作轉場效果,這種轉場效果實際使用的人比較少,大多數是視頻 A 的最後一幀與視頻 B 的前一段時間的視頻作轉場效果。
所以也能夠對轉場效果作個分類:
這四個分類的實現原理其實都差很少,若是是一段視頻的話,那麼就在視頻播放時更新對應紋理。
以上就在關於使用 OpenGL 在視頻編輯中實現轉場效果的講解,經過這篇文章但願你們能夠掌握轉場的基本實現原理。
阿里P6P7【安卓】進階資料分享+加薪跳槽必備面試題