Skip to content

Commit

Permalink
Merge branch 'upstream_hls.js/master' into release
Browse files Browse the repository at this point in the history
* upstream_hls.js/master: (31 commits)
  Patch sauce connect test fixes
  Improve handling of bad AVC PTS
  Bump netlify-cli from 2.63.2 to 2.63.3
  Bump webpack from 4.44.1 to 4.44.2
  Bump netlify-cli from 2.62.0 to 2.63.2
  Bump eventemitter3 from 4.0.5 to 4.0.7
  Bump chromedriver from 84.0.1 to 85.0.1
  Bump @babel/preset-env from 7.11.0 to 7.11.5
  Bump @babel/core from 7.11.4 to 7.11.6
  Improve functional test results for trouble-shooting flakey tests
  Allow mp3 data that does not contain ID3 video-dev#3037
  Bump husky from 4.2.5 to 4.3.0
  Bump webpack-merge from 5.1.2 to 5.1.4
  [Security] Bump http-proxy from 1.17.0 to 1.18.1
  Set sauce job status after test run and on test failure
  Update optional functional test browser list
  Bump karma from 5.1.1 to 5.2.2
  Bump @babel/register from 7.10.5 to 7.11.5
  Bump mocha from 8.1.1 to 8.1.3
  Clean up browser version in test run name
  ...
  • Loading branch information
Rob Walch committed Sep 22, 2020
2 parents 7fb473f + b704a53 commit dd30675
Show file tree
Hide file tree
Showing 11 changed files with 1,356 additions and 957 deletions.
25 changes: 7 additions & 18 deletions .travis.yml
Expand Up @@ -6,10 +6,6 @@ sudo: required
# don't connect to sauce labs unless running functional tests
before_install: if [ "${TRAVIS_MODE}" != "funcTests" ]; then unset SAUCE_USERNAME && unset SAUCE_ACCESS_KEY; fi
script: ./scripts/travis.sh
after_script: if [ "${TRAVIS_MODE}" = "funcTests" ]; then echo -n "travis_fold:start:sauce_logs\nSauce connect log:\n" && cat /home/travis/sauce-connect.log && echo -n "\ntravis_fold:end:sauce_logs\n"; fi
env:
global:
- SAUCE_USERNAME=mangui
stages:
- buildAndTest
- releaseAlpha
Expand Down Expand Up @@ -52,25 +48,18 @@ jobs:
env: TRAVIS_MODE=funcTests UA=chrome OS="Windows 10"
# Optional Func tests
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA=firefox OS="Windows 10"
env: TRAVIS_MODE=funcTests UA=safari OS="OS X 10.15"
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA=chrome OS="Windows 7"
env: TRAVIS_MODE=funcTests UA=firefox OS="Windows 10"
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA=firefox OS="Windows 7"
env: TRAVIS_MODE=funcTests UA=chrome OS="OS X 10.11" UA_VERSION="79.0"
# - stage: testFuncOptional
# env: TRAVIS_MODE=funcTests UA=MicrosoftEdge OS="Windows 10"
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA="internet explorer" OS="Windows 8.1" UA_VERSION="11.0"
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA="internet explorer" OS="Windows 10"
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA=chrome OS="OS X 10.11"
# - stage: testFuncOptional
# env: TRAVIS_MODE=funcTests UA=firefox OS="OS X 10.11"
env: TRAVIS_MODE=funcTests UA="internet explorer" OS="Windows 8.1" UA_VERSION="11.0"
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA=chrome OS="Windows 7" UA_VERSION="69.0"
- stage: testFuncOptional
env: TRAVIS_MODE=funcTests UA=safari OS="OS X 10.12" UA_VERSION="10.1"
addons:
sauce_connect:
tunnel_domains: localhost
jwt:
secure: TxJT041jqRf4raCwtNJRb0rz2gGvEaADZjWO41UQND2+YIZ//S9qB2C4YyrL1BBsn8/ebdHr0cd18PwCzoBSEmoCdoAWXmqBaaLvM1DOeQkKJbU3+pFmWtv1qGqRXJLEAysNvzhG0sLdvBc0M7a/CWxqRfx1O3lGhLnTlAW33LlQndjJ8vh3SGQm8HxFR1503ujPd7V1jGwduVwaQp4zbAKTnQ4MLugmJf6UKiTc+YILMrVWOwipOIyYHh2GqbChd/v1PXff26XCNJXcaRZKJ8JosWyBpq5t4zlPO0qDfHpqbEuYK44xm4vzbZS94P/KF8BYzdtxQYLrxoS1UlnUYU7RmzqgL3y3AM7nzX/cXvJcoNXfUK2BpsB754XNyQfRmXOdRiHoC8+wwPqGkH/KCrmS4UIOqv4THfmDbrtewfcDTgKOzHxGcT1IsUq9BTxMNtxSwpHTHUXTXrzpS/UBDvrlc+9qPTqf+e6QL1aG+JT5sOg5REm2hMy0j18/Kr+HLXkehxEgJ6JrybyHUkkJrfcuWgVDu7Lv3cxlrtSMXi7TIwSB75NMoM8AE71GEVjXwpOw/0giwnmGsJNNi01ztod0UFe2V2rS+yPI1WNZIJ7Fw66U0oOKJ1rb4Iksl86n5Y2snHsxK8q5jhKaAaiWgGK5kVTAgF89t/GXYyNH6cI=
env: TRAVIS_MODE=funcTests UA=safari OS="OS X 10.12" UA_VERSION="10.1"
6 changes: 4 additions & 2 deletions README.md
Expand Up @@ -2,6 +2,7 @@
[![npm](https://img.shields.io/npm/v/hls.js.svg?style=flat)](https://npmjs.org/package/hls.js)
[![npm](https://img.shields.io/npm/v/hls.js/alpha.svg?style=flat)](https://www.npmjs.com/package/hls.js/v/alpha)
[![](https://data.jsdelivr.com/v1/package/npm/hls.js/badge?style=rounded)](https://www.jsdelivr.com/package/npm/hls.js)
[![Sauce Test Status](https://saucelabs.com/buildstatus/robwalch)](https://app.saucelabs.com/u/robwalch)

[![](https://www.netlify.com/img/global/badges/netlify-color-accent.svg)](https://www.netlify.com)

Expand Down Expand Up @@ -402,6 +403,7 @@ npm run test:func

Click [here](/docs/design.md) for details.

### Tested With
### Test Status

[<img src="https://cloud.githubusercontent.com/assets/7864462/12837037/452a17c6-cb73-11e5-9f39-fc96893bc9bf.png" alt="Browser Stack Logo" width="300">](https://www.browserstack.com/)
[![Sauce Test Status](https://saucelabs.com/browser-matrix/robwalch.svg)](https://saucelabs.com/u/robwalch)
[![Testing Powered By SauceLabs](https://opensource.saucelabs.com/images/opensauce/powered-by-saucelabs-badge-gray.png?sanitize=true "Testing Powered By SauceLabs")](https://saucelabs.com)
27 changes: 15 additions & 12 deletions demo/index.html
Expand Up @@ -71,24 +71,27 @@ <h3>
</label>

<label class="innerControls">
Player size:
HTML video element width:
<select id="videoSize" style="float:right;">
<option value="" selected>Set video width (height will vary according to selected size)</option>
<option value="240px">240 x 135</option>
<option value="426px">426 x 240</option>
<option value="640px">640 x 360</option>
<option value="720px">720 x 405</option>
<option value="854px">854 x 480</option>
<option value="1280px">1280 x 720</option>
<option value="1920px">1920 x 1080</option>
<option value="240px">240px</option>
<option value="426px">426px</option>
<option value="640px">640px</option>
<option value="720px">720px</option>
<option value="854px">854px</option>
<option value="1280px">1280px</option>
<option value="1920px">1920px</option>
<option value="80%">Responsive (80%)</option>
<option value="100%">Responsive (100%)</option>
</select>
</label>

<label class="innerControls">
Current video-resolution:
<span id="currentResolution">/</span>
Current player size:
<span id="currentSize"></span>
</label>
<label class="innerControls">
Current video resolution:
<span id="currentResolution"></span>
</label>

<label class="innerControls">
Expand All @@ -114,7 +117,7 @@ <h3>

</div>

<video id="video" controls autoplay class="videoCentered"></video>
<video id="video" controls autoplay class="videoCentered" style="width: 80%;"></video>
<br>
<canvas id="bufferedCanvas" width="720" height="15" class="videoCentered" onclick="onClickBufferedRange(event);" style="height: fit-content;"></canvas>
<br>
Expand Down
142 changes: 93 additions & 49 deletions demo/main.js
Expand Up @@ -36,7 +36,8 @@ let dumpfMP4 = getDemoConfigPropOrDefault('dumpfMP4', false);

let bufferingIdx = -1;
let selectedTestStream = null;
const video = $('#video')[0];

const video = document.querySelector('#video');
const startTime = Date.now();

let lastSeekingIdx;
Expand All @@ -52,6 +53,30 @@ let fmp4Data;
let configPersistenceEnabled = false;
let configEditor = null;
let chart;
let resizeAsyncCallbackId = -1;

const requestAnimationFrame = self.requestAnimationFrame || self.setTimeout;
const cancelAnimationFrame = self.cancelAnimationFrame || self.clearTimeout;
const resizeHandlers = [];
const resize = () => {
cancelAnimationFrame(resizeAsyncCallbackId);
resizeAsyncCallbackId = requestAnimationFrame(() => {
resizeHandlers.forEach(handler => {
handler();
});
});
};

self.onresize = resize;
if (self.screen && self.screen.orientation) {
self.screen.orientation.onchange = resize;
}

const playerResize = () => {
const bounds = video.getBoundingClientRect();
$('#currentSize').html(`${Math.round(bounds.width * 10) / 10} x ${Math.round(bounds.height * 10) / 10}`);
};
resizeHandlers.push(playerResize);

$(document).ready(function () {
setupConfigEditor();
Expand All @@ -63,10 +88,22 @@ $(document).ready(function () {
const option = new Option(stream.description, key);
$('#streamSelect').append(option);
if (stream.url === sourceURL) {
$('#streamSelect')[0].selectedIndex = index + 1;
document.querySelector('#streamSelect').selectedIndex = index + 1;
}
});

const videoWidth = video.style.width;
if (videoWidth) {
$('#videoSize option').each(function (i, option) {
if (option.value === videoWidth) {
document.querySelector('#videoSize').selectedIndex = i;
$('#bufferedCanvas').width(videoWidth);
resize();
return false;
}
});
}

$('#streamSelect').change(function () {
selectedTestStream = testStreams[$('#streamSelect').val()];
const streamUrl = selectedTestStream.url;
Expand All @@ -83,6 +120,7 @@ $(document).ready(function () {
$('#video').width($('#videoSize').val());
$('#bufferedCanvas').width($('#videoSize').val());
checkBuffer();
resize();
});

$('#enableStreaming').click(function () {
Expand Down Expand Up @@ -145,12 +183,16 @@ $(document).ready(function () {

$('.btn-dump').toggle(dumpfMP4);
$('#toggleButtons').show();
toggleTab($('.demo-tab-btn')[0]);
toggleTab(document.querySelector('.demo-tab-btn'));

$('#metricsButtonWindow').toggle(self.windowSliding);
$('#metricsButtonFixed').toggle(!self.windowSliding);

loadSelectedStream();

// Uncomment to show the second and third tabs under the first (Playback, Timeline, Quality-levels)
// toggleTab($('.demo-tab-btn')[1], true);
// toggleTab($('.demo-tab-btn')[2], true);
});

function setupGlobals () {
Expand Down Expand Up @@ -217,10 +259,7 @@ function loadSelectedStream () {

if (hls) {
hls.destroy();
if (hls.bufferTimer) {
clearInterval(hls.bufferTimer);
hls.bufferTimer = undefined;
}
clearInterval(hls.bufferTimer);
hls = null;
}

Expand Down Expand Up @@ -433,14 +472,15 @@ function loadSelectedStream () {
duration: data.frag.duration,
level: event.id
});
if (hls.bufferTimer === undefined) {
if (events.buffer.length === 0) {
events.buffer.push({
time: 0,
buffer: 0,
pos: 0
});
hls.bufferTimer = self.setInterval(checkBuffer, 100);
}
clearInterval(hls.bufferTimer);
hls.bufferTimer = self.setInterval(checkBuffer, 100);
trimEventHistory();
self.refreshCanvas();
updateLevelInfo();
Expand Down Expand Up @@ -594,15 +634,18 @@ function loadSelectedStream () {
break;
case Hls.ErrorDetails.LEVEL_EMPTY_ERROR:
logError('Loaded level contains no fragments ' + data.level + ' ' + data.url);
handleLevelError(data);
// handleLevelError demonstrates how to remove a level that errors followed by a downswitch
// handleLevelError(data);
break;
case Hls.ErrorDetails.LEVEL_LOAD_ERROR:
logError('Error while loading level playlist ' + data.context.level + ' ' + data.url);
handleLevelError(data);
// handleLevelError demonstrates how to remove a level that errors followed by a downswitch
// handleLevelError(data);
break;
case Hls.ErrorDetails.LEVEL_LOAD_TIMEOUT:
logError('Timeout while loading level playlist ' + data.context.level + ' ' + data.url);
handleLevelError(data);
// handleLevelError demonstrates how to remove a level that errors followed by a downswitch
// handleLevelError(data);
break;
case Hls.ErrorDetails.LEVEL_SWITCH_ERROR:
logError('Error while trying to switch to level ' + data.level);
Expand Down Expand Up @@ -746,6 +789,7 @@ function handleVideoEvent (evt) {
break;
case 'resize':
data = evt.target.videoWidth + '/' + evt.target.videoHeight;
playerResize();
break;
case 'loadedmetadata':
case 'loadeddata':
Expand Down Expand Up @@ -855,31 +899,30 @@ function timeRangesToString (r) {
}

function checkBuffer () {
const v = $('#video')[0];
const canvas = $('#bufferedCanvas')[0];
const canvas = document.querySelector('#bufferedCanvas');
const ctx = canvas.getContext('2d');
const r = v.buffered;
const r = video.buffered;
let bufferingDuration;
ctx.fillStyle = 'black';
if (r) {
if (!canvas.width || canvas.width !== v.clientWidth) {
canvas.width = v.clientWidth;
ctx.fillStyle = 'black';
if (!canvas.width || canvas.width !== video.clientWidth) {
canvas.width = video.clientWidth;
}
ctx.fillRect(0, 0, canvas.width, canvas.height);
const pos = v.currentTime;
const pos = video.currentTime;
let bufferLen = 0;
ctx.fillStyle = 'gray';
for (let i = 0; i < r.length; i++) {
const start = r.start(i) / v.duration * canvas.width;
const end = r.end(i) / v.duration * canvas.width;
const start = r.start(i) / video.duration * canvas.width;
const end = r.end(i) / video.duration * canvas.width;
ctx.fillRect(start, 2, Math.max(2, end - start), 11);
if (pos >= r.start(i) && pos < r.end(i)) {
// play position is inside this buffer TimeRange, retrieve end of buffer position and buffer length
bufferLen = r.end(i) - pos;
}
}
// check if we are in buffering / or playback ended state
if (bufferLen <= 0.1 && v.paused === false && (pos - lastStartPosition) > 0.5) {
if (bufferLen <= 0.1 && video.paused === false && (pos - lastStartPosition) > 0.5) {
if (lastDuration - pos <= 0.5 && events.isLive === false) {
// don't create buffering event if we are at the end of the playlist, don't report ended for live playlist
} else {
Expand Down Expand Up @@ -936,28 +979,32 @@ function checkBuffer () {
trimEventHistory();
self.refreshCanvas();

let log = `Duration: ${v.duration}\nBuffered: ${timeRangesToString(v.buffered)}\nSeekable: ${timeRangesToString(v.seekable)}\nPlayed: ${timeRangesToString(v.played)}\n`;
if ($('#statsDisplayTab').is(':visible')) {
let log = `Duration: ${video.duration}\nBuffered: ${timeRangesToString(video.buffered)}\nSeekable: ${timeRangesToString(video.seekable)}\nPlayed: ${timeRangesToString(video.played)}\n`;

if (hls.media) {
for (const type in tracks) {
log += 'Buffer for ' + type + ' contains: ' + timeRangesToString(tracks[type].buffer.buffered) + '\n';
}
if (hls.media) {
for (const type in tracks) {
log += 'Buffer for ' + type + ' contains: ' + timeRangesToString(tracks[type].buffer.buffered) + '\n';
}

const videoPlaybackQuality = v.getVideoPlaybackQuality;
if (videoPlaybackQuality && typeof (videoPlaybackQuality) === typeof (Function)) {
log += `Dropped frames: ${v.getVideoPlaybackQuality().droppedVideoFrames}\n`;
log += `Corrupted frames: ${v.getVideoPlaybackQuality().corruptedVideoFrames}\n`;
} else if (v.webkitDroppedFrameCount) {
log += `Dropped frames: ${v.webkitDroppedFrameCount}`;
const videoPlaybackQuality = video.getVideoPlaybackQuality;
if (videoPlaybackQuality && typeof (videoPlaybackQuality) === typeof (Function)) {
log += `Dropped frames: ${video.getVideoPlaybackQuality().droppedVideoFrames}\n`;
log += `Corrupted frames: ${video.getVideoPlaybackQuality().corruptedVideoFrames}\n`;
} else if (video.webkitDroppedFrameCount) {
log += `Dropped frames: ${video.webkitDroppedFrameCount}`;
}
}

$('#bufferedOut').text(log);
$('#statisticsOut').text(JSON.stringify(sortObject(stats), null, '\t'));
}

$('#bufferedOut').text(log);
$('#statisticsOut').text(JSON.stringify(sortObject(stats), null, '\t'));
ctx.fillStyle = 'blue';
const x = v.currentTime / v.duration * canvas.width;
const x = video.currentTime / video.duration * canvas.width;
ctx.fillRect(x, 0, 2, 15);
} else {
} else if (ctx.fillStyle !== 'black') {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
}
Expand Down Expand Up @@ -999,10 +1046,9 @@ function goToMetricsPermaLink () {
}

function onClickBufferedRange (event) {
const canvas = $('#bufferedCanvas')[0];
const v = $('#video')[0];
const target = (event.clientX - canvas.offsetLeft) / canvas.width * v.duration;
v.currentTime = target;
const canvas = document.querySelector('#bufferedCanvas');
const target = (event.clientX - canvas.offsetLeft) / canvas.width * video.duration;
video.currentTime = target;
}

function updateLevelInfo () {
Expand Down Expand Up @@ -1093,10 +1139,8 @@ function updateLevelInfo () {
html4 += 'onclick="hls.nextLevel=' + i + '">' + levelName + '</button>';
}

const v = $('#video')[0];

if (v.videoWidth && v.videoHeight) {
$('#currentResolution').html(v.videoWidth + ' x ' + v.videoHeight);
if (video.videoWidth && video.videoHeight) {
$('#currentResolution').html(`${video.videoWidth} x ${video.videoHeight}`);
}

if ($('#currentLevelControl').html() !== html1) {
Expand Down Expand Up @@ -1269,10 +1313,10 @@ function setupTimelineChart () {
responsive: false
});

self.onresize = () => chart.resize();
if (self.screen && self.screen.orientation) {
self.screen.orientation.addEventListener('change', self.onresize);
}
resizeHandlers.push(() => {
chart.resize();
});

chart.resize();

return chart;
Expand Down

0 comments on commit dd30675

Please sign in to comment.