Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

...

Описание

Данный плеер пример демонстрирует возможности WCS по преобразованию опубликованного на сервере потока в HLS и воспроизведению его в браузере при помощи библиотеки VideoJS. Нарезка потока в HLS запускается автоматически, при обращении к потоку, опубликованному на сервере, по HLS URL, например, для потока на рисунке скриншоте ниже http`https://localhost:8082test1.flashphoner.com:8445/test/test.m3u8Image Removed.m3u8`

Пример также позволяет выбрать версию VideoJS для проигрывания. Версия 8, в отличие от версии 7, поддерживает Low Latency HLS, если сервер отдает поток в этом формате

Image Added

Image Added

Код примера

Код данного примера находится на сервере по следующему пути:

...

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

Code Block
languagejs
themeRDark
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

Code Block
languagejs
themeRDark
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

Code Block
languagejs
themeRDark
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
languagejs
themeRDark
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
languagejs
themeRDark
function playBtnClick() {
    if (validateForm()) {
           varlet streamName = $getValue('#playStreamplayStream').val();
           streamName = encodeURIComponent(streamName);
        ...
    }
}

46. Формирование URL HLS-потока и запуск плеера

player.play() code

Если указаны ключ и токен авторизации, они будут включены в URL потока

Code Block
languagejs
themeRDark
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
languagejs
themeRDark
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
languagejs
themeRDark
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
languagejs
themeRDark
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
languagejs
themeRDark
const liveBtnClick = function() {
    if (player != null && player.liveTracker) {
        player.liveTracker.playseekToLiveEdge();
        onStartedtoggleBackButtons(true);
    }
}

512. Остановка воспроизведения

player.dispose() code

Этот метод удаляет со страницы div элемент, в котором был ранее инициализирован плеер

Code Block
languagejs
themeRDark
functionconst stopBtnClick = function() {
    if (player != null) {
        console.log("Stop VideoJS player");
        //player.pausestopLiveUITimer();
        player.dispose();
    }
    onStopped();
}

613. Создание нового div элемента и плеера в нем после остановки предыдущего плеера

code

Code Block
languagejs
themeRDark
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);
}