# 開發直播應用要知道的事

今天來談談前端實作串流這件事。

在早期,如果想要做影片相關的應用的話,只能用像是 flash 之類的方式嵌入,不像現在那麼奢侈,不過自從 <video> tag 出現後,我們不需要再使用 flash 就可以播放影片了。

最近直播應用一個接著一個,如果要讓體驗好一些的話,開發上就要注意許多細節。不過今天可能沒辦法一一介紹,我們會從最基礎串流協定與前端上常用開發方式來做介紹。

# 編碼與常見影片格式

首先我們來了解一下編碼以及影片格式。對於電腦來說,因為內部只看得動二進制的位元碼,所以需要一個編碼方式來將影像轉換成二進位的文件,而為了讓各個系統通用,所以目前有幾個主流的編碼方式:H.264 與 VP8。

對於影片來說,如果我們將資料原封不動地傳上去,絕對是大到不行,在傳輸上不太可能達到即時,效益也不大,因此在編碼的時候也會將影片做適當的壓縮。

目前主流的編碼方式有:

  • H.264 (opens new window):目前主流的影片編碼方式,可以很有效率地壓縮影片大小,目前許多服務都使用此編碼方式。
  • VP8 (opens new window):由 Google 釋出,希望透過 HTML 和開放的 VP8 編碼來取代 H.264。

這是目前 video tag 在各大瀏覽器的支援格式情形:

Browser MP4 WebM Ogg
Internet Explorer YES NO NO
Chrome YES YES YES
Firefox YES YES YES
Safari YES NO NO
Opera YES (from Opera 25) YES YES

咦?阿怎麼都沒看到剛剛的編碼方式,接下來就來淺談影片格式。

# 影片格式

上述我們簡單介紹了主流的影片編碼方式,但瀏覽器或解碼方要怎麼知道該怎麼解碼呢?例如我該如何知道這一坨二進制編碼是 H.264 還是 VP8?總有有資訊來紀錄吧?要怎麼紀錄?資料又該怎麼存放,就是容器在做的事情。

一個影片的容器可以包涵:標頭(記錄編碼資訊等)、聲音編碼與影像編碼。有了容器包裝後我們才能順利解析影片與聲音,也知道要採用哪個方式編碼。而上述的 MP4、WebM、Ogg 就屬於一種封裝。

例如 mp4 這個最常見的影片格式,在影片編碼上就可以選擇 H.26x、VP9 等等,而聲音編碼則可以選擇(AAC、ALAC 等)。

而 WebM 則採用了 VP9 為影片編碼與 Vorbis、Opus 當作聲音編碼當作封裝。

# 直播串流協定

如果要做直播串流應用,有幾個蠻重要的傳輸協定:

  • RTP(Real Time Protocol):用來規範多媒體的格式如何傳輸
  • RTMP:由 Adobe 所規範的協定,將資料切成 message chunk 來傳輸
  • HLS(Http Live Streaming):由 apple 開發,為了對抗 flash player 而提出的規範。
  • HTTP-FLV:如果在網頁要做到觀看直播通常會選擇 http-flv,原因在於 http 協定與低延遲,而且也可以透過 http-chunked 的方式來做分段。

比較要特別注意的是在 hls 當中會有兩份檔案:

  • m3u8:索引檔來表示影片與聲音是如何切分的
  • .ts:實際的影片與聲音資料

因此在解碼的時候會先請求 m3u8 檔,再依照目前的時間來拿曲對應的 .ts 檔。但也因為需要先有索引才能拿檔案,代表延遲相對會高一些,如果是要求即時性的話,通常不會用這種協定,但不要求那麼即時的話,用 HLS 也算是不錯的選擇。

# Media Source Extension(MSE)

前面我們有提到各種傳輸協定,不過如果要在網頁上套用的話,目前只有上述提到的 mp4、ogg、webM 可以使用,對於一個比較進階的應用來說不太足夠,例如當時要做串流,還是得仰賴 flash 的幫助。

Media Source Extension 是 JavaScript 為了加強多媒體檔案的控制而推出 API。在以前我們或許只能用 video tag 然後塞個 URL,加幾個 event listener 做控制,然後就這樣了。

搭配 MSE 的 API,我們可以有相對細膩的操作,例如透過 fetch 拿取影像資料(ArrayBuffer 等),送給 MediaSource,再把資料餵給 video。

# flv.js 與 hls.js

如果是要做影片相關應用的話,這兩個函式庫應該是大宗,flv.js 使用 Media Source Extension 來支援 flv 格式;hls.js 則是可以幫你處理 hls 在瀏覽器端播放要處理的麻煩事。目前主流的函式庫大概就 flv.js 與 hls.js 了,差別在於支援的編碼格式不同。

# WebRTC

雖然做直播應用的話不太可能會用 WebRTC,但實作像是小型會議室的話,webRTC 還是蠻常見的。WebRTC 想要解決的事是不透過 server/client 這種架構,而是讓兩個 client 之間直接溝通,不透過任何 server(但還是要有個 signaling server)。

不過在實作上還真的是挺麻煩的,但因為瀏覽器有支援 API,如果是想要練習小型會議的應用開發的話,可以考慮使用 WebRTC。

# 小結

今天介紹了前端在做直播的時候要理解的概念與常見的函式庫介紹。這些基本的東西先了解才不會哪天要做網頁版的時候心浮氣躁,或是出現像是後端使用 HLS 協定,卻在前端用 flv.js 串接結果發現怎麼串都串不好的類似窘境發生。

如果真正想做直播應用,最好的方法還是進入一間大公司,如果只是小專案,自己開個 server 玩玩還好,但如果要承受大流量的話(例如 200, 300 人就好),不燒錢是絕對玩不起來的,光是 CDN 的費用就貴死人。

另外除了串接影片之外,在做直播應用的時候也有許多要考慮的地方,例如:

  • 聊天室的實作
  • 禮物系統
  • 美膚美肌等功能(通常是後端先過濾好才送來前端,但如果在前端也能做一些效果也挺酷的)
  • 加解密
  • 字幕與影片同步

現在直播服務越來越多,參考各大網站的實作也是很好的學習機會。

在瀏覽器雖然不像 App 端那樣有那麼豐富的 API 可供使用,但透過 WebGL 或是 AudioNode 之類的 API,或許在直播的應用上可以變得更有趣也說不定,至於 WebGL 與 AudioNode,就看有沒有機會再來介紹了。