Chrome使用video無法正常播放MP4視訊的解決方案

Yellow_ice發表於2020-09-28

    H5的video標籤讓前端開發者用一行程式碼就可以實現視訊和音訊的播放,然而,有時候我們會突然發現,某些Mp4格式的視訊在Chrome下居然無法正常播放?這究竟是什麼原因呢?這篇文章主要分析了部分Mp4檔案在Chrome下無法正常播放的原因,最後,將會給出相應的解決方案~

一、先從video標籤講起

    在2000年代初期到後期,網路上的視訊播放主要依靠Flash外掛,這是因為當時沒有其它方法可以在瀏覽器上流式傳輸視訊,然而,並非所有瀏覽器都擁有相同的外掛,同時,如果使用者如果沒有安裝Flash外掛,則無法播放任何視訊

 

    為了填補這個空白,WHATWG開始研究HTML標準的新版本,並在HTML5中規定了一種通過video標籤來包含視訊的標準方法。在HTML5中,在頁面中播放視訊非常簡單,只需要在頁面中新增具有很少屬性的視訊標籤即可~

<html>
  <head>
    <meta charset="UTF-8">
    <title>My Video</title>
  </head>
  <body>
    <video src="some_video.mp4" width="1280px" height="720px" />
  </body>
</html>

    到目前為止,Internet Explorer 9+、FireFox、Opera、Chrome和Safari等瀏覽器中都已經支援<video>標籤,同時,<video>也能夠支援MP4、WebM和Ogg等不同視訊格式檔案的播放,因此,採用video標籤在Web站點實現視訊的播放已經成為了開發者的首選~

    然而,前不久在做一個專案時,發現在Chrome下有些MP4視訊檔案居然不能正常播放了!!!!在這個專案中,主要包括了教師端和學生端,在教師端中,老師可以上傳MP4格式的視訊作為課件,而在學生端中,學生可以開啟視訊進行學習。當我用Chrome登入到學生端時,可以看到很多課程列表,接著,我開啟了一個MP4課件進行學習  

    嗯~這個視訊看起來挺正常的呀,於是我又選擇了另一個MP4視訊進行播放~

     咦?怎麼這個MP4視訊在播放時不能看到影像而只能聽到聲音了?於是我又開啟了IE,發現這個視訊在IE中居然又可以正常播放了!

    明明都是MP4視訊格式的檔案,為什麼在Chrome中一些MP4格式的視訊就不能正常播放了?要想弄清楚裡面的原因,還需要先從視訊的檔案格式、封裝格式和編碼方式講起~

 

二、視訊格式及編碼方式簡介

1、視訊檔案格式

    在Windows系統中,我們所建立的檔案都帶有字尾,如.doc等,Windows設定字尾名的目的是讓系統中的應用程式來識別並關聯這些檔案,讓相應的檔案由相應的應用程式開啟,比如我們雙擊.doc檔案時,它會知道讓Microsoft Office去開啟而不是用PhotoShop去開啟這個檔案~

    一般來說,常用的視訊檔案格式通常包括了.mpg、.mkv、.wmv和.mp4等,當我們雙擊這些檔案時,它會和我們電腦安裝的視訊播放器關聯,並且開啟視訊播放器進行播放~我們可以隨意改副檔名,但是千萬不要以為將.avi改為.mp4,視訊就變成mp4格式了,要想真正的轉換,還需要採用如格式工廠等工具進行轉換。

2、視訊封裝格式

    視訊封裝格式是指把編碼器生成的多媒體內容(視訊、音訊和字幕)混合封裝在一起的標準。簡單點講,視訊封裝格式其實就是相當於一種儲存視訊資訊的容器,我們可以往這個容器中嵌入任何形式的資料、各種編碼的視訊和音訊~我們平時看到的.avi、.mpg和.vob這些視訊檔案格式的字尾名即採用相應的視訊封裝格式的名稱。

    

    一般來說,常見的視訊封裝格式主要包括了以下幾種:

    (1)AVI格式(檔案字尾為.avi):Audio Video InterLeaved,音訊視訊交錯格式,這種視訊格式影像質量好,但是體積過於龐大,壓縮標準不統一

    (2)DV-AVI格式(檔案字尾為.avi):Digital Video Format,由索尼、松下、JVC等多家廠商聯合提出的一種家用數字視訊格式

    (3)QuickTime File Format(檔案字尾為.mov):美國Apple公司開發的一種視訊格式,預設的播放器是蘋果的QuickTime,具有較高的壓縮比率和較完美的視訊清晰度

    (4)MPGE格式(檔案字尾可以是.mpg、.mpeg、.mpe、.dat、.vob、.asp、.3gp和mp4等):Moving Picture Experts Group,運動影像專家組格式,MPGE目前包括三個壓縮標準,分別是MPEG-1、MPEG-2和MPEG-4

    (5)WMV格式(檔案字尾為.wmv或.asf):Windows Media Viedo,微軟推出的一種採用獨立編碼方式並且可以直接在網上實時觀看視訊節目的檔案壓縮格式

    (6)Real Video格式(檔案字尾為.rm或.rmvb):Real Networks公司所制定的音訊視訊壓縮規範

    (7)Flash Video格式(檔案字尾為.flv):由Adobe Flash延伸出來的一種流行網路視訊封裝格式

    (8)Matroska格式(檔案字尾為.mkv):一種新的多媒體封裝格式,可以把多種不同編碼的視訊及16條或以上不同格式的音訊和語言不同的字幕封裝到一個Matroska Media檔內

3、視訊編碼方式

    視訊編碼方式是指能夠對數字視訊進行壓縮或者解壓縮(視訊編碼)的程式或裝置,通常這種壓縮屬於有損資料壓縮,通過特定的壓縮技術,可以將某個視訊格式轉化成另一種視訊格式~從視訊誕生到發展,無疑在追求更高質量的畫質和儘可能低的位元率,下圖主要給出了視訊編碼方式的發展。

    

    從上圖可以看出,目前常見的編碼方式式主要包括了以下幾種:

  (1)H.26X系列:包括H.261、H.262、H.263、H.264和H.265

  (2)MPEG系列:包括MPEG-1第二部分、MPEG-2第二部分、MPEG-4第二部分和MPEG-4第十部分

  (3)其它系列:AMV、AVS、Bink、CineForm、Cinepak、Dirac、VP3、VP5、VP6、VP7、VP8和VP9等

    在目前的編碼方式中,最新的就是大家關注的H.265和VP9,不過由於歷史的積累和瀏覽器的支援問題,現在還是以H.264編碼的視訊為主~

    綜上所述,其實對於同一種視訊檔案格式,如.mpg檔案,它其實包括MPEG-1、MPEG-2和MPEG-4幾種不同的視訊封裝格式,而對於MPEG-4又可以使用多種視訊編碼格式,因此,視訊的編碼格式才是一個視訊檔案的本質所在,不要簡單的通過檔案格式和封裝格式來區分視訊~

 

三、部分MP4視訊檔案無法在Chrome下播放的原因

    搞清楚了視訊的檔案格式、封裝格式和編碼格式,讓我們再回歸到前面說的那個問題中~前面提到了部分MP4視訊檔案無法在Chrome正常播放的問題。而通過前面的分析,我們可以知道,對於兩個不同的.mp4視訊來說,雖然它們的字尾名是一樣的,但是兩個MP4視訊採用的編碼格式可能是不一樣的,它們可以採用H.264或H.265的編碼格式進行編碼,也可以採用MPEG-4的編碼方式。而對於MP4視訊檔案的播放,Chrome只支援標準的H.264方式編碼。因此如果MP4視訊的編碼格式不是H.264,那麼這個視訊檔案就無法正常播放~

    那麼,為什麼Chrome只支援H.264這種編碼方式而不支援所有的視訊編碼方式呢?Google查了一下,網上給出的原因主要是說因為絕大部分的視訊編碼格式都要付專利費的,Google已經購買了H.264編碼格式,而其它的就沒有購買了~因此如果一個MP4視訊不是H.264格式的,那麼Chrome也是不支援播放的~

 

四、解決方案

    既然對於MP4視訊檔案來說,Chrome只能支援H.264編碼方式視訊檔案的播放,而由於MP4視訊檔案可能包含多種編碼,因此,較好的解決方案就是對上傳的MP4視訊檔案進行轉碼,將非H.264編碼方式的MP4視訊檔案轉換成H.264編碼方式的視訊,這樣就能夠保證所有的MP4視訊檔案在Chrome上正常播放~

1、ffmpeg轉碼

    網上Google了一圈,發現很多方法都是推薦採用ffmpeg工具進行轉碼,通過使用ffmpeg,就可以輕鬆使用命令列進行視訊轉碼~

    如果你的電腦是mac,那麼ffmpeg的安裝非常簡單,只需要下面一句命令列就搞定了 

brew install ffmpeg

    我們也可以通過npm進行安裝ffmpeg,並且在node中使用

npm install ffmpeg //安裝
var ffmpeg = require('ffmpeg');

    通過下面的命令,我們就可以輕鬆的將MP4視訊檔案轉換成H.264編碼方式的視訊

ffmpeg -i input.mp4 -vcodec h264 output.mp4 //h264預設轉碼

    然而,在實際的業務中,我們並不能總要求使用者只上傳H.264編碼方式的MP4視訊檔案,更好的方式是能夠實現MP4視訊檔案的自動轉碼而無需使用者自己進行轉碼,因此,最後我們採用了前端MP4視訊編碼格式判斷+後臺視訊檔案轉碼的方案解決~

2、前端MP4視訊編碼格式判斷+後臺視訊檔案轉碼

    首先,當使用者上傳MP4檔案時,前端會對MP4視訊檔案的編碼格式進行判斷。如果該視訊檔案是H.264編碼格式,則將事先約定的欄位is_transcode設定為0,告訴後臺無需對該檔案進行轉碼。如果不是H.264編碼格式,則將is_transcode設定為1,告訴後臺需要將該MP4視訊檔案轉換成H.264編碼格式的視訊。

    那麼,問題又來了,前端怎麼進行判斷一個MP4視訊檔案是不是H.264編碼格式呢?在這裡,就需要獲取當前視訊編碼的資訊,也就是Codec,並且根據Codec進行視訊編碼格式的判斷。而為了獲取到Codec,我們可以藉助現有的一些外掛,如mediainfo.js(https://github.com/buzz/mediainfo.js)或mp4box.js(https://github.com/gpac/mp4box.js)進行獲取,而由於medianinfo.js的體積較大,mp4box.js比較輕量,因此實現過程中採用了mp4box.js進行視訊編碼格式的檢測。

    為了使用mp4box.js,我們首先需要先進行mp4box.js的安裝

npm install mp4box --save

     接著就需要在我們的專案中引入mp4box.js

import mp4box from 'mp4box'

    由於在mp4box.js中,如果一個MP4視訊檔案的編碼格式為H.264,則其Codec是會包括avc這個字串的,因此我們可以通過判斷Codec中是否包含"avc"從而進行H.264視訊編碼格式的判斷

   

    示例程式碼如下: 

var input  = document.getElementById("file"); // 獲取上傳的檔案
input.onchange = function() {
  var file = this.files[0];
  var mp4boxfile = MP4Box.createFile();
  var is_transcode = 0;
  mp4boxFile.onReady = function(info){
    let mime = info.mime
    let codec = mime.match(/codecs="(\S*),/)[1]
    if (codec.indexOf('avc') === -1) {
      is_transcode = 1;  // 需要轉碼
    }
    // 進行檔案上傳操作
    ...
  }
  if(file){
    // 讀取mp4的buffer
    var reader = new FileReader();
    var buffer = reader.readAsArrayBuffer(file);
    reader.onload = function(e) {
      var arrayBuffer = e.target.result
      arrayBuffer.fileStart = 0
      mp4boxFile.appendBuffer(arrayBuffer)
    }
  }
}

    最後,當後臺接收到的is_transcode為1時,就將MP4視訊檔案進行轉碼,並且將轉碼後的視訊檔案儲存起來,這樣,無論使用者上傳什麼編碼格式的MP4視訊檔案,最後都能夠轉換成H.264編碼格式的視訊檔案儲存起來,因此,當使用者下次訪問頁面並播放MP4視訊時,就可以看到所有的MP4視訊都能夠在Chrome正常播放啦~

相關文章