Browse Source

feat: Start at offset from EXT-X-START (#1389)

Co-authored-by: Pat O'Neill <pgoneill@gmail.com>
Co-authored-by: Adam Waldron <awaldron@brightcove.com>
pull/1397/head
mister-ben 2 years ago
committed by GitHub
parent
commit
b3a508df2c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      docs/supported-features.md
  2. 23
      src/playlist-controller.js
  3. 15
      test/manifests/startLive.m3u8
  4. 12
      test/manifests/startNegative.m3u8
  5. 12
      test/manifests/startVod.m3u8
  6. 66
      test/videojs-http-streaming.test.js

1
docs/supported-features.md

@ -116,7 +116,6 @@ not yet been implemented. VHS currently supports everything in the
* [EXT-X-SESSION-DATA]
* [EXT-X-SESSION-KEY]
* [EXT-X-INDEPENDENT-SEGMENTS]
* Use of [EXT-X-START] (value parsed but not used)
* Alternate video via [EXT-X-MEDIA] of type video
* ASSOC-LANGUAGE in [EXT-X-MEDIA]
* CHANNELS in [EXT-X-MEDIA]

23
src/playlist-controller.js

@ -989,20 +989,33 @@ export class PlaylistController extends videojs.EventTarget {
return false;
}
// when the video is a live stream
if (!media.endList) {
// when the video is a live stream and/or has a start time
if (!media.endList || media.start) {
const seekable = this.seekable();
if (!seekable.length) {
// without a seekable range, the player cannot seek to begin buffering at the live
// point
// without a seekable range, the player cannot seek to begin buffering at the
// live or start point
return false;
}
const seekableEnd = seekable.end(0);
let startPoint = seekableEnd;
if (media.start) {
const offset = media.start.timeOffset;
if (offset < 0) {
startPoint = Math.max(seekableEnd + offset, seekable.start(0));
} else {
startPoint = Math.min(seekableEnd, offset);
}
}
// trigger firstplay to inform the source handler to ignore the next seek event
this.trigger('firstplay');
// seek to the live point
this.tech_.setCurrentTime(seekable.end(0));
this.tech_.setCurrentTime(startPoint);
}
this.hasPlayed_ = true;

15
test/manifests/startLive.m3u8

@ -0,0 +1,15 @@
#EXTM3U
#EXT-X-START:TIME-OFFSET=0
#EXT-X-TARGETDURATION:10
#EXTINF:10,
media-00001.ts
#EXTINF:10,
media-00002.ts
#EXTINF:10,
media-00003.ts
#EXTINF:10,
media-00004.ts
#EXTINF:10,
media-00005.ts
#EXTINF:10,
media-00006.ts

12
test/manifests/startNegative.m3u8

@ -0,0 +1,12 @@
#EXTM3U
#EXT-X-START:TIME-OFFSET=-5.0
#EXT-X-TARGETDURATION:10
#EXTINF:10,
media-00001.ts
#EXTINF:10,
media-00002.ts
#EXTINF:10,
media-00003.ts
#EXTINF:10,
media-00004.ts
#EXT-X-ENDLIST

12
test/manifests/startVod.m3u8

@ -0,0 +1,12 @@
#EXTM3U
#EXT-X-START:TIME-OFFSET=10.3
#EXT-X-TARGETDURATION:10
#EXTINF:10,
media-00001.ts
#EXTINF:10,
media-00002.ts
#EXTINF:10,
media-00003.ts
#EXTINF:10,
media-00004.ts
#EXT-X-ENDLIST

66
test/videojs-http-streaming.test.js

@ -396,6 +396,72 @@ QUnit.test('autoplay seeks to the live point after media source open', function(
assert.notEqual(currentTime, 0, 'seeked on autoplay');
});
QUnit.test('seeks to the start offset point', function(assert) {
let currentTime = 0;
this.player.autoplay(true);
this.player.on('seeking', () => {
currentTime = this.player.currentTime();
});
this.player.src({
src: 'startVod.m3u8',
type: 'application/vnd.apple.mpegurl'
});
this.clock.tick(1);
openMediaSource(this.player, this.clock);
this.player.tech_.trigger('play');
this.standardXHRResponse(this.requests.shift());
this.clock.tick(1);
assert.strictEqual(currentTime, 10.3, 'seeked to positive offset');
});
QUnit.test('seeks to non-negative offet for a live stream', function(assert) {
let currentTime = 0;
this.player.autoplay(true);
this.player.on('seeking', () => {
currentTime = this.player.currentTime();
});
this.player.src({
src: 'startLive.m3u8',
type: 'application/vnd.apple.mpegurl'
});
this.clock.tick(1);
openMediaSource(this.player, this.clock);
this.player.tech_.trigger('play');
this.standardXHRResponse(this.requests.shift());
this.clock.tick(1);
assert.strictEqual(currentTime, 0, 'seeked to offset on live stream');
});
QUnit.test('seeks to negative offset point', function(assert) {
let currentTime = 0;
this.player.autoplay(true);
this.player.on('seeking', () => {
currentTime = this.player.currentTime();
});
this.player.src({
src: 'startNegative.m3u8',
type: 'application/vnd.apple.mpegurl'
});
this.clock.tick(1);
openMediaSource(this.player, this.clock);
this.player.tech_.trigger('play');
this.standardXHRResponse(this.requests.shift());
this.clock.tick(1);
assert.strictEqual(currentTime, 35, 'seeked to negative offset');
});
QUnit.test(
'duration is set when the source opens after the playlist is loaded',
function(assert) {

Loading…
Cancel
Save