Skip to content

Commit 2974ad3

Browse files
brandonocaseygkatsev
authored andcommitted
feat: support seeking during live playback via liveui option (#5511)
When liveui is enabled, allow seeking during the live window, add button that allows you to seek to the live edge and that indicates whether you are at the live edge or not.
1 parent db1369a commit 2974ad3

File tree

17 files changed

+912
-46
lines changed

17 files changed

+912
-46
lines changed

package-lock.json

Lines changed: 19 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sandbox/live.html.example

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Video.js Sandbox</title>
6+
<link href="../dist/video-js.css" rel="stylesheet" type="text/css">
7+
<script src="../dist/video.js"></script>
8+
</head>
9+
<body>
10+
<div style="background-color:#eee; border: 1px solid #777; padding: 10px; margin-bottom: 20px; font-size: .8em; line-height: 1.5em; font-family: Verdana, sans-serif;">
11+
<p>You can use /sandbox/ for writing and testing your own code. Nothing in /sandbox/ will get checked into the repo, except files that end in .example (so don't edit or add those files). To get started make a copy of index.html.example and rename it to index.html.</p>
12+
<pre>cp sandbox/index.html.example sandbox/index.html</pre>
13+
<pre>npm run start</pre>
14+
<pre>open http://localhost:9999/sandbox/index.html</pre>
15+
</div>
16+
17+
<video-js id="vid1" controls preload="auto" width="640" height="264">
18+
<source src="https://akamai-axtest.akamaized.net/routes/lapd-v1-acceptance/www_c4/Manifest.m3u8" type="application/x-mpegURL">
19+
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
20+
</video-js>
21+
22+
<script>
23+
// fake a livestream for easy testing
24+
var vid = document.getElementById('vid1');
25+
26+
var player = videojs(vid);
27+
</script>
28+
29+
</body>
30+
</html>

sandbox/liveui.html.example

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Video.js Sandbox</title>
6+
<link href="../dist/video-js.css" rel="stylesheet" type="text/css">
7+
<script src="../dist/video.js"></script>
8+
</head>
9+
<body>
10+
<div style="background-color:#eee; border: 1px solid #777; padding: 10px; margin-bottom: 20px; font-size: .8em; line-height: 1.5em; font-family: Verdana, sans-serif;">
11+
<p>You can use /sandbox/ for writing and testing your own code. Nothing in /sandbox/ will get checked into the repo, except files that end in .example (so don't edit or add those files). To get started make a copy of index.html.example and rename it to index.html.</p>
12+
<pre>cp sandbox/index.html.example sandbox/index.html</pre>
13+
<pre>npm run start</pre>
14+
<pre>open http://localhost:9999/sandbox/index.html</pre>
15+
</div>
16+
17+
<video-js id="vid1" controls preload="auto" width="640" height="264">
18+
<source src="https://akamai-axtest.akamaized.net/routes/lapd-v1-acceptance/www_c4/Manifest.m3u8" type="application/x-mpegURL">
19+
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
20+
</video-js>
21+
22+
<script>
23+
// fake a livestream for easy testing
24+
var vid = document.getElementById('vid1');
25+
var liveui = true
26+
27+
if (videojs.browser.IS_ANDROID) {
28+
liveui = false;
29+
}
30+
var player = videojs(vid, {liveui: liveui});
31+
</script>
32+
33+
</body>
34+
</html>

src/css/components/_live.scss

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// We are assuming there is no progress bar and using the live display
2-
// to fill in the middle space. Live+DVR will need to adjust this.
1+
// css for the old live ui, assumes that the progress bar is hidden
32
.video-js .vjs-live-control {
43
@include display-flex(flex-start);
54
@include flex(auto);
@@ -12,3 +11,53 @@
1211
width: auto;
1312
text-align: left;
1413
}
14+
15+
// hide the LiveDisplay when not live or when
16+
// the new liveui is in use
17+
.video-js:not(.vjs-live) .vjs-live-control,
18+
.video-js.vjs-liveui .vjs-live-control {
19+
display: none;
20+
}
21+
22+
// css for the new live ui below
23+
.video-js .vjs-seek-to-live-control {
24+
cursor: pointer;
25+
@include flex(none);
26+
display: inline-flex;
27+
height: 100%;
28+
padding-left: 0.5em;
29+
padding-right: 0.5em;
30+
font-size: 1em;
31+
line-height: 3em;
32+
width: auto;
33+
min-width: 4em;
34+
}
35+
36+
.vjs-no-flex .vjs-seek-to-live-control {
37+
display: table-cell;
38+
width: auto;
39+
text-align: left;
40+
}
41+
42+
// hide the SeekToLive button when not live and
43+
// when the liveui is not in use
44+
.video-js.vjs-live:not(.vjs-liveui) .vjs-seek-to-live-control,
45+
.video-js:not(.vjs-live) .vjs-seek-to-live-control {
46+
display: none;
47+
}
48+
49+
// only show as a pointer when we will seek to live edge
50+
.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge {
51+
cursor: auto;
52+
}
53+
54+
.vjs-seek-to-live-control .vjs-seek-to-live-circle {
55+
margin-right: 0.5em;
56+
@extend .vjs-icon-circle;
57+
color: #888;
58+
}
59+
60+
// make the live circle red when at the live edge
61+
.vjs-seek-to-live-control.vjs-control.vjs-at-live-edge .vjs-seek-to-live-circle {
62+
color: red;
63+
}

src/css/components/_progress.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
display: none;
1818
}
1919

20+
.vjs-liveui .vjs-progress-control {
21+
@include display-flex(center);
22+
}
23+
2024
.vjs-no-flex .vjs-progress-control {
2125
width: auto;
2226
}

src/js/control-bar/control-bar.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import './time-controls/duration-display.js';
1010
import './time-controls/time-divider.js';
1111
import './time-controls/remaining-time-display.js';
1212
import './live-display.js';
13+
import './seek-to-live.js';
1314
import './progress-control/progress-control.js';
1415
import './fullscreen-toggle.js';
1516
import './volume-panel.js';
@@ -58,6 +59,7 @@ ControlBar.prototype.options_ = {
5859
'durationDisplay',
5960
'progressControl',
6061
'liveDisplay',
62+
'seekToLive',
6163
'remainingTimeDisplay',
6264
'customControlSpacer',
6365
'playbackRateMenuButton',

src/js/control-bar/progress-control/load-progress-bar.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ class LoadProgressBar extends Component {
5454
* @listens Player#progress
5555
*/
5656
update(event) {
57+
const liveTracker = this.player_.liveTracker;
5758
const buffered = this.player_.buffered();
58-
const duration = this.player_.duration();
59+
const duration = liveTracker.isLive() ? liveTracker.seekableEnd() : this.player_.duration();
5960
const bufferedEnd = this.player_.bufferedEnd();
6061
const children = this.partEls_;
6162

src/js/control-bar/progress-control/mouse-time-display.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
*/
44
import Component from '../../component.js';
55
import * as Fn from '../../utils/fn.js';
6-
import formatTime from '../../utils/format-time.js';
76

87
import './time-tooltip';
98

@@ -55,18 +54,10 @@ class MouseTimeDisplay extends Component {
5554
* from the left edge of the {@link SeekBar}
5655
*/
5756
update(seekBarRect, seekBarPoint) {
57+
const time = seekBarPoint * this.player_.duration();
5858

59-
// If there is an existing rAF ID, cancel it so we don't over-queue.
60-
if (this.rafId_) {
61-
this.cancelAnimationFrame(this.rafId_);
62-
}
63-
64-
this.rafId_ = this.requestAnimationFrame(() => {
65-
const duration = this.player_.duration();
66-
const content = formatTime(seekBarPoint * duration, duration);
67-
59+
this.getChild('timeTooltip').updateTime(seekBarRect, seekBarPoint, time, () => {
6860
this.el_.style.left = `${seekBarRect.width * seekBarPoint}px`;
69-
this.getChild('timeTooltip').update(seekBarRect, seekBarPoint, content);
7061
});
7162
}
7263
}

src/js/control-bar/progress-control/play-progress-bar.js

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
*/
44
import Component from '../../component.js';
55
import {IS_IOS, IS_ANDROID} from '../../utils/browser.js';
6-
import formatTime from '../../utils/format-time.js';
76

87
import './time-tooltip';
98

@@ -40,24 +39,17 @@ class PlayProgressBar extends Component {
4039
* from the left edge of the {@link SeekBar}
4140
*/
4241
update(seekBarRect, seekBarPoint) {
42+
const timeTooltip = this.getChild('timeTooltip');
4343

44-
// If there is an existing rAF ID, cancel it so we don't over-queue.
45-
if (this.rafId_) {
46-
this.cancelAnimationFrame(this.rafId_);
44+
if (!timeTooltip) {
45+
return;
4746
}
4847

49-
this.rafId_ = this.requestAnimationFrame(() => {
50-
const time = (this.player_.scrubbing()) ?
51-
this.player_.getCache().currentTime :
52-
this.player_.currentTime();
48+
const time = (this.player_.scrubbing()) ?
49+
this.player_.getCache().currentTime :
50+
this.player_.currentTime();
5351

54-
const content = formatTime(time, this.player_.duration());
55-
const timeTooltip = this.getChild('timeTooltip');
56-
57-
if (timeTooltip) {
58-
timeTooltip.update(seekBarRect, seekBarPoint, content);
59-
}
60-
});
52+
timeTooltip.updateTime(seekBarRect, seekBarPoint, time);
6153
}
6254
}
6355

0 commit comments

Comments
 (0)