作者:楊德倫 / 臺灣大學計算機及資訊網路中心教學組幹事
過去使用影音串流技術時,需要建置串流相關協定的伺服器,來提供服務,然而目前大多主流網頁改以HTML5技術來加以開發,其Video元素的影片來源格式尚未支援串流協定,因此我們必須使用一些技巧,讓HTML5Video元素能達到串流的功能。
前言
大多主流的入口網站及官方頁面,已經採用HTML5來開發自家網頁,尤以YouTube為最,透過自家開發的影音串流機制,來達到最佳的播放效果,同時也解決了過去使用Flash Player來當作播放平台的不便。筆者將透過HTML5 Video API與H264 Streaming Module的相關機制,將影片時間進行切割,並針對切割的間距逐一播放,以達到串流效果的相關技巧。
圖一 採用HTML5的YouTube播放器
安裝測試環境
為了讓讀者方便測試與重複操作,我們必須進行作業系統(Ubuntu)、網頁伺服器(Apache)、H264串流模組(mod_h264_streaming.so)、影音轉檔平台(FFmpeg)等機制的安裝,相關知識的取得,便成為閱讀本電子報的先決條件。另外,安裝過程中,需要對Linux的基礎指令有一定的了解與熟悉,請自行至網路上查詢相關概念,並加以學習。若讀者已有熟悉的安裝流程、環境與方法,可自行測試與實作。
安裝Ubuntu
請下載「伺服器版本」;若讀者希望能夠擁有長期支援(Long-term support, LTS),請下載LTS版本。
圖二 Ubuntu 官方下載頁面
前置作業
當ubuntu安裝完成後,我們將進行一些前置作業。請依先後順序來輸入指令「sudo apt-get update」、「sudo apt-get upgrade」「sudo apt-get dist-upgrade」,來進行系統內套件的更新與下載,若有詢問,請按下「y」鍵來繼續安裝。待一切更新完成後,請輸入「sudo apt-get install gcc build-essential libtool python-dev m4 autoconf pkg-config」來安裝後續需要用到的套件。
設定對外服務用的 IP
請輸入「sudo vi /etc/network/interfaces」來編輯網路卡相關設定,並加入下圖所示資訊:
圖三 設定網路卡對外服務用的 IP後,儲存離開
圖四 輸入「sudo ifup eth1」來啟動第二張網卡,並輸入「ifconfig」來確定是否如圖中所示。若有,則代表開啟成功
安裝Apache Web Server
一、安裝apache portable runtime
下載指令:sudo wget http://mirror.reverse.net/pub/apache/apr/apr-1.5.1.tar.gz
說明:
解壓縮後,進入該資料夾,先編輯configure檔案,約略第30145行,註解掉「$RM “$cfgfile”」(在面前加上 # 字號)後儲存,再進行以下安裝指令:
$ sudo ./configure
--prefix=/usr/local/apr
--enable-shared
--enable-static
$ sudo make
$ sudo make install
圖五 若安裝有問題,請先修改configure檔
二、安裝apr-iconv
下載指令:sudo wget http://mirror.reverse.net/pub/apache/apr/apr-iconv-1.2.1.tar.gz
說明:解壓縮後,進入該資料夾,請輸入以下安裝指令:
$ sudo ./configure
--prefix=/usr/local/apr-iconv
--with-apr=/usr/local/apr
--enable-shared
--enable-static
$ sudo make
$ sudo make install
三、安裝apr-util
下載指令:sudo wget http://mirror.reverse.net/pub/apache/apr/apr-util-1.5.4.tar.gz
說明:解壓縮後,進入該資料夾,請輸入以下安裝指令:
$ sudo ./configure
--prefix=/usr/local/apr-util
--with-apr=/usr/local/apr
--with-apr-iconv=apr-iconv
$ sudo make
$ sudo make install
四、安裝pcre (Perl-compatible regular expression library)
下載指令:sudo wget http://jaist.dl.sourceforge.net/project/pcre/pcre/8.36/pcre-8.36.tar.gz
說明:解壓縮後,進入該資料夾,請輸入以下安裝指令:
$ sudo ./configure
--prefix=/usr/local/pcre
--enable-utf8
--enable-unicode-properties
$ sudo make
$ sudo make install
五、安裝apache web server
下載指令:sudo wget http://apache.mirrors.tds.net/httpd/httpd-2.4.12.tar.gz
說明:解壓縮後,進入該資料夾,請輸入以下安裝指令:
$ sudo ./configure
--prefix=/usr/local/apache2
--with-apr=/usr/local/apr
--with-apr-util=/usr/local/apr-util
--with-pcre=/usr/local/pcre
--enable-so
$ sudo make
$ sudo make install
六、設定apache帳號 for Web server
說明:請輸入以下指令
$ sudo groupadd apache
$ sudo useradd -s /sbin/nologin -g apache apache
七、設定 ServerName 及 web server 所使用的帳號
至 /usr/local/apache2/conf/httpd.conf 中,找到下面的部分,並將User及Group皆改成「apache」;再來搜尋ServerName,會看到註解後的文字,可於下方空白處(或直接拿掉註解),輸入ServerName 192.168.56.100(請自行輸入先前所設定對外開啟服務用的IP),而後再輸入「sudo /usr/local/apache2/bin/apachectl restart」來重新啟動Apache Web Server。若開啟成功,在瀏覽器網址列上輸入IP,便會出現「It works!」。
圖六 將User與Group從daemon改成apache
圖七 由於沒有domain name,因此輸入對外開啟服務用的IP
八、Apache 的預設網頁根目錄
預設網頁根目錄路徑為 /usr/local/apache2/htdocs,之後我們必須要將撰寫的程式和相關檔案,放至該路徑底下。
安裝 H264 串流模組
下載指令:sudo wget http://h264.code-shop.com/download/apache_mod_h264_streaming-2.2.7.tar.gz
說明:解壓縮後,進入該資料夾,請輸入以下安裝指令
$ sudo ./configure
--prefix=/usr/local/apache2/modules/
--with-apxs=/usr/local/apache2/bin/apxs
圖八 可指/usr/local/apache2/modules查看是否有h264的模組
再到 httpd.conf 當中,尋找 LoadModule,在當中或相關設定後面,加上「LoadModule h264_streaming_module /usr/local/apache2/modules/mod_h264_streaming.so」
圖九 讓apache讀取H264模組
另外再到 <IfModule mime_module> 裡面,加入以下資料:
AddType video/mp4 .mp4 .m4v .f4v .f4p
AddHandler h264-streaming.extensions .mp4
圖十 加入H264相關參數與資訊
安裝 FFmpeg
以下安裝過程與參數,是筆者個人為了轉換「影」與「音」所自訂的設定;若是對FFmpeg不甚了解,可以參考筆者設定:
一、先更新所有套件
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get dist-upgrade
二、安裝 git、subversion套件
$ sudo apt-get install git subversion
三、安裝 build-essential nasm pkg-config套件
$ sudo apt-get install build-essential nasm pkg-config
四、安裝 yasm
說明:稍候安裝 x264(mp4影像編碼格式)需要 yasm 組譯器
$ sudo apt-get remove yasm
$ sudo wget http://www.tortall.net/projects/yasm/releases/yasm-1.2.0.tar.gz
$ sudo tar -zxvf yasm-1.2.0.tar.gz
$ cd yasm-1.2.0
$ sudo ./configure --prefix=/usr/local
$ sudo make
$ sudo make install
$ yasm --version(這指令是作 yasm 版本查詢)
五、下載 ffmpeg
$ sudo git clone git://source.ffmpeg.org/ffmpeg.git ffmpeg
六、安裝 AAC, MP3, Theora, Vorbis, AMR, GSM 套件
說明:AAC, MP3, Theora, Vorbis, AMR, GSM 是影音轉檔會用到的編碼格式
$ sudo apt-get install
libfaac-dev
libmp3lame-dev
libtheora-dev
libopencore-amrnb-dev
libopencore-amrwb-dev
libgsm1-dev
zlib1g-dev
libgpac-dev
七、安裝 libx264
$ sudo git clone git://git.videolan.org/x264.git
$ cd x264
$ sudo./configure --prefix=/usr/local --enable-shared –enable-static
$ sudo make
$ sudo make install
八、安裝 libxvid
$ sudo wget http://downloads.xvid.org/downloads/xvidcore-1.3.2.tar.gz
$ sudo tar -zxvf xvidcore-1.3.2.tar.gz
$ cd xvidcore-1.3.2/build/generic
$ sudo ./configure --prefix=/usr/local
$ sudo make
$ sudo make install
九、安裝 libvpx
$ sudo wget https://webm.googlecode.com/files/libvpx-v1.3.0.tar.bz2
$ sudo tar -jxvf libvpx-v1.3.0.tar.bz2
$ cd libvpx-v1.3.0
$ sudo ./configure --prefix=/usr/local --enable-vp8 --enable-vp9 --enable-shared
$ sudo make
$ sudo make install
十、安裝 libvorbis
$ sudo wget http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.4.tar.gz
$ sudo tar -zxvf libvorbis-1.3.4.tar.gz
$ cd libvorbis-1.3.4
$ sudo ./configure --prefix=/usr/local --enable-shared –enable-static
$ sudo make
$ sudo make install
十一、安裝 ffmpeg 與相關參數
$ cd /usr/local/src/ffmpeg
$ sudo ./configure
--prefix=/usr/local
--enable-gpl
--enable-version3
--enable-nonfree
--enable-libopencore-amrnb
--enable-libopencore-amrwb
--enable-libfaac
--enable-libgsm
--enable-libmp3lame
--enable-libtheora
--enable-libx264
--enable-libxvid
--enable-libvpx
--enable-libvorbis
--enable-pthreads
--enable-shared
--enable-static
$ sudo make
$ sudo make install
$ sudo ldconfig –v(請務必輸入該指令)
將影片轉成h264 streamiong模組可用的mp4格式
首先,我們要準備一部 mp4 格式的影片;若無,則需要透過以下實驗指令來進行影片轉檔(若讀者對ffmpeg已有一定了解,請以自身經驗實作),將其轉成 mp4 格式,以方便串流模組使用:
$ ffmpeg –i [來源影片名稱.副檔名]
-s 640x480 (寬x高)
-vcodec libx264 (影片編碼格式)
-quality good (品質:good;另有best可選擇)
-cpu-used 5 (0~5,值愈低,cpu使用愈多,可產生愈佳品質)
-threads 4 (欲使用cpu核心數)
result.mp4(轉換影音所產出的檔案)
確認影片長度
我們可以透過Linux指令,來確認影片的長度,稍候可以讓程式方便計算時間間距:「ffmpeg –i 影片名稱.副檔名 2>&1 | grep Duration | cut –d ‘ ‘ –f 4 | sed s/,//」。在本測試影片的時間長度為 00:00:48.90(時:分:秒),約略為48秒。
圖十一 找出影片的時間總長(持續時間)
確認Apache mod h264 streaming是否有作用
Apache h264 模組的特色之一,即是在影片連結的後方,加入「?start=開始時間&end=結束時間」,讓播放器知道影片播放的始終,例如在網址列輸入「http://(你對外服務的IP)/result.mp4?start=5&end=10」,時間間距5秒,若播出影片總長為5秒,即為正確結果。
圖十二 測試影片是否僅播放自訂的時間間距
自訂播放器格式
準備好前面所要安裝、建置的所有機制,我們將自訂播放器格式,分別有HTML5 的Video元素,以及jQuery UI的slider功能,還有幾個「播放、暫停、停止」的按鈕。筆者將在隨後分享程式碼給大家,希望大家多多測試與利用。
圖十三 影片播放器格式
原始碼分享
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HTML5 Video API 與 Apache mod h264 streaming 的簡易串流技巧</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script> <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<style>
<!--
/* 播放器 - 外觀初始設定 */
video{
width: 100%;
max-width: 640px;
}
/* 播放器 - 時間軸 */
div#slider{
margin: 0 auto;
padding: 0;
display: inline-block;
width: 100%;
max-width: 502px;
}
-->
</style>
<script>
$(document).ready(function(){
//隨機給影片編號
var sn = 1;
//放置切割時間點用的陣列
var arr_divide_time = new Array();
//放置間距時間用的陣列
var arr_interval_time = new Array();
//影片元素
var video = $("video");
//時間軸元素
var slider = $("#slider");
//影片來源
var path_mp4 = "http://192.168.56.100/result.mp4";
//影片時間總長
var duration = 48.9;
//切割成幾份
var divide = 5;
//將切割時間分成若干個有顏色的時間軸區塊
for(var b = 0; b < divide; b++)
{
slider.append("<div class='slider_color_" + sn + "'></div>");
}
//將每個時間軸區塊設定等份(百分比)
var percentage = 100 / divide;
//設定時間軸等份的 CSS 屬性/值,讓他們顏色相間
var slider_color = $(".slider_color_" + sn);
slider_color.filter(":even").css({
"display":"inline-block",
"background-color": "yellow",
"width": percentage + "%",
"height":"100%",
"float":"left"
});
slider_color.filter(":odd").css({
"display":"inline-block",
"background-color": "orange",
"width": percentage + ""%,
"height":"100%",
"float":"left"
});
//每一等份是多少
var seg = duration / divide ;
//初始化資料存放
arr_divide_time[sn] = new Array();
arr_interval_time[sn] = new Array();
//分割用字串
var str = "";
//分割字串後的陣列
var split;
//儲存每一個切割影片的時間間距 e.g. 0-9, 10-19, 20-29 ... etc
for(var t = 1; t <= divide; t++)
{
arr_divide_time[sn][t] = seg * t;
if( t == 1 )
{
arr_interval_time[sn][t] = "0-" + arr_divide_time[sn][t];
}
else
{
arr_interval_time[sn][t] = arr_divide_time[sn][t-1] + "-" + arr_divide_time[sn][t];
}
}
//讓陣列變數產生初始值,以便計算時間距間
arr_divide_time[sn][0] = 0;
//放置初始 source 元素
str = arr_interval_time[sn][1];
split = str.split("-");
video.prepend('<source src="' + path_mp4 + '?start=' + split[0] + '&end=' + split[1] + '" type="video/mp4">');
//計算 slider 與 video progress 時間用
var g = 1;
//讓 slider 可以控制 video 的時間軸
slider.slider({
range: "min",
min: 0,
max: parseInt( duration, 10 ),
value: 0,
slide: function(event_slide, ui_slide){
//當滑動 slider 時,檢查當前需要播放的區段代號
for(var gg = 1; gg <= divide; gg++)
{
if( parseFloat(arr_divide_time[sn][gg]) > parseFloat( ui_slide.value ) &&parseFloat( ui_slide.value ) >= parseFloat(arr_divide_time[sn][gg-1]) )
{
g = gg;
}
}
},
start: function(event_start, ui_start){
video[0].pause();
},
stop: function(event_stop, ui_stop){
str = arr_interval_time[sn][g];
split = str.split("-");
video.children("source").eq(0).attr("src", path_mp4 + '?start=' + split[0] + '&end=' + split[1]);
video[0].load();
video[0].play();
//目前時間 - 目前距間的開始時間 = 該段影片的當前播放時間
video[0].currentTime = parseInt( parseFloat( ui_stop.value ) - parseFloat( split[0] ) );
}
});
//播放器播放時,時間進度會跟 slider 同步移動
video[0].addEventListener("timeupdate", function(){
slider.slider('value', parseFloat(video[0].currentTime) + parseFloat(arr_divide_time[sn][g-1]));
});
//若是當現影片區間播放完了,自動跳下一個區間
video[0].addEventListener("ended", function(){
g++;
video[0].pause();
str = arr_interval_time[sn][g];
split = str.split("-");
video.children("source").eq(0).attr("src", path_mp4 + '?start=' + split[0] + '&end=' + split[1]);
video[0].load();
video[0].play();
});
//按下播放鈕
$("#btn_start").on("click", function(){
video[0].play();
});
//按下暫停鈕
$("#btn_pause").on("click", function(){
video[0].pause();
});
//按下停止鈕
$("#btn_stop").on("click", function(){
str = arr_interval_time[sn][1];
split = str.split("-");
video.children("source").eq(0).attr("src", path_mp4 + '?start=' + split[0] + '&end=' + split[1]);
g = 1;
slider.slider('value', 0);
video[0].load();
});
});
</script>
</head>
<body>
<video preload="auto">
<!-- 都不支援,可能是瀏覽器版本老舊,要請使用者更新 -->
<p>Your user agent does not support the HTML5 Video element.</p>
</video>
<br />
<div id="slider"></div>
<div>
<input type="button" id="btn_start" value="播放" />
<input type="button" id="btn_pause" value="暫停" />
<input type="button" id="btn_stop" value="停止" />
</div>
</body>
</html>
|
後記
HTML5 Video元素的影音來源下載,是以HTTP Code 206(Partial Content)作為基礎,簡而言之,即是使用類似續傳軟體的手法,來達到檔案下載的目的。我們利用這項特點,將影片時間進行區隔,讓Video元素在抓取檔案時,僅能在特定區間內(例如第5秒至第14秒)進行下載,而不會浪費多餘的頻寬,對未來不確定是否會觀看的影片片段進行緩衝與抓取,如此一來便能達到串流的目的,並能有效地節省網路資源。
參考資料
[1] Ubuntu Download
http://www.ubuntu-tw.org/modules/tinyd0/
[2] Apache Web Server
http://httpd.apache.org/
[3] H264 Streaming Module for Apache
http://h264.code-shop.com/trac/wiki/Mod-H264-Streaming-Apache-Version2
[4] FFmpeg
https://www.ffmpeg.org/
[5] jQuery user interface - Slider
https://jqueryui.com/slider/
[6] HTML Audio/Video DOM Reference(查詢API)
http://www.w3schools.com/tags/ref_av_dom.asp