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

  • 2020 年 9 月 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(//github.com/buzz/mediainfo.js)或mp4box.js(//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正常播放啦~