1. 程式人生 > >HTML5 視訊播放器 最全API

HTML5 視訊播放器 最全API

轉載地址:https://segmentfault.com/a/1190000000380064

前段時間重新學習了一下html5的video部分,以前只是停留在標籤的使用上,這一次決定深入瞭解相關的API,並運用這些API打造一個簡單的視訊播放器。所謂“打造自己的”,就是要自己重寫video標籤的控制欄部分,實現包括播放、暫停、進度和音量控制、全屏等功能,並自定義控制欄的樣式。

下面我將逐步講解打造自己的html5視訊播放器的過程:

一、自定義控制欄涉及到的主要API

1、video播放相關API

只讀屬性: 
video.duration:整個媒體檔案的播放時長,單位s 
video.paused :如果媒體檔案被暫停,則返回true;如果還沒開始播放,預設返回true 
video.ended :如果媒體檔案播放完畢,則返回true

可寫屬性: 
video.currentTime:以s為單位返回從開始播放到現在所用的時間。在播放過程中,設定currentTime來進行搜尋,並定位到媒體檔案的特定位置 
video.volume :在0.0到1.0之間設定音訊音量的相對值,或者查詢當前音量相對值 
video.muted :檢測當前是否為靜音,是則為true;為檔案設定靜音或消除靜音

控制函式: 
video.play() :播放視訊檔案 
video.pause() :暫停處於播放狀態的視訊檔案 
video.canPlayType() :測試video元素是否支援給定MIME型別的檔案

監聽事件: 
ontimeupdate :當video.currentTime發生改變時觸發該事件

2、全屏控制API 
說明:這裡只給出webkit的全屏API,本程式碼沒有做相容性處理,主要應用了webkit的一些高階API和chrome的偽元素,所以前面請大家用chrome開啟演示地址。

video.webkitRequestFullScreen():全屏顯示 
document.webkitCancelFullScreen():退出全屏 
document.webkitIsFullScreen:如果當前處於全屏狀態,則返回true,否則返回false 
document.addEventListener('webkitfullscreenchange', handler):當在全屏和非全屏狀態切換時,觸發該事件

3、本地檔案讀取API 
說明:我的這個視訊播放器支援從本地新增視訊檔案播放,支援的格式在webkit瀏覽器支援的html5視訊播放標準範圍內。本地檔案讀取API是html5的新標準。

window.URL.createObjectURL(file):file為檔案物件,該函式返回指向檔案的物件URL,通過該URL可以訪問檔案。

video.src = window.URL.createObjectURL(file);

二、視訊播放器控制欄的樣式實現

為了圖方便,佈局上我使用 pure 來幫忙,一個很簡潔的css框架,其實也沒用到它多少。至於那些控制按鈕,藉助css3的@font-face,我使用icon-font來實現。

icon-font其實就是所謂的圖示字型,將設計好的svg格式圖片匯入相關平臺,生成字型檔案或者base64的編碼字串,然後在頁面中引用這些自定義的字型檔案或者插入base64編碼字串。

這裡給大家推薦一個不錯的平臺,IcoMoon,藉助該平臺的IcoMoon App,可以方面的完成上述操作。而且該平臺還提供了不少優秀的字型庫,我使用的就是現有的。對於不怎麼會做設計又不想花時間找圖片的童鞋來說,這是個不錯的選擇。其實icon-font主要還是用來減小請求檔案大小的。

三、video元素的初始化工作

video元素的html結構:

<video id="player" width="600" height="450">您的瀏覽器不支援HTML5
    <source src="./videos/echo-hereweare.mp4"></source>  <!-- 提供預設的播放視訊  -->
</video>

video元素的js初始化:

var $player = $('#player');
var player = $player[0];  //方便使用dom原生的api

四、控制欄上各個控制器的功能實現

1、播放、暫停和停止 
html:

<span id="play" class="icon icon-play"></span>
<span id="stop" class="icon icon-stop"></span>

javascript:

$play
    .on('click', function() {
        if (player.paused) {
            player.play(); //播放
            $(this).removeClass('icon-play').addClass('icon-pause');
        } else {
            player.pause(); //暫停
            $(this).removeClass('icon-pause').addClass('icon-play');
        }
    });

$stop
    .on('click', function() {
        player.currentTime = 0; //停止播放
        $innerBar.css('width', 0 + 'px');
    });

2、播放進度控制條和播放時間顯示 
1)播放進度控制條: 
這一部分要實現兩個功能,一個是點選控制條上的某一點,視訊能跳轉到對應的時間點;另一個是點選後控制條要有相應的顯示(反饋),表明當前位置。 
html:

<div id="progressBar" class="controlBar">
    <div id="innerBar" class="controlInner"></div>
</div>

javascript:

$progressBar
    .on('click', function(e) {
        var w = $(this).width(),
            x = e.offsetX;
        window.per = (x / w).toFixed(3); //全域性變數

        var duration = player.duration;
        player.currentTime = (duration * window.per).toFixed(0);

        $innerBar.css('width', x + 'px'); //反饋
    });

進度控制條的實現部分,要用到一個很關鍵的屬性:e.offsetX,在firefox裡無此屬性,但有一個類似的e.layerX,具體可以查閱MDN。e.offsetX表示滑鼠指標的位置相對於觸發事件的物件的X座標,知道了這個值和進度條的寬度,就可以計算出當前點選位置的百分比了,然後就可以根據百分比來重新設定video的currentTime,實現進度控制。

注意:這裡之所以要引入一個全域性變數window.per來記錄當前播放的進度百分比,是因為在切換到全屏後,控制條的長度會變長,退出全屏後,控制條的長度又會變短,所以對應的內層進度條(用於顯示進度的)的長度也要隨之變化,在之後講實現全屏/非全屏切換時會具體說明。此外,因為在播放過程中這個百分比是變化的,所以也要不斷更新window.per這個全域性變數: 
javascript:

$player
    .on('timeupdate', function() {
        // ... (表示省略的程式碼)
        var w = $progressBar.width();
        if (player.duration) {
            var per = (player.currentTime / player.duration).toFixed(3);
            window.per = per;
        } else {
            per = 0;
        }
        $innerBar.css('width', (w * per).toFixed(0) + 'px');
        // ...
    });

2)播放時間顯示 
這個就比較簡單了,主要是一個時間換算,還是利用上面的timeupdate事件 
html:

<span id="timer">0:00</span>

javascript:

$player
    .on('timeupdate', function() {
        //秒數轉換
        var time = player.currentTime.toFixed(1),
            minutes = Math.floor((time / 60) % 60),
            seconds = Math.floor(time % 60);

        if (seconds < 10) {
            seconds = '0' + seconds;
        }
        $timer.text(minutes + ':' + seconds);

        // ... (更新控制條部分)

        if (player.ended) { //播放完畢
            $play.removeClass('icon-pause').addClass('icon-play'); 
        }
    });

注意:播放完畢後,記得將播放按鈕的圖示重置為播放狀態

3、音量控制 
1)靜音與取消靜音 
html:

<span id="volume" class="icon icon-volume"></span>

javascript:

$volume
    .on('click', function() {
        if (player.muted) {
            player.muted = false;
            $(this).removeClass('icon-volume-mute').addClass('icon-volume');
            $volumeInner.css('width', 100 + '%'); //音量控制條回滿血
        } else {
            player.muted = true;
            $(this).removeClass('icon-volume').addClass('icon-volume-mute');
            $volumeInner.css('width', 0);
        }
    });

2)音量控制條 
音量控制條和播放進度控制條其實是一樣的,唯一不同的是這裡我們改變的是video.volume的值。 
html:

<div id="volume-control" class="controlBar">
    <div id="volume-inner" class="controlInner"></div>
</div>

javascript:

$volumeControl
    .on('click', function(e) {
        var w = $(this).width(),
            x = e.offsetX;
        window.vol = (x / w).toFixed(1); //全域性變數

        player.volume = window.vol;
        $volumeInner.css('width', x + 'px');
    });

這裡設定全域性變數的理由同上。

4、檔案上傳按鈕 
這裡要做兩件事,一件是上傳檔案並生成物件URL,另一件是在上傳前判斷瀏覽器是否能播放該格式的檔案。由於瀏覽器支援的播放格式比較少,比較常見的就是mp4了,算是一個嘗試性功能吧。 
html:

<span id="upload" class="icon icon-upload"></span>
<!-- ... 省略程式碼 -->
<input type="file" id="file">

css:

#file {
    visibility: hidden;
}

javascript:

$upload
    .on('click', function() {
        $file.trigger('click');
    });

$file
    .on('change', function(e) {
        var file = e.target.files[0],
            canPlayType = player.canPlayType(file.type); //判斷是否支援該格式

        if (canPlayType === 'maybe' || canPlayType === 'probably') {
            src = window.URL.createObjectURL(file);
            player.src = src;
            $play.removeClass('icon-pause').addClass('icon-play'); //新開啟的視訊處於paused狀態
            player.onload = function() {
                window.URL.revokeObjectURL(src);
            };
        } else {
            alert("瀏覽器不支援您選擇的檔案格式");
        }
    });

注意:這裡為了完全自由定義上傳按鈕的樣式,用了一個小技巧,就是通過點選自定義的上傳按鈕來觸發真正的提交按鈕(input[type='file'])的點選事件,然後在css中隱藏真正的提交按鈕即可。關於檔案讀取的API,可以去MDN上詳細學習一下。

5、全屏/非全屏的切換及相關控制 
在全屏和非全屏之間切換,利用webkit的API很容易實現 
html:

<span id="expand" class="icon icon-expand"></span>

javascript:

$expand
    .on('click', function() {
        if (!document.webkitIsFullScreen) {
            player.webkitRequestFullScreen(); //全屏
            $(this).removeClass('icon-expand').addClass('icon-contract');
        } else {
            document.webkitCancelFullScreen();
            $(this).removeClass('icon-contract').addClass('icon-expand');
        }
    });

現在有兩個比較關鍵的問題,一是如何在全屏時隱藏video標籤預設的控制欄並顯示自己的控制欄;二是播放進度控制條和音量控制條顯示狀態的調整,這個在前面已經提到過了。

1)如何在全屏時隱藏video標籤預設的控制欄 
關於這個問題,我剛開始用中文搜了好久,都沒有找到相關內容,所以我嘗試著在google裡用"how to hide video controls in html5",結果出來的第三條就是我想要的,不得不感慨有些資源只能通過英語才能搜到。

2)在全屏/非全屏切換時更改控制進度條(內層進度條)的寬度 
javascript:

$(document)
    .on('webkitfullscreenchange', function(e) {
        var w = $progressBar.width(),
            w1 = $volumeControl.width();
        if (window.per) {
            $innerBar.css('width', (window.per * w).toFixed(0) + 'px');
        }
        if (window.vol) {
            $volumeInner.css('width', (window.vol * w1).toFixed(0) + 'px')
        }
    });

這裡前面定義的兩個全域性變數就派上用場了。