1. 程式人生 > >關於大視訊video播放的問題以及解決方案(m3u8的播放)

關於大視訊video播放的問題以及解決方案(m3u8的播放)

在HTML5裡,提供了<video> 標籤,可以直接播放視訊,video的使用很簡單:

<video width="320" height="240" controls>
  <source src="movie.mp4" type="video/mp4"> 
</video>

這基本上能滿足大部分使用者的需求,但是還是有幾個問題需要解決:

(1)大視訊的問題。

(2)字幕的問題

(3)清晰度的問題

(4)視訊保密問題。

本文將簡單的探討上面幾個問題並給出簡單的解決方案。

備註:這些問題也是我在製作啟明星視訊系統時遇到的(演示  http://demo.dotnetcms.org/video ),所以,如果你在開發視訊播放,那麼本文應該對你有用。

 

1.大視訊問題

當使用video播放視訊時,對於大視訊最好是分片儲存,例如一個500M的視訊,以10M為一個視訊段,那麼可以分為50個片段。播放時,按需載入所需要的視訊片段(例如使用者拖動滾動條直接到一個部分)。

這裡又遇到2個問題:

1.1大檔案的上傳

大檔案上傳,這裡使用的百度的 WebUploader,百度很好的一個上傳元件,可惜已經不再維護,當然國外也有很多開源的大檔案上傳元件,所以,這個問題不大。

大檔案上傳的原理也比較簡單:HTML5裡提供了JS 的 FileReader 類,Blob類,利用這個類可以在本地直接讀取視訊的大小,例如要上傳500M的視訊,以10M為一個分塊,把視訊分割為一個為50份,對於每一份利用JQuery的AJAX分別上傳到伺服器上,等50份上傳完後,伺服器再把這50分視訊合併成一個大檔案即可。

在上傳時通常需要給每個視訊一個編號,例如 file0,file1,file2... file49, 上傳完畢後,利用.NET提供的System.IO.File.ReadAllBytes讀取這些檔案然後合併起來。

                    foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))//排一下序,保證從0-N Write
                        {
                            var bytes = System.IO.File.ReadAllBytes(part);
                            fs.Write(bytes, 0, bytes.Length);
                            bytes = null;
                            System.IO.File.Delete(part);//刪除分塊
                        }

這樣,就把本地的500M視訊,原封不動的加速上傳到伺服器暫且命名為 video1.mp4。

 

1.2大檔案分割

當視訊播放時,利用的是m3u8進行列表播放(下述),在這裡使用了ffmpeg.exe元件,ffmpeg提供瞭如下命令:

ffmpeg.exe -i a.mp4 -hls_time 30 -hls_list_size 0 -f hls  a.m3u8;

上面程式碼段裡, -i 表示輸入(input)  a.mp4,   -hls_time 30 表示每個分塊斷是30秒, hls_list_size 表示序號是從0開始。  a.m3u8 表示最終生成的檔名。

上面代表的是意思是:用ffmpeg把a.mp4進行分割,每個分段長為30秒,並把分割後的資訊存放在a.m3u8裡。

執行上述命令後,就可以得到 一些列的 *.ts 檔案和一個a.m3u8檔案

利用.NET可以通過伺服器執行合併操作。

 

1.3 m3u8

 m3u8用來儲存視訊播放的列表,他的內容類似如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:35232
#EXT-X-TARGETDURATION:10
#EXTINF:10.000,
cctv6hd-1549272376000.ts
#EXTINF:10.000,
cctv6hd-1549272386000.ts
#EXTINF:10.000,
cctv6hd-1549272396000.ts
#EXTINF:10.000,
cctv6hd-1549272406000.ts
#EXTINF:10.000,
cctv6hd-1549272416000.ts
#EXTINF:10.000,
cctv6hd-1549272426000.ts

簡單的說,m3u8存放的是播放列表,視訊以.ts格式儲存, ts即"Transport Stream"的縮寫。 全稱為MPEG2-TS,MPEG2-TS,格式的特點就是要求從視訊流的任一片段開始都是可以獨立解碼的。

不用mp4是因為,如果用mp4,那麼在2個分塊直接播放時,會出現卡頓。而ts格式可以無縫對接。

你甚至可以設定客戶端儲存的數量,例如設定為3,當使用手機看到5.ts時,手機開始快取6.ts ,7.ts, 8.ts, 只有這3個都下載完畢後,才播放,而不用等到整個下完才播放,這樣增加了播放的流暢度。(有時候我們看視訊時,卡頓時,手機會顯示一直在緩衝中,來快取片段。。。)

m3u8不是<video> 標籤的支援的標準格式。換句話說,你使用如下程式碼是無法播放的

<video width="320" height="240" controls>
  <source src="a.m3u8"  type=application/x-mpegURL> 
</video>

目前國內的有 騰訊的 tcplayerlite 和百度的cyberplayer 可以播放m3u8,不過,他們其實都使用videojs這個開源內容,外加一層面板。

在我自己開發裡,因為不想引入太多的JS,所以直接使用 HLS.JS (HTTP Live Streaming )

當引入hls後,播放視訊變的非常簡單:

                  
      <video          width="100%"      id="video2"     >     </video> 

                <script>
                    if (Hls.isSupported()) {
                        var video2 = document.getElementById('video2');
                        var hls = new Hls();
                        hls.loadSource('a.m3u8'); 
                        hls.attachMedia(video2);
                        hls.on(Hls.Events.MANIFEST_PARSED, function () {
                            video2.play();
                        });
                    }
        </script>

直接使用       hls.loadSource('a.m3u8');  即可載入播放列表。

 

1.4 播放清晰度

m3u8指向的是播放列表,他本身不提供多清晰度的問題,通常,你需要利用 ffmpeg.exe 生成不同的清晰度,例如

對於video1.mp3, 你可以生成 video-360.mp4, video-720.mp4和 video-1080.mp4 並生產 多個m3u8

 video-360.m3u8
 video-720.m3u8
 video-1080.m3u8

當視訊播放時,如果使用者選擇不同的清晰度,載入不同的m3u8.

你也可以根據使用者的網速,載入不同的m3u8.

 

2.字幕問題

 (以下內容主要來自張鑫旭的文章)HTML5 Video視訊支援支援外掛字幕,檔案字尾名是.vtt,稱為WebVTT格式,專門的web字幕格式。使用很簡單,用一個<track>元素即可,例如:

<video id="video">
<source src="example.mp4" type="video/mp4">
<track src="example.vtt" default>
</video>

只要src屬性地址OK,同時有default屬性,字幕就會生效。

字幕格式是純文字格式

WEBVTT
00:00:00.001 --> 00:00:01.000
請把你的鍋

00:00:01.001 --> 00:00:03.500
帶回你的蝦

00:00:03.501 --> 00:00:07.000
請把你的微笑留下……

00:00:07.501 --> 00:00:10.000
請把你的鍋

00:00:10.001 --> 00:00:12.000
帶回你的蝦

00:00:12.001 --> 00:00:15.000
請把你的微笑留下

<video>標籤外掛<track>

<track src="example.vtt" kind="subtitles" label="中文字幕" srclang="zh" default>

而track支援多個字幕,例如:

<track src="example.vtt" kind="subtitles" label="中文字幕" srclang="zh" default>
<track src="example2.vtt" kind="subtitles" label="中文字幕(修正)" srclang="zh">

如果你的視訊希望提供中文/英文/日文等多語言版本,利用這個方法,可以解決視訊字幕多語言版本的問題。

在youtube上,我們有時候會看到一個視訊會提供很多語言版本,如上所述,vtt是一個純文字格式,利用機器翻譯,例如百度翻譯,把 vtt翻譯上百個版本,掛在在track上,這樣

瞬間,讓你的視訊支援幾百個語言,立刻就會高大上。

 

 

最後,說一下視訊加密,無論你用何種技術,視訊最終是要在使用者端顯示的,所以,視訊本身是無法加密的,而作為簡單加密主要有2個方法:

(1)createObjectURL

當我們檢視部分網站得出視訊或者部分圖片時,你會發現網址網址是用blob:src開頭,這其實是 createObjectURL搞的鬼

有興趣的朋友可以看看其文件介紹,簡單說,他就是把真實的地址隱藏了,當你看video的src看到的是一個虛擬地址。

 

(3)m3u8 加密

如上所述,m3u8裡存放的是一個個 *.ts,對於普通使用者來說,就算看到*.ts檔案,讓他一個個下載ts,估計想死的心都有。所以,我們保護m3u8最核心的是防止工具下載。

一個簡單的解決方法是:m3u8加引數或者利用session,例如  a.m3u8?key=xxxxx-xxx-xxx

當使用工具下載視訊時,工具因為無法獲取key引數,那麼就無法獲取到a.m3u8。

當然,如果真正想下載m3u8也不是完全沒辦法,

ffmpeg.exe 這個工具既然提供了video分割為ts功能,自然也提供ts合併為一個完整的video功能。只是對普通人來說比較繁瑣罷了。

 

當然,如果你不想搞這麼複雜,使用下面程式碼就可以了, controlslist="nodownload" 讓視訊不出現下載,而contextmenu不允許使用右鍵播放,這應付一般的小白應該足夠了。

            
      <video    
         id="video2"   
         controlslist="nodownload" 
        >   
         </video>
  
      
      <script>
          $('#video').bind('contextmenu',function() { return false; });
      </script>

 

最後說一下視訊播放的問題,雖然HTML5裡使用 autoplay 就可以制動播放,但是谷歌的chrome在新版本里,已經禁止自動播放了,谷歌給的解釋:很多使用者利用autoplay這個屬性投放大量廣告,讓使用者不堪其擾。因此,如果要autoplay必須配合muted(靜音),也就是隻有靜音後自動播放才能生效,否則需要使用者手動點選“播放”。

當然谷歌也給出另外一個解決方案:就是不靜音的自動播放,需要這個網址在安全性名單裡,因此,我們看youtube是可以自動播放的,但是,很多網站是不能自動播放 。

 

以上內容是我做啟明星視訊遇到的,你可以檢視demo當然還有很多細節要考慮,但是大部分問題都已經解決。

&n