Table of Contents |
---|
...
Описание
Данный плеер пример демонстрирует возможности WCS по преобразованию опубликованного на сервере потока в HLS и воспроизведению его в браузере при помощи библиотеки VideoJS. Нарезка потока в HLS запускается автоматически, при обращении к потоку, опубликованному на сервере, по HLS URL, например, для потока на рисунке скриншоте ниже http`https://localhost:8082test1.flashphoner.com:8445/test/test.m3u8.m3u8`
Пример также позволяет выбрать версию VideoJS для проигрывания. Версия 8, в отличие от версии 7, поддерживает Low Latency HLS, если сервер отдает поток в этом формате
Код примера
Код данного примера находится на сервере по следующему пути:
...
hls-player.css - файл стилей страницы с плеером
video-js.css - файл стилей HLS-плеера
hls-player.html - страница с плеером
hls-player.js - скрипт, обеспечивающий запуск плеера
player-page.html - общие элементы страницы плеера для трех примеров воспроизведения HLS
В подкаталогах videojs7 и videojs8 находятся, соответственно, две версии VideoJS:
video.js - скрипт, обеспечивающий работу плеера (http://videojs.com/, Apache License Version 2.0)
videojs-hlsvideo.min.js - скрипт, обеспечивающий работу плеера (минимизированная версия)
video-js.css - файл стилей HLS-плеера
Тестировать данный пример можно по следующему адресу:
https://host:88888444/client2/examples/demo/streaming/hls-player/hls-player.html
...
Для разбора кода возьмем версию файла hls-player.js с хешем ecbadc332144d9, которая находится здесь и доступна для скачивания в соответствующей сборке 2.0.212243.
1. Определение HLS URL сервераgetHLSUrl() Загрузка страницы плеера
Code Block | ||||
---|---|---|---|---|
| ||||
const loadPlayerPage = function() {
if (videojsVersion) {
hideItem("videojsInputForm");
loadVideoJS("videojs" + videojsVersion);
} else {
let videojsInput = document.getElementById("videojsInput");
for (videojsType in VIDEOJS_VERSION_TYPE) {
let option = document.createElement("option");
let videojsFolder = "";
switch (videojsType) {
case 'VIDEOJS7':
videojsFolder = VIDEOJS_VERSION_TYPE.VIDEOJS7;
break;
case 'VIDEOJS8':
videojsFolder = VIDEOJS_VERSION_TYPE.VIDEOJS8;
break;
}
option.text = videojsFolder;
option.value = videojsFolder;
videojsInput.appendChild(option);
}
setHandler("videojsBtn", "click", onVideojsBtnClick);
}
} |
2. Загрузка выбранной версии VideoJS
Code Block | ||||
---|---|---|---|---|
| ||||
const loadVideoJS = function initPage( (version) { if (version) { let playerPage = $document.getElementById("#headerplayerPage"); loadFile(version + "/video.js", "text/javascript").then( data => { console.log("HLS VideoJSlibrary Playerloaded Minimalsuccessfully", data); $("#urlServer").val(getHLSUrl()); ... } |
2. Инициализация плеера
videojs() code
...
loadFile(version + "/video-js.css", "stylesheet").then ( data => {
console.log("HLS library stylesheet loaded successfully", data);
hideItem("videojsInputForm");
loadPage("player-page.html", "playerPage", initPage );
}).catch( err => {
playerPage.innerHTML = "Can't load VideoJS library stylesheet";
playerPage.setAttribute("class", "text-danger");
console.error(err);
})
}).catch( err => {
setText("videojsError", "Can't load VideoJS library");
console.error(err);
});
}
} |
3. Инициализация HTML-страницы плеера
Code Block | ||||
---|---|---|---|---|
| ||||
functionconst initPage = function() { setText("header", "HLS VideoJS Player Minimal"); setValue("urlServer", getHLSUrl()); enableItem("applyBtn"); setText("applyBtn", "Play"); setHandler("applyBtn", "click", playBtnClick); setHandler("backBtn10", "click", backBtnClick); setHandler("backBtn30", "click", backBtnClick); setHandler("backBtnMax", "click", backBtnClick); setHandler("liveBtn", ..."click", liveBtnClick); varlet remoteVideo = document.getElementById('remoteVideo'); remoteVideo.className = "video-js vjs-default-skin"; player = initVideoJsPlayer(remoteVideo); playbackStats = PlaybackStats(STATS_INTERVAL); } |
4. Инициализация плеера
videojs() code
Плееру передаются следующие параметры:
- video - div-элемент, в котором должен быть проигран поток
- playsinline: true - проигрывать видео на странице, не переключаясь в полноэкранный режим (игнорируется в iOS Safari)
- playbackRates - список скоростей воспроизведения
- liveui: true - включает интерфейс для перемотки (DVR)
- liveTracker - настройка границы проигрывания живого потока
Code Block | ||||
---|---|---|---|---|
| ||||
const initVideoJsPlayer = function(video) { let videoJsPlayer = videojs(video, { playsinline: true, playbackRates: [0.1, 0.25, 0.5, 1, 1.5, 2], liveui: true, liveTracker: { trackingThreshold: LIVE_THRESHOLD, liveTolerance: LIVE_TOLERANCE }, fill: true }); console.log("Using VideoJs " + videojs(remoteVideo).VERSION); if (Browser.isSafariWebRTC() && Browser.isiOS()) { // iOS hack when using standard controls to leave fullscreen mode let videoTag = getActualVideoTag(); if(videoTag) { setWebkitFullscreenHandlers(videoTag, false); } } return videoJsPlayer; } |
35. Определение имени потока (должен быть опубликован на сервере)
encodeURIComponent() code
Code Block | ||||
---|---|---|---|---|
| ||||
function playBtnClick() { if (validateForm()) { varlet streamName = $getValue('#playStreamplayStream').val(); streamName = encodeURIComponent(streamName); ... } } |
46. Формирование URL HLS-потока и запуск плеера
player.play() code
Если указаны ключ и токен авторизации, они будут включены в URL потока
Code Block | ||||
---|---|---|---|---|
| ||||
functionconst playBtnClick = function() { if (validateForm()) { ... varlet videoSrc = $getValue("#urlServerurlServer").val() + '/' + streamName + '/' + streamName + '.m3u8'; varlet key = $getValue('#keykey').val(); varlet token = $getValue("#tokentoken").val(); if (key.length > 0 && token.length > 0) { videoSrc += "?" + key + "=" + token; } player.on('loadedmetadata', function() { console.log("Play with VideoJs"); player.play(); }); ... player.src({ src: videoSrc, type: "application/vnd.apple.mpegurl" }); onStarted(); } } |
7. Обработка события playing
player.on() code
Code Block | ||||
---|---|---|---|---|
| ||||
const playBtnClick = function() { if (validateForm()) { ... player.on('playing', function() { console.log("Play with VideoJs");"playing event fired"); if (player.liveTracker) { if (!player.liveTracker.isLive()) { // A cratch to display live UI for the first subscriber liveUIDisplay(); } if (player.liveTracker.atLiveEdge()) { // Unlock backward buttons when seeked to live edge toggleBackButtons(true); // Stop live UI startup timer stopLiveUITimer(); } } }); ... } } |
8. Включение интерфейса перемотки (DVR) для первого подписчика
player.liveTracker.seekToLiveEdge() code
Code Block | ||||
---|---|---|---|---|
| ||||
const liveUIDisplay = function() {
stopLiveUITimer()
if (player && player.liveTracker) {
liveUITimer = setInterval(function() {
if (!player.liveTracker.isLive() && player.liveTracker.liveWindow() > LIVE_THRESHOLD) {
// Live UI is not displayed yet, seek to live edge to display
player.liveTracker.seekToLiveEdge();
}
}, LIVE_UI_INTERVAL)
}
} |
9. Действия по нажатию на кнопку перемотки назад
player.seekable(), player.currentTime() code
Code Block | ||||
---|---|---|---|---|
| ||||
const backBtnClick = function(event) {
if (player != null && player.liveTracker) {
toggleBackButtons(false);
let seekable = player.seekable();
let backTime = -1;
if (event.target.id.indexOf("10") !== -1) {
backTime = player.currentTime() - 10;
} else if (event.target.id.indexOf("30") !== -1) {
backTime = player.currentTime() - 30;
}
if (backTime < 0) {
backTime = seekable ? seekable.start(0) : player.currentTime();
}
player.currentTime(backTime);
}
} |
11. Действия по нажатию на кнопку Live
player.liveTracker.seekToLiveEdge() code
Code Block | ||||
---|---|---|---|---|
| ||||
const liveBtnClick = function() { if (player != null && player.liveTracker) { player.liveTracker.playseekToLiveEdge(); onStartedtoggleBackButtons(true); } } |
512. Остановка воспроизведения
player.dispose() code
Этот метод удаляет со страницы div элемент, в котором был ранее инициализирован плеер
Code Block | ||||
---|---|---|---|---|
| ||||
functionconst stopBtnClick = function() { if (player != null) { console.log("Stop VideoJS player"); //player.pausestopLiveUITimer(); player.dispose(); } onStopped(); } |
613. Создание нового div элемента и плеера в нем после остановки предыдущего плеера
Code Block | ||||
---|---|---|---|---|
| ||||
functionconst createRemoteVideo = function(parent) { let remoteVideo = document.createElement("video"); remoteVideo.id = "remoteVideo"; remoteVideo.width=852; remoteVideo.height=480; remoteVideo.controls="controls"; remoteVideo.autoplay="autoplay"; remoteVideo.type="application/vnd.apple.mpegurl"; remoteVideo.className = "video-js vjs-default-skin"; remoteVideo.setAttribute("playsinline",""); remoteVideo.setAttribute("webkit-playsinline",""); parent.appendChild(remoteVideo); player = videojsinitVideoJsPlayer(remoteVideo); } |