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


一、前言

Hi,大家好,我是承香墨影!

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

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

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

說到多個視頻拼接來說,如果你了解過 Google 出的 ExoPlayer 的話,它其內正好有一個 ConcatenatingMediaSource 可以來完成多個視頻源的拼接工作,並且 Api 很好用,基本上算是無縫拼接。

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

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

二、IJKPlayer Concat

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

因為背靠 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 文檔,也是有幫助的。

三、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

今天在公眾號后台回復成長『成長』,將會得到我整理的一些學習資料,也能回復『加群』,一起學習進步。

推薦閱讀:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM