基於 IJKPlayer-concat 協議的視頻無縫拼接技術實現

1、前言

Hi,你們好,我是承香墨影!html

開門見山,開篇名義。今天來聊聊如何將多段視頻,拼接成一個完整而連續的視頻,而後無縫進行播放。git

這樣的需求應該不算偏門吧?程序員

最簡單的就是一些視頻 App,會將大段的視頻切割成小段的視頻進行播放,還有一些在播放視頻以前,會插播一段廣告,這些需求均可以被本文的內容覆蓋到。github

說到多個視頻拼接來講,若是你瞭解過 Google 出的 ExoPlayer 的話,它其內正好有一個 ConcatenatingMediaSource 能夠來完成多個視頻源的拼接工做,而且 Api 很好用,基本上算是無縫拼接。安全

不過呢,ExoPlayer 是依賴 MediaCodec 的,除了 Api Level 的限制以外(Api Level 16+),它對設備硬件也是有要求的,在一些低端機上,你會碰到一些莫名其妙的卡頓、馬賽克、花屏等問題。而正是由於封裝的太好了,若是你想自行添加軟解,很遺憾,不太簡單。而 Github 上 extensions 中,對 ffmpeg 的支持,也只是僅限於 Audio,對 Video 沒有這個支持。服務器

本文是基於另一個很火的開源播放器:IJKPlayer,來看看如何去拼接視頻。tcp

2、IJKPlayer Concat

IJKPlayer 是一個基於 FFmpeg 的輕量級 Android/iOS 視頻播放器,被 Bilibili 開源出來,算是國內很火的一款開源播放器了,不少 App 都在用。ide

由於背靠 FFmpeg,因此你在視頻編碼解碼上碰到的大部分問題,IJKPlayer 均可以幫你解決,是一款很是好用的播放器。學習

IJKPlayer 自己已經很好用了,你若是想播放多段視頻源的話,想要挨個的順序播放,在要求不高或者自己有轉場效果的前提條件下,也不是不能夠。可若是是須要那種無縫的銜接,使用這種方式你會發現會有短暫的黑屏,由於加載新的視頻源須要經歷一小段時間,這種黑屏的現象在越差的設備上,越明顯。測試

對此,我這裏推薦的解決方案,就是使用 FFmpeg 的 concat 協議

2.1 什麼是 concat

concat 是 FFmpeg 提供的一個虛級聯腳本分解器(如下簡稱 concat 協議),它是以一段有規則的腳本文件的形式存在的。可使用 concat 定義一個視頻播放列表,FFmpeg 在播放的時候,會根據你定義的順序,一個接一個的解析進行播放,就好像他們自己就是一個視頻源同樣。

這麼解釋可能有點不清晰,不過若是你瞭解 .m3u8 的格式,你對 concat 的理解應該就不難,它們都是定義了一個視頻列表,交由播放器的解碼器去順序播放。

具體的信息,能夠去 FFmpeg 的官方文檔中,查閱對應的內容。

FFmpeg Doc:

https://ffmpeg.org/ffmpeg-formats.html#concat

2.2 concat 文件

想要使用 concat 協議,首先須要定義一個待解析的文件。它必須是以 .ffcat 或者 .ffconcat 後綴結尾,而且文件的內容頭,必須標記當前 concat 的版本號。

其內有兩個可配置的選項:

  • file:用於指定一個待解析的視頻源,它能夠指定一個本地的文件路徑,或者一個在線的 Uri,都是合法的。
  • duration:標記前一個 file 指定的視頻源的長度,根據官方文檔的介紹,它是和 seek 相關的,當你調整進度的時候,它能夠精準的定位到文件。不過它是一個輔助參數,若是你拼接的視頻碼率什麼的參數都一致,是能夠不須要它的,因此 duration 是一個非必須的參數。

下面舉個官方的例子來看看一個完整的 .ffcat 文件,應該是什麼樣子的。

ffconcat version 1.0
# my first filename
file /mnt/share/file-1.wav
duration 20.0
# my second filename including whitespace
file '/mnt/share/file 2.wav'
# my third filename including whitespace plus single quote
file '/mnt/share/file 3'\''.wav'

2.3 IJKPlayer 對 concat 的 Options 配置

在使用 IJKPlayer 的時候,會有一些設置是經過 setOption() 方法進行設置的,若是須要支持 concat 協議,同時也須要有對應的設置。

這裏主要關注兩點:

  1. protocol_whitelist : 協議白名單。
  2. safe:安全路徑。

爲了讓 IJKPlayer 能支持 concat 協議,你須要將 concat 配置到它的白名單協議裏,主要是爲了添加 ffconcat 和 concat 兩個。

ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "protocol_whitelist", "rtmp,concat,ffconcat,file,subfile,http,https,tls,rtp,tcp,udp,crypto");

而 safe 主要是爲了指定容許一些不安全的路徑,默認值是 1 ,會拒絕一些不安全的文件路徑。固然,什麼是安全路徑?你能夠自行測試或者查閱文檔,這裏直接將它設置爲 0 ,就能夠將其安全監測關掉。

ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT,"safe",0);

到此,基本上就說清楚關鍵點了,直接將這個 .ffcat 文件,丟給 IJKPlayer 就能夠正常的順序播放了。

concat 相關的內容很是的少,若是你在實際操做過程當中,碰到問題,仍是建議關注一下 Logcat 的輸出信息,看看出錯的緣由。固然,通讀一遍 FFmpeg 的 concat 文檔,也是有幫助的。

3、Concat 查缺補漏

3.1 什麼是安全路徑

前面提到的,concat 文件中,file 後面跟隨的文件路徑,必須是一個安全路徑,那什麼是安全路徑?

根據 concat 的文檔描述,安全路徑必須是一個相對路徑,而且只不包含特殊符號,只包含(字母。數字、句點、下劃線)等字符,而且路徑開始的時候,不包含句點「.」,則認爲是一個安全路徑。

例如 :

file a.mp4

則認爲是當前 .ffcat 文件所在目錄下的 a.mp4 文件,這是一個安全路徑。

相反的,例如 :"https://"、"file://"、"./" 這種視頻源路徑,均會視爲不安全路徑。

3.2 ffcat 文件是否必定要在本地

FFmpeg 只是接受一個 concat 協議格式的數據流,具體它是在本地仍是在遠端的服務器上,實際上是不影響的。

3.3 file 是否能夠混編

file 後面跟隨的視頻源的地址,concat 並不強制要求須要都在同一個地方。

ffconcat version 1.0

file /sdcard/a.mp4

file http://down4.xxx.com/hash/c644d9e118417e56d91cba3dc467ab9b.mp4

例如這樣一個 .ffcat 文件,它是合法可播放的。

3.4 視頻拼接的地方有黑屏閃動

concat 要求拼接的視頻必須具備相同的流(相同的碼率和時間基準等),因此若是先後兩個視頻源這些參數不一致,是可能致使閃一下黑屏的。

這個問題,我在很是差的電視盒子上作過測試,若是文件流保持一致,是能夠作到無縫銜接。因此若是你也碰到這樣的狀況,不要懷疑 FFmpeg 的 concat 的問題,從新用 FFmpeg 轉碼一下你的視頻文件再試試吧。

https://github.com/alwaystest/Blog/issues/58

https://www.jianshu.com/p/ea794a357b48

今天在公衆號後臺回覆成長『成長』,將會獲得我整理的一些學習資料,也能回覆『加羣』,一塊兒學習進步。

推薦閱讀:

相關文章
相關標籤/搜索