"今天又是充滿但願的一天"git
最近在作一個視頻播放的需求,由於比較簡單,只須要實現基本的loading,播放,暫停等功能,因此就用Android系統的播放器MediaPlayer。原本開開心心打完了工,正偷偷給妹妹發微信,測試大姐拿着手機過來就噼裏啪啦一頓輸出github
「啊,大家的視頻加載怎麼這麼慢?!」web
「你看看人家iOS就不這樣,這樣能上線嗎?!」微信
臥槽,我測的時候明明好好的啊,怎麼如今加載個視頻就要30多秒。看着不斷轉圈圈的loading圖,我內心大罵markdown
「又tm有坑是吧」oop
爲了避免耽誤各位男哥哥女哥哥的時間,直接上結論:視頻元數據位置不對測試
???什麼是視頻元數據?哪裏位置不對?你特麼寫技術文還要別人百度是吧?spa
別別別,聽我解釋code
實際項目中用到的視頻格式大可能是MP4,MP4格式的視頻是由一個個Box組成的。這個Box能夠理解爲數據塊。Box裏面能夠嵌套Box:orm
(若是哥哥們想本身體驗一把, mac能夠用MediaParaser, window用Mp4Info)
ftyp,moov,mdat就是Box的名字。這裏須要重點關注的是moov和mdat兩個Box。
moov就是視頻的元數據,存放着視頻的整體信息,時長啦,碼率啦,寬高等等
mdat是具體的媒體數據,也就是咱們播放的內容
下面這句話很關鍵
播放器獲取到moov box才能開始播放視頻!!!
播放器獲取到moov box才能開始播放視頻!!!
播放器獲取到moov box才能開始播放視頻!!!
這句話是這篇文章的核心。其餘能夠無論,這個起碼要記住
因此關於播放器加載視頻慢的緣由,聰明的哥哥必定早就有答案了,繼續看無非就是驗證一下啦
上面那張圖是理想狀態下視頻box的位置。
但一些視頻在壓制的時候,會把moov box放在視頻尾部,也就是mdat以後。這就形成播放器必須把整個視頻下載完才能獲取到moov box,而後才能播放。
至關於你和妹子去約會,剛見面老闆說線上有問題讓你解決,你哼哧哼哧解決完繼續約會你看妹妹會不會當場跟你分手
直接緣由是找到了。聰明的哥哥必定會提出另外一個問題
既然moov box這麼關鍵,爲何有的視頻會把它放在最後呢?
這個我作了一下實驗,發現ffmpeg在轉換視頻格式的時候,會默認把moov box放在視頻尾部。我猜是ffmpeg轉化完整個視頻以後才能確切知道新視頻的時長,碼率等信息,因此順手就把它放到新視頻的末尾了。
ffmpeg其實也提供了移動moov box到視頻頭部的命令
ffmpeg -i input.mp4 -c copy -f mp4 -movflags faststart output.mp4
複製代碼
這不就是解決方案之一嘛?
用新的視頻一試,加載時間果真變成2~3秒了
真相大白!!!
正當我神清氣爽準備再找妹妹交流感情之時,產品阿姨告訴我,咱們視頻有幾萬個,項目立刻要上線了,誰給你時間一個個轉換,你說啊,你說啊!!!
我就是個打工的.. 別罵我嘛..
實際開發中會有各類狀況沒法對視頻源作修改,這時候咱們只能本身想辦法。
視頻播放的前提是要獲取到moov box,而視頻源moov box在尾部,那麼咱們能不能
先請求視頻的尾部獲取到moov box,而後再從頭請求視頻呢?
固然能夠。流媒體的請求並非一次請求完成的,而是分片請求。 先發起一個http請求,讀取響應body的開頭,若是發現moov在開頭就繼續往下讀mdat。若是沒有發現,第二個請求直接讀取文件末尾的數據,這樣用兩個請求也能獲取到moov。這個方案要求服務端能支持Request-Range請求,也就是能經過Range直接讀取文件尾部,不過通常的oss服務都支持。
這個方案能夠耶!但是難道要我重寫一遍MediaPlayer的請求??那個人妹妹怎麼辦?!
轉念一想,這個問題應該很廣泛,聰明的哥哥們必定已經填過坑了。因而我用ijkPlayer和exoPlayer分別測了一下,果真這兩個播放器都已經對這種狀況作了處理,直接替換就好。ijkPlayer的官方so庫不支持https請求,因而最終採用了exoPlayer
耶!終於結束了!雖然妹妹早就不耐煩地不回我消息了,但我相信只要堅持對她好她必定會感動的。下個坑,我必定不會再讓妹妹久等了
我是方木
想把技術變得不那麼枯燥
想用手裏的技術去解決一些問題,實現一些東西
想要賺錢,想要成長
歡迎各位交流關注~~
參考文章 阿里巴巴工程師這樣秒開短視頻