iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 20
2
Software Development

30天之即時網路影音開發攻略(小白本)系列 第 20

30-20之如何建立像 KKTV 一樣的點播功能呢 ?

黑色好看版 - 傳送門


正文開始

前面聲音與影像的基本原理都學習完後,咱們接下來要來實作一些東西。

在筆者的30-09之別人要如何聽到我的聲音呢 ?有提到三種影音的傳遞方式,分別為:

  • 將聲音檔案直接丟給對方 ( 方法 1 )
  • 將聲音檔案以串流的方式傳送給對方 ( 方法 2 )
  • 像直播或網路電話一樣即時的將聲音傳送給對方 ( 方法 3 )

接下來我們將來實作方法 2 的選項,而這東西事實上就是點播網站的應用,像 KKTV、楓林網就是這種類型的應用,本篇文章將會說明:

如何建立的像 KKTV 一樣的點播功能呢 (可以動就好版) ?

https://ithelp.ithome.com.tw/upload/images/20181104/20089358KWIlq1XlIf.jpg

先說好,如果真的要建立像 KKTV 一樣的可營運的應用,還需要做不少架構的調整,這裡就是只是學習如何做出可以動的點播網站,也就是可以看片 (不是全部下載完才可以看)。

本篇將分為以下幾個章節:

  • 點播架構原理。
  • 實作 - 建立 Media Server。
  • 實作 - 網頁用戶端取得串流影像。

架構原理


基本上點播的架構,最基本(不管流量或 CDN 這些鬼)的樣貌會如下:

https://ithelp.ithome.com.tw/upload/images/20181104/200893585CaXOeE2zc.png

然後基本上可以選擇的協議有RTMPHLSHTTP-FLVMPEG-DASH

那這裡問個問題 ?

我要選擇那個協議呢 ?

基本上我覺得是要看你的用戶端的裝置取向,基本上以現在的狀態選擇 HLS 與 MPEG-DASH 在點播類的應用,應該是最安穩的,最主要我覺得有以下三個原因:

  • 這兩個都是使用 HTTP 來傳輸,不太會發生有的用戶可以看有的不行。
  • 大部份的平台都可以找到方法支援。
  • 這兩種都有支援依劇網路狀況,來自動調整畫質的功能,這在看影片時尤其有用。

這兩個協議可以去參考筆者的以下兩篇文章。

30-17之 MPEG-DASH 傳輸協議
30-15之 HLS 傳輸協議

接下來咱們就先以 HLS 為主,來開始來進行實作 ( Dash 的建立實際上也差不多 )。

實作 - 建立 Media Server


首先第一部,我們要先建立一個 Media Server,它的主要功能有以下兩個:

  • 可以將影片檔轉換成 HLS 使用的 .m3u8。(不一定要在 Media Server 中處理,這裡只是範例)
  • 用戶可以使用 Http 來取得 HLS 影片。

Media Server 現在的選擇事實上很多,像以 nodejs 來說可以使用下面連結的這個,非常的簡單,而 nginx 它也有提供一些 media server 的套件。

nodejs-media-server
nginx-rtmp-module
nodejs-hls-server

接下來我們簡單的以 nodejs-hls-server 這個套件來實作個 Media Server。

1. 建立 Media Server

這個 Media Server 有兩件事情要處理。

  • 可以將影片檔轉成 HLS 用的 .m3u8 檔。
  • 用戶可以使用 Http 來使用 HLS 觀看影片。

首先咱們先來看看 Server 的部份,基本上程式碼很簡單,就像它套件裡面使用的,建立一個 Http Server 然後將 HLS 的套件附加到裡面。

// index.js

const HLSServer = require('hls-server')
const http = require('http')

const server = http.createServer()
const hls = new HLSServer(server, {
  path: '/streams',     // Base URI to output HLS streams
  dir: 'source-m3u8'  // Directory that input files are stored
})
server.listen(8000)

然後這裡還要做一件事情,那就是將 .mp4 影片檔轉換成 .m3u8 檔,這裡我們就需要使用到前一篇文章說的 ffmpeg 的神器,基本上程式碼如下,這裡我將套件裡的範例改成 async/await 的版本。

然後下面這段程式碼,就會將輸入的 .mp4 檔轉換成每 10 秒一段的 .ts 檔,然後最後在產生出 .m3u8 檔到你指定的位置。

const ffmpeg = require('fluent-ffmpeg')

module.exports = {
    convertToHls: async (file) => {
        return new Promise((resolve) => {
            ffmpeg(file, { timeout: 432000 }).addOptions([
                '-profile:v baseline', // for H264 video codec
                '-level 3.0',
                '-s 640x360',          // 640px width, 360px height 
                '-start_number 0',     // start the first .ts segment at index 0
                '-hls_time 10',        // 10 second segment duration
                '-hls_list_size 0',    // Maxmimum number of playlist entries)
                '-f hls'               // HLS format
            ]).output(`./source-m3u8/output.m3u8`).on('end', resolve).run()
        });
    }
}

上面這段要在 Server 啟動前先完成,使用範例如下:

// conver.js

const ffmpegHelper = require('./ffmpeg-helper’);

(async () => {
   await ffmpegHelper.convertToHls(‘./source-mp4/input.mp4’);
})();

最要在執行以下兩段程式碼,然後就可以使用了。

node conver.js  // 轉換成 .m3u8 檔
node index.js //啟動 server

然後到了這裡 Server 端,就準備才不多了。接下來就進入到用戶端。

使用 ffplay 測試

對了如果你在完成 server 以後,想要先測試一下你轉的 .m3u8 檔可不可以看,可以使用 ffplay 來測看看,執行完有看到影片就代表 ok !

ffplay http://127.0.0.1:8000/streams/output.m3u8

實作 - 網頁用戶端取得串流影像。


接下來咱們來建立一個可以在網頁上。

基本上要做的事情有以下幾件:

  • 載入 hls.js,這樣才可以讓 audio 標籤直接使用 hls 連結。
  • 讀取 hls 來源 ( hls.loadSource )。
  • 讀取到以上就播放 ( video.play )。
<html>
<head><title>Test</title></head>
  <body>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <video controls id="video"></video>
  

  <input type="text" />
  <button id="load">Load</button>
  <script>
    if(Hls.isSupported()) {
      var video = document.getElementById('video');
      var hls = new Hls();
      hls.attachMedia(video);
      hls.on(Hls.Events.MANIFEST_PARSED,function() {
        video.play();
      });
      document.querySelector("#load").addEventListener("click", function () {
        hls.loadSource(document.querySelector("input").value);
      })
   } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
      video.addEventListener('canplay',function() {
        video.play();
      });
      document.querySelector("#load").addEventListener("click", function () {
        video.src = document.querySelector("input").value;
      })
    }
  </script>
  </body>
</html>

執行結果如下圖。

https://ithelp.ithome.com.tw/upload/images/20181104/20089358iHkOkBuyBY.jpg

結論


本篇文章中,咱們學習到如何建立最簡單可以動的點播功能,基本上重點就是三個功能。

  • Media Server 可以處理 HLS 請求處理。
  • Media Server 可以將不同格式的影片轉換 HLS 用的 .m3u8 (事實上這不一定要在 Media Server 處理)
  • Client 要可以播放 HLS。

接下來下一篇文章咱們將要來學習如何建立一個直播功能

參考資料



上一篇
30-19 之收到聲音後要如何的播出呢 ? ( FFMpeg )
下一篇
30-21之如何建立的像 17 一樣的直播功能呢 ?
系列文
30天之即時網路影音開發攻略(小白本)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
chunhan
iT邦新手 5 級 ‧ 2019-07-12 16:21:08

請問我想用node.js把mp4檔案轉成hls的檔案,但複製您的node.js程式執行後,無錯誤訊息,但也沒有hls相關的檔案產生,但相同的參數,直接用ffmpeg轉檔確可成功,是我哪裡沒設定好嗎?

馬克 iT邦研究生 4 級 ‧ 2019-07-12 16:49:22 檢舉

呃不好意思…… 下面這一段有點問題 ~ 抱歉 ~

// conver.js

const ffmpegHelper = require('./ffmpeg-helper’);

(async () => {
   await ffmpegHelper.convertToHls(‘./source-mp4/input.mp4’);
});

改成如下

// conver.js

const ffmpegHelper = require('./ffmpeg-helper’);

(async () => {
   await ffmpegHelper.convertToHls(‘./source-mp4/input.mp4’);
})();
馬克 iT邦研究生 4 級 ‧ 2019-07-12 16:49:51 檢舉

樣應該會有看到產生的 hls 了。

我要留言

立即登入留言