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正常播放啦~