Android 短視頻 SDK 轉(zhuǎn)場特效的音視頻同步分析
在短視頻的應用場景中,經(jīng)常存在用戶拍攝的兩個或者多個視頻生成一個視頻的需求,為了達到兩個視頻平滑過渡,就需要在兩個視頻中間添加轉(zhuǎn)場效果。
由于導入視頻的幀率、碼率等參數(shù)都不一致,如何保證在添加完轉(zhuǎn)場效果后音視頻同步?
本文主要介紹轉(zhuǎn)場效果的實現(xiàn)及如何保證最終合成視頻的音視頻同步,同時簡單介紹一下轉(zhuǎn)場濾鏡。
作者:金山視頻云
鏈接:https://www.jianshu.com/p/5eef175a8cb8
一. 轉(zhuǎn)場功能介紹
市面上的轉(zhuǎn)場基本分為三類:
片頭片尾轉(zhuǎn)場:即只作用在一個視頻上。
此種和普通的時間濾鏡添加區(qū)別不大,并不復雜,本文不再贅述
非重疊轉(zhuǎn)場:轉(zhuǎn)場接替作用在第一個視頻的最后和第二個視頻的開始,兩個視頻是順次拼接。
比如持續(xù)1s的blur轉(zhuǎn)場,blur濾鏡 在第一個視頻的最后0.5s開始,直到結(jié)束,作用是由清晰變模糊;在第二個視頻的開始作用,持續(xù)0.5s,作用是由模糊變清晰。
重疊轉(zhuǎn)場:轉(zhuǎn)場疊加作用在第一個視頻的最后和第二個視頻的開始,兩個視頻有一個轉(zhuǎn)場時間的重疊區(qū)。
比如持續(xù)1s的 淡入淡出轉(zhuǎn)場,淡入淡出濾鏡接收兩個視頻輸入源,并且從第一個視頻的最后1s開始作用,即在第一個視頻的最后1s需要同時啟動第二個視頻的解碼,并將解碼后的數(shù)據(jù)輸入到濾鏡中,在轉(zhuǎn)場的持續(xù)時間內(nèi)是同時疊加了兩個視頻數(shù)據(jù)。
二. 轉(zhuǎn)場方案介紹
轉(zhuǎn)場是在時間上對多個視頻做轉(zhuǎn)碼和拼接。
我們采取的方案如如下圖所示,依次對待拼接文件做解碼,輸出音頻采樣和視頻像素數(shù)據(jù)到編碼器,經(jīng)過muxer最終將不同幀率、碼率的視頻生成統(tǒng)一格式的文件。

上圖中AVMediaCapture為demuxer和decoder的封裝。
如第一章節(jié)的介紹轉(zhuǎn)場同一時間最多作用在兩個視頻上,因此只需要創(chuàng)建兩個AVMediaCapture的實例,第一個視頻解碼結(jié)束后,第三個視頻可以使用第一個視頻創(chuàng)建的AVMediaCapture,依次類推,避免反復創(chuàng)建造成資源浪費。
如下圖所示:

而對于AVMediaCapture中的解碼器(硬解為例),也不需要反復創(chuàng)建,我們來看官網(wǎng)上關于MediaCodec的生命周期:

如上圖所示,當一個文件解碼完成以后,通過reset接口使解碼器處于Uninitialized狀態(tài),當對第二個文件進行解碼時,只需要重新configure,start即可。
三. 轉(zhuǎn)場中的音視頻pts 計算
3.1 非重疊轉(zhuǎn)場
在兩個視頻之間添加持續(xù)時間 trans_t 的轉(zhuǎn)場濾鏡,濾鏡在第一個視頻 [dur_0 - trans_t / 2.0f] 開始作用,直到第一個視頻結(jié)束,然后繼續(xù)在第二個視頻的開始作用,持續(xù) [trans_t / 2.0f]。
pts 依次是之前視頻時長的累加,公式如下:
vTrack_1 和 aTrack_1 開始點的 pts : [0 + dur_0];
vTrack_2 和 aTrack_2 開始點的 pts : [dur_0 + dur_1]。
vTrack_n 和 aTrack_n 開始點的 pts : [dur_0 + dur_1 + ... + dur_n]。

3.2 重疊轉(zhuǎn)場
在兩個視頻之間添加持續(xù)時間 trans_t 的轉(zhuǎn)場濾鏡,濾鏡是同時作用在兩個視頻上的,因此濾鏡在第一個視頻的 [dur_0 - 1.0f] 時開始作用,直到第一個視頻結(jié)束,同時開始第二個視頻的解碼,并作為濾鏡的第二視頻輸入源。
pts 的計算需要將轉(zhuǎn)場的作用時間裁剪掉,公式如下:
vTrack_1 和 aTrack_1 開始點的 pts: [0 + dur_0 - trans_t];
vTrack_2 和 aTrack_2 開始點的 pts: [dur_0 + dur_1 - 2 * trans_t]。
vTrack_n 和 aTrack_n 開始點的 pts: [dur_0 + dur_1 + ... + dur_n - n * trans_t]

四. 轉(zhuǎn)場中的音視頻同步
因為采用的是pull的方式從解碼向編碼輸入數(shù)據(jù),因此在添加重疊場景的轉(zhuǎn)場時,在轉(zhuǎn)場的時間段內(nèi),同時存在2個音頻軌道和2個視頻軌道,就需要考慮四個軌道的同步問題
單個視頻的音視頻解碼同步
重疊場景的轉(zhuǎn)場,若音視頻 demuxer 相差很大,比如第一個視頻的音頻已經(jīng) demuxer 結(jié)束,但是第一個視頻的視頻還在繼續(xù)處理,因為同時開啟了第二個視頻的 demuxer ,所以會有累加的音視頻不同步的情況。

如上圖所示,在 decoder 之后添加AVSync模塊以解決此種情況的不同步問題,AVSync模塊采用視頻驅(qū)動音頻的同步模式,即,對音頻做緩存,以視頻幀驅(qū)動音頻幀向下傳遞,threshold 不超過100ms。
兩個視頻之間的視頻解碼同步
重疊場景下,轉(zhuǎn)場濾鏡需要同時輸入兩個視頻源,若第一個視頻解碼速度快,但是第二個視頻的解碼速度慢,會造成某一幀數(shù)據(jù)中只有第一個視頻,并沒有第二個視頻,或者濾鏡已經(jīng)持續(xù)了0.8s了,第二個視頻才有了輸入,造成整體的轉(zhuǎn)場效果較差。

為了解決此種問題,加入 VTracks_Sync 同步模塊, Vtracks_Sync 保證兩個視頻的 pts 的diff在100ms之內(nèi),若 vtrack_0_pts – vtrack_1_pts > 100ms, 則對 vtrack_0 的 demuxer 做暫停,反之對 vtrack_1 的 demuxer 做暫停,以達兩個視頻源的同步
五. 轉(zhuǎn)場濾鏡
重疊轉(zhuǎn)場的漸變?yōu)V鏡,基本方案為 以vtrack_0 為濾鏡的主視頻輸入源 sTexture ,以 vtrack_1 為濾鏡第二個視頻輸入源 vTexture1 ,在 shader 中通過修改漸變因子,以達到不同輸入源的比重不同。
以最簡單的淡入淡出濾鏡為例,offset 為漸變因子,例如持續(xù)時間為1s的轉(zhuǎn)場,則offset在1s內(nèi)從0漸變到1,作用到視頻幀的單位值計算公式:[offset_maxvalue / offset_maxcount]
offset_maxvalue為漸變因子的最大值,即1
offset_maxcount為作用幀數(shù),以幀率是20為例,1s的轉(zhuǎn)場,offset_maxcount即為20。
void main()
{
vec4 video = texture2D(sTexture, vTextureCoord);
vec4 screen = texture2D(vTexture1, vTextureCoord);
gl_FragColor = mix(video, screen, offset);
};
mix是對video和screen做線性混淆,即gl_FragColor = video(1- offset) + (screen * offset)
最后歡迎大家加入 音視頻開發(fā)進階 知識星球 ,這里有知識干貨、編程答疑、開發(fā)教程,還有很多精彩分享。
更多內(nèi)容可以在星球菜單中找到,隨著時間推移,干貨也會越來越多!!!

給出 10元 優(yōu)惠券,漲價在即,目前還是白菜價,基本上提幾個問題就回本,投資自己就是最好的投資!!!

加我微信 ezglumes ,拉你進技術交流群
推薦閱讀:
覺得不錯,點個在看唄~

