Versions Compared

Key

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

...

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

Код примера

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

/usr/local/FlashphonerWebCallServer/client2/examples/demo/streaming/hls-player

hls-player.css - файл стилей страницы с плеером
hls-player.html - страница с плеером
hls-player.js - скрипт, обеспечивающий запуск плеера
player-page.html - общие элементы страницы плеера для трех примеров воспроизведения HLS

В подкаталогах videojs7 и videojs8 находятся, соответственно, две версии VideoJS:

video.js - скрипт, обеспечивающий работу плеера (http://videojs.com/, Apache License Version 2.0)
video.min.js - скрипт, обеспечивающий работу плеера (минимизированная версия)
video-js.css - файл стилей HLS-плеера

Тестировать данный пример можно по следующему адресу:

https://hostНачиная со сборки 2.0.244, пример поддерживает следующие параметры:

  • version - используемая версия VideoJS: videojs7 или videojs8 
  • src - полный HLS URL потока для проигрывания, должен быть закодирован при помощи URI encode, например https%3A%2F%2Ftest1.flashphoner.com%3A8445%2Ftest%2Ftest.m3u8 
  • autoplay - автоматически запустить проигрывание указанного HLS URL, при этом все поля ввода и кнопки скрываются: false (по умолчанию) или true 

Пример открытия плеера с параметрами, как на скриншоте выше (ссылка в поле Permalink )

Code Block
themeRDark
https://test1.flashphoner.com:8444/client2/examples/demo/streaming/hls-player/hls-player.html?version=videojs7&src=https%3A%2F%2Ftest1.flashphoner.com%3A8445%2Ftest%2Ftest.m3u8

Пример вызова плеера с автозапуском

Code Block
themeRDark
https://test1.flashphoner.com:8444/client2/examples/demo/streaming/hls-player/hls-player.html

...

Здесь host - адрес вашего WCS-сервера.

Работа с кодом примера

Для разбора кода возьмем версию файла hls-player.js с хешем 32144d9, которая находится здесь и доступна для скачивания в соответствующей сборке 2.0.243.

1. Загрузка страницы плеера

code

Code Block
languagejs
themeRDark
const loadPlayerPage = function() {
    if (videojsVersion) {
?version=videojs7&src=https%3A%2F%2Ftest1.flashphoner.com%3A8445%2Ftest%2Ftest.m3u8&autoplay=true

При этом воспроизведение потока будет запущено автоматически, с отключенным звуком. Для включения звука зритель должен использовать кнопку регулятора громкости в интерфейсе плеера.

Код примера

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

/usr/local/FlashphonerWebCallServer/client2/examples/demo/streaming/hls-player

hls-player.css - файл стилей страницы с плеером
hls-player.html - страница с плеером
hls-player.js - скрипт, обеспечивающий запуск плеера
player-page.html - общие элементы страницы плеера для трех примеров воспроизведения HLS

В подкаталогах videojs7 и videojs8 находятся, соответственно, две версии VideoJS:

video.js - скрипт, обеспечивающий работу плеера (http://videojs.com/, Apache License Version 2.0)
video.min.js - скрипт, обеспечивающий работу плеера (минимизированная версия)
video-js.css - файл стилей HLS-плеера

Тестировать данный пример можно по следующему адресу:

https://host:8444/client2/examples/demo/streaming/hls-player/hls-player.html

Здесь host - адрес вашего WCS-сервера.

Работа с кодом примера

Для разбора кода возьмем версию файла hls-player.js с хешем 1703e13, которая находится здесь и доступна для скачивания в соответствующей сборке 2.0.244.

1. Загрузка страницы плеера

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;
                 hideItem("videojsInputForm")   break;
        loadVideoJS("videojs"  + videojsVersion);
    } else {case 'VIDEOJS8':
        let videojsInput = document.getElementById("videojsInput");
        for (videojsTypevideojsFolder in= VIDEOJS_VERSION_TYPE) {
.VIDEOJS8;
              let option = document.createElement("option");
   break;
         let videojsFolder = "";}
            switch (videojsType) {option.text = videojsFolder;
            option.value    case 'VIDEOJS7':= videojsFolder;
            videojsInput.appendChild(option);
        videojsFolder}

 = VIDEOJS_VERSION_TYPE.VIDEOJS7;
      setHandler("videojsBtn", "click", onVideojsBtnClick);
            break;}
}

2. Загрузка выбранной версии VideoJS

code

Code Block
languagejs
themeRDark
const loadVideoJS = function (version) {
    if (version) {
        let playerPage case 'VIDEOJS8':= document.getElementById("playerPage");
        loadFile(version + "/video.js",          videojsFolder = VIDEOJS_VERSION_TYPE.VIDEOJS8;"text/javascript").then( data  => {
            console.log("HLS library loaded successfully", data);
    break;
        loadFile(version + "/video-js.css",  }"stylesheet").then ( data => {
            option.text = videojsFolder;
   console.log("HLS library stylesheet loaded successfully", data);
    option.value = videojsFolder;
            videojsInput.appendChild(optionhideItem("videojsInputForm");
        }

        setHandlerloadPage("videojsBtnplayer-page.html", "clickplayerPage", onVideojsBtnClickinitPage );
      }
}

2. Загрузка выбранной версии VideoJS

code

Code Block
languagejs
themeRDark
const loadVideoJS = function (version) {
      }).catch( err => {
     if (version) {
        let playerPage.innerHTML = document.getElementById("playerPage")"Can't load VideoJS library stylesheet";
        loadFile(version + "/video.js        playerPage.setAttribute("class", "text/javascript-danger").then( data  => {;
            console.log("HLS library loaded successfully", data console.error(err);
            loadFile(version + "/video-js.css", "stylesheet").then ( data})
        }).catch( err => {
            setText("videojsError", "Can't load VideoJS console.log("HLS library stylesheet loaded successfully", datalibrary");
            console.error(err);
        });
    }
}

3. Инициализация HTML-страницы плеера

code

Code Block
languagejs
themeRDark
const initPage =  hideItemfunction("videojsInputForm"); {
    if (playSrc) {
          loadPagesetValue("player-page.htmlfullLink", "playerPage", initPage decodeURIComponent(playSrc));
    } else if (autoplay) {
    }).catch( err => {    console.warn("No HLS URL set, autoplay disabled");
        autoplay = false;
    }
  playerPage.innerHTML = "Can't load VideoJS library stylesheet"let remoteVideo = document.getElementById('remoteVideo');
    if (autoplay) {
        // There should  playerPage.setAttribute("class", "text-danger");
       not be any visible item on the page unless player
         console.errorhideAllToAutoplay(err);
        // The player should use })
all available page width
     }).catch( err => { setUpPlayerItem(true);
        // The player should  setText("videojsError", "Can't load VideoJS library");be muted to automatically start playback
        player =   console.error(errinitVideoJsPlayer(remoteVideo, true);
        }playBtnClick();
    }
}

3. Инициализация HTML-страницы плеера

code

Code Block
languagejs
themeRDark
const initPage = function() {
    setText("header", "HLS VideoJS Player Minimal");
    setValue("urlServer", getHLSUrl());
    enableItem("applyBtn");
 else {
        // No autoplay, all the forms and buttons should be visible
        setText("applyBtnheader", "Play");
HLS VideoJS   setHandler("applyBtn", "click", playBtnClickPlayer Minimal");
    setHandler("backBtn10", "click", backBtnClick    displayCommonItems();
     setHandler("backBtn30", "click", backBtnClick   setUpButtons();
    setHandler("backBtnMax", "click", backBtnClick    enablePlaybackStats();
        // The player  setHandler("liveBtn", "click", liveBtnClick);should have a maximum fixed size
    let  remoteVideo = document.getElementById('remoteVideo'setUpPlayerItem(false);
    remoteVideo.className = "video-js vjs-default-skin";
    player = initVideoJsPlayer(remoteVideo);
    // The player can be unmuted because user should click Play button
        playbackStatsplayer = PlaybackStats(STATS_INTERVAL);initVideoJsPlayer(remoteVideo, false);
    }
}

4. Инициализация плеера

videojs() code

Плееру передаются следующие параметры:

...

Code Block
languagejs
themeRDark
const initVideoJsPlayer = function(video) {
const initVideoJsPlayer = function(video, muted) {
    let videoJsPlayer = null;
    if (video) {
        video.className = "video-js vjs-default-skin";
        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
            },
            liveTolerancefill: LIVE_TOLERANCEtrue,
        },
    muted: muted
   fill: true
    });
        console.log("Using VideoJs " + videojs.VERSION);
        if (Browser.isSafariWebRTC() && Browser.isiOS()) {
            // iOS hack when using standard controls to leave fullscreen mode
        let videoTag = getActualVideoTag();
        if(videoTag) {
            setWebkitFullscreenHandlers(videoTag, false);
        }
let videoTag = getActualVideoTag();
       }
    return videoJsPlayer;
}

5. Определение имени потока (должен быть опубликован на сервере)

encodeURIComponent() code

Code Block
languagejs
themeRDark
function playBtnClick() {
 if(videoTag) {
      if (validateForm()) {
        let streamName = getValue('playStream');
        streamName = encodeURIComponent(streamName);setWebkitFullscreenHandlers(videoTag, false);
            }
        ...}
    }
    return videoJsPlayer;
}

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

encodeURIComponent() code

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

Code Block
languagejs
themeRDark
const playBtnClickgetVideoSrc = function(src) {
    let videoSrc = src;
    if (validateForm()) {
        let streamName = getValue(validateForm()) {
'playStream');
        streamName  ...= encodeURIComponent(streamName);
        let videoSrc = getValue("urlServer") + '/' + streamName + '/' + streamName + '.m3u8';
        let key = getValue('key');
        let token = getValue("token");
        if (key.length > 0 && token.length > 0) {length > 0) {
            videoSrc += "?" + key + "=" + token;
        }
    }
    setValue("fullLink", videoSrc);
    return videoSrc += "?" + key + "=" + token;
}

6. Запуск плеера

player.on(), player.play() code

Code Block
languagejs
themeRDark
const playBtnClick = function() {
    let videoSrc = getVideoSrc(getValue("fullLink"));
    if     }(videoSrc) {
        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() {
     let videoSrc if= getVideoSrc(validateFormgetValue("fullLink")) {
        ;
     if (videoSrc) {
         ...
        player.on('playing', function() {
            console.log("playing event fired");
            displayPermalink(videoSrc);
            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();
                }
            }
        });
        ...
    }
}

...

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)
    }
}

...

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);
    }
}

...

player.liveTracker.seekToLiveEdge() code

Code Block
languagejs
themeRDark
const liveBtnClick = function() {
    if (player != null && player.liveTracker) {
        player.liveTracker.seekToLiveEdge();
        toggleBackButtons(true);
    }
}

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

player.dispose() code

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

...

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

code

Code Block
languagejs
themeRDark
const createRemoteVideo = function(parent) {
    let remoteVideo = document.createElement("video");
    remoteVideo.id = "remoteVideo";
    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 = initVideoJsPlayer(remoteVideo, autoplay);
}

13. Получение доступной статистики воспроизведения из HTML5 video элемента

HTML5Stats code

Code Block
languagejs
themeRDark
const PlaybackStats = function(interval) {
    const playbackStats = {
        interval: interval || STATS_INTERVAL,
        timer: null,
        stats: null,
        start: function() {
            let video = getActualVideoTag();

            playbackStats.stop();
            stats = HTML5Stats(video);
            playbackStats.timer = setInterval(playbackStats.displayStats, playbackStats.interval);
            setText("videoWidth", "N/A");
            setText("videoHeight", "N/A");
            setText("videoRate", "N/A");
            setText("videoFps", "N/A");
            showItem("stats");
        },
        stop: function() {
            if (playbackStats.timer) {
                clearInterval(playbackStats.timer);
                playbackStats.timer = null;
            }
            playbackStats.stats = null;
            hideItem("stats");
        },
        displayStats: function() {
            if (stats.collect()) {
                let width = stats.getWidth();
                let height = stats.getHeight();
                let bitrate = stats.getBitrate();
                let fps = stats.getFps();

                setText("videoWidth", width);
                setText("videoHeight", height);

                if (bitrate !== undefined) {
                    setText("videoRate", Math.round(bitrate));
                }
                if (fps !== undefined) {
                    setText("videoFps", fps.toFixed(1));
                }
            }
        }
    };
    return playbackStats;
}