@gcorevideo/player 2.6.0 → 2.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +38 -211
- package/lib/plugins/dash-playback/DashPlayback.d.ts +0 -4
- package/lib/plugins/dash-playback/DashPlayback.d.ts.map +1 -1
- package/lib/plugins/dash-playback/DashPlayback.js +38 -211
- package/package.json +1 -1
- package/src/plugins/dash-playback/DashPlayback.ts +40 -243
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Copyright 2014 Globo.com Player authors. All rights reserved.
|
|
2
2
|
// Use of this source code is governed by a BSD-style
|
|
3
3
|
// license that can be found in the LICENSE file.
|
|
4
|
-
import { Events, HTML5Video, Log, Playback, Utils
|
|
5
|
-
import assert from 'assert';
|
|
4
|
+
import { Events, HTML5Video, Log, Playback, Utils } from '@clappr/core';
|
|
5
|
+
import assert from 'assert';
|
|
6
6
|
import DASHJS from 'dashjs';
|
|
7
7
|
import { trace } from '../../trace/index.js';
|
|
8
8
|
const AUTO = -1;
|
|
@@ -11,24 +11,38 @@ const T = 'DashPlayback';
|
|
|
11
11
|
export default class DashPlayback extends HTML5Video {
|
|
12
12
|
_levels = null;
|
|
13
13
|
_currentLevel = null;
|
|
14
|
+
// true when the actual duration is longer than hlsjs's live sync point
|
|
15
|
+
// when this is false playableRegionDuration will be the actual duration
|
|
16
|
+
// when this is true playableRegionDuration will exclude the time after the sync point
|
|
14
17
|
_durationExcludesAfterLiveSyncPoint = false;
|
|
15
18
|
_isReadyState = false;
|
|
19
|
+
// if content is removed from the beginning then this empty area should
|
|
20
|
+
// be ignored. "playableRegionDuration" excludes the empty area
|
|
16
21
|
_playableRegionDuration = 0;
|
|
22
|
+
// for hls streams which have dvr with a sliding window,
|
|
23
|
+
// the content at the start of the playlist is removed as new
|
|
24
|
+
// content is appended at the end.
|
|
25
|
+
// this means the actual playable start time will increase as the
|
|
26
|
+
// start content is deleted
|
|
27
|
+
// For streams with dvr where the entire recording is kept from the
|
|
28
|
+
// beginning this should stay as 0
|
|
17
29
|
_playableRegionStartTime = 0;
|
|
18
30
|
_playbackType = Playback.VOD;
|
|
31
|
+
// #EXT-X-PLAYLIST-TYPE
|
|
19
32
|
_playlistType = null;
|
|
20
33
|
// #EXT-X-PROGRAM-DATE-TIME
|
|
21
34
|
_programDateTime = 0;
|
|
22
35
|
_dash = null;
|
|
23
36
|
_extrapolatedWindowDuration = 0;
|
|
24
|
-
_extrapolatedWindowNumSegments = 0
|
|
37
|
+
// _extrapolatedWindowNumSegments: number = 0
|
|
25
38
|
_lastDuration = null;
|
|
26
39
|
_lastTimeUpdate = { current: 0, total: 0 };
|
|
40
|
+
// {local, remote} remote is the time in the video element that should represent 0
|
|
41
|
+
// local is the system time when the 'remote' measurment took place
|
|
27
42
|
_localStartTimeCorrelation = null;
|
|
43
|
+
// {local, remote} remote is the time in the video element that should represents the end
|
|
44
|
+
// local is the system time when the 'remote' measurment took place
|
|
28
45
|
_localEndTimeCorrelation = null;
|
|
29
|
-
_recoverAttemptsRemaining = 0;
|
|
30
|
-
_recoveredAudioCodecError = false;
|
|
31
|
-
_recoveredDecodingError = false;
|
|
32
46
|
startChangeQuality = false;
|
|
33
47
|
manifestInfo = null;
|
|
34
48
|
// #EXT-X-TARGETDURATION
|
|
@@ -53,19 +67,14 @@ export default class DashPlayback extends HTML5Video {
|
|
|
53
67
|
set currentLevel(id) {
|
|
54
68
|
this._currentLevel = id;
|
|
55
69
|
this.trigger(Events.PLAYBACK_LEVEL_SWITCH_START);
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
ABRStrategy: 'abrL2A',
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
};
|
|
70
|
+
const settings = this.options.dash ? structuredClone(this.options.dash) : {};
|
|
71
|
+
settings.streaming = settings.streaming || {};
|
|
72
|
+
settings.streaming.abr = settings.streaming.abr || {};
|
|
73
|
+
settings.streaming.abr.autoSwitchBitrate = settings.streaming.abr.autoSwitchBitrate || {};
|
|
74
|
+
settings.streaming.abr.autoSwitchBitrate.video = id === -1;
|
|
66
75
|
assert.ok(this._dash, 'An instance of dashjs MediaPlayer is required to switch levels');
|
|
67
76
|
const dash = this._dash;
|
|
68
|
-
|
|
77
|
+
dash.updateSettings(settings);
|
|
69
78
|
if (id !== -1) {
|
|
70
79
|
this._dash.setQualityFor('video', id);
|
|
71
80
|
}
|
|
@@ -122,59 +131,26 @@ export default class DashPlayback extends HTML5Video {
|
|
|
122
131
|
}
|
|
123
132
|
constructor(options, i18n, playerError) {
|
|
124
133
|
super(options, i18n, playerError);
|
|
125
|
-
// backwards compatibility (TODO: remove on 0.3.0)
|
|
126
|
-
// this.options.playback || (this.options.playback = this.options);
|
|
127
|
-
// The size of the start time extrapolation window measured as a multiple of segments.
|
|
128
|
-
// Should be 2 or higher, or 0 to disable. Should only need to be increased above 2 if more than one segment is
|
|
129
|
-
// removed from the start of the playlist at a time. E.g if the playlist is cached for 10 seconds and new chunks are
|
|
130
|
-
// added/removed every 5.
|
|
131
|
-
this._extrapolatedWindowNumSegments =
|
|
132
|
-
this.options.playback?.extrapolatedWindowNumSegments ?? 2;
|
|
133
134
|
if (this.options.playbackType) {
|
|
134
135
|
this._playbackType = this.options.playbackType;
|
|
135
136
|
}
|
|
136
|
-
// this._lastTimeUpdate = { current: 0, total: 0 };
|
|
137
|
-
// this._lastDuration = null;
|
|
138
|
-
// for hls streams which have dvr with a sliding window,
|
|
139
|
-
// the content at the start of the playlist is removed as new
|
|
140
|
-
// content is appended at the end.
|
|
141
|
-
// this means the actual playable start time will increase as the
|
|
142
|
-
// start content is deleted
|
|
143
|
-
// For streams with dvr where the entire recording is kept from the
|
|
144
|
-
// beginning this should stay as 0
|
|
145
|
-
// this._playableRegionStartTime = 0;
|
|
146
|
-
// {local, remote} remote is the time in the video element that should represent 0
|
|
147
|
-
// local is the system time when the 'remote' measurment took place
|
|
148
|
-
// this._localStartTimeCorrelation = null;
|
|
149
|
-
// {local, remote} remote is the time in the video element that should represents the end
|
|
150
|
-
// local is the system time when the 'remote' measurment took place
|
|
151
|
-
// this._localEndTimeCorrelation = null;
|
|
152
|
-
// if content is removed from the beginning then this empty area should
|
|
153
|
-
// be ignored. "playableRegionDuration" excludes the empty area
|
|
154
|
-
// this._playableRegionDuration = 0;
|
|
155
|
-
// #EXT-X-PROGRAM-DATE-TIME
|
|
156
|
-
// this._programDateTime = 0;
|
|
157
|
-
// this.manifestInfo = null;
|
|
158
|
-
// true when the actual duration is longer than hlsjs's live sync point
|
|
159
|
-
// when this is false playableRegionDuration will be the actual duration
|
|
160
|
-
// when this is true playableRegionDuration will exclude the time after the sync point
|
|
161
|
-
// this._durationExcludesAfterLiveSyncPoint = false;
|
|
162
|
-
// // #EXT-X-TARGETDURATION
|
|
163
|
-
// this._segmentTargetDuration = null;
|
|
164
|
-
// #EXT-X-PLAYLIST-TYPE
|
|
165
|
-
// this._playlistType = null;
|
|
166
|
-
if (this.options.hlsRecoverAttempts) {
|
|
167
|
-
this._recoverAttemptsRemaining = this.options.hlsRecoverAttempts;
|
|
168
|
-
}
|
|
169
137
|
}
|
|
170
138
|
_setup() {
|
|
171
139
|
const dash = DASHJS.MediaPlayer().create();
|
|
172
140
|
this._dash = dash;
|
|
173
141
|
this._dash.initialize();
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
142
|
+
if (this.options.dash) {
|
|
143
|
+
const settings = structuredClone(this.options.dash);
|
|
144
|
+
if (!settings.streaming) {
|
|
145
|
+
settings.streaming = {};
|
|
146
|
+
}
|
|
147
|
+
if (!settings.streaming.text) {
|
|
148
|
+
settings.streaming.text = {
|
|
149
|
+
defaultEnabled: false,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
this._dash.updateSettings(this.options.dash);
|
|
153
|
+
}
|
|
178
154
|
this._dash.attachView(this.el);
|
|
179
155
|
this._dash.setAutoPlay(false);
|
|
180
156
|
this._dash.attachSource(this.options.src);
|
|
@@ -216,28 +192,6 @@ export default class DashPlayback extends HTML5Video {
|
|
|
216
192
|
this._isReadyState = true;
|
|
217
193
|
this.trigger(Events.PLAYBACK_READY, this.name);
|
|
218
194
|
}
|
|
219
|
-
// TODO
|
|
220
|
-
// _recover(evt, data, error) {
|
|
221
|
-
// console.warn('recover', evt, data, error);
|
|
222
|
-
// assert.ok(this._dash, 'An instance of dashjs MediaPlayer is required to recover');
|
|
223
|
-
// // TODO figure out what's going on here
|
|
224
|
-
// const dash = this._dash;
|
|
225
|
-
// if (!this._recoveredDecodingError) {
|
|
226
|
-
// this._recoveredDecodingError = true;
|
|
227
|
-
// // dash.recoverMediaError();
|
|
228
|
-
// } else if (!this._recoveredAudioCodecError) {
|
|
229
|
-
// this._recoveredAudioCodecError = true;
|
|
230
|
-
// // dash.swapAudioCodec();
|
|
231
|
-
// // dash.recoverMediaError();
|
|
232
|
-
// } else {
|
|
233
|
-
// // TODO what does it have to do with hlsjs?
|
|
234
|
-
// Log.error('hlsjs: failed to recover', { evt, data });
|
|
235
|
-
// error.level = PlayerError.Levels.FATAL;
|
|
236
|
-
// const formattedError = this.createError(error);
|
|
237
|
-
// this.trigger(Events.PLAYBACK_ERROR, formattedError);
|
|
238
|
-
// this.stop();
|
|
239
|
-
// }
|
|
240
|
-
// }
|
|
241
195
|
// override
|
|
242
196
|
_setupSrc() {
|
|
243
197
|
// this playback manages the src on the video element itself
|
|
@@ -305,7 +259,6 @@ export default class DashPlayback extends HTML5Video {
|
|
|
305
259
|
_updateSettings() {
|
|
306
260
|
if (this._playbackType === Playback.VOD) {
|
|
307
261
|
this.settings.left = ['playpause', 'position', 'duration'];
|
|
308
|
-
// this.settings.left.push('playstop');
|
|
309
262
|
}
|
|
310
263
|
else if (this.dvrEnabled) {
|
|
311
264
|
this.settings.left = ['playpause'];
|
|
@@ -501,131 +454,6 @@ export default class DashPlayback extends HTML5Video {
|
|
|
501
454
|
});
|
|
502
455
|
this.trigger(Events.PLAYBACK_LEVELS_AVAILABLE, this._levels);
|
|
503
456
|
}
|
|
504
|
-
// _onLevelUpdated(_: any, data) {
|
|
505
|
-
// this._segmentTargetDuration = data.details.targetduration;
|
|
506
|
-
// this._playlistType = data.details.type || null;
|
|
507
|
-
// let startTimeChanged = false;
|
|
508
|
-
// let durationChanged = false;
|
|
509
|
-
// const fragments = data.details.fragments;
|
|
510
|
-
// const previousPlayableRegionStartTime = this._playableRegionStartTime;
|
|
511
|
-
// const previousPlayableRegionDuration = this._playableRegionDuration;
|
|
512
|
-
// if (fragments.length === 0) {
|
|
513
|
-
// return;
|
|
514
|
-
// }
|
|
515
|
-
// // #EXT-X-PROGRAM-DATE-TIME
|
|
516
|
-
// if (fragments[0].rawProgramDateTime) {
|
|
517
|
-
// this._programDateTime = fragments[0].rawProgramDateTime;
|
|
518
|
-
// }
|
|
519
|
-
// if (this._playableRegionStartTime !== fragments[0].start) {
|
|
520
|
-
// startTimeChanged = true;
|
|
521
|
-
// this._playableRegionStartTime = fragments[0].start;
|
|
522
|
-
// }
|
|
523
|
-
// if (startTimeChanged) {
|
|
524
|
-
// if (!this._localStartTimeCorrelation) {
|
|
525
|
-
// // set the correlation to map to middle of the extrapolation window
|
|
526
|
-
// this._localStartTimeCorrelation = {
|
|
527
|
-
// local: this._now,
|
|
528
|
-
// remote: (fragments[0].start + (this._extrapolatedWindowDuration / 2)) * 1000
|
|
529
|
-
// };
|
|
530
|
-
// } else {
|
|
531
|
-
// // check if the correlation still works
|
|
532
|
-
// const corr = this._localStartTimeCorrelation;
|
|
533
|
-
// const timePassed = this._now - corr.local;
|
|
534
|
-
// // this should point to a time within the extrapolation window
|
|
535
|
-
// const startTime = (corr.remote + timePassed) / 1000;
|
|
536
|
-
// if (startTime < fragments[0].start) {
|
|
537
|
-
// // our start time is now earlier than the first chunk
|
|
538
|
-
// // (maybe the chunk was removed early)
|
|
539
|
-
// // reset correlation so that it sits at the beginning of the first available chunk
|
|
540
|
-
// this._localStartTimeCorrelation = {
|
|
541
|
-
// local: this._now,
|
|
542
|
-
// remote: fragments[0].start * 1000
|
|
543
|
-
// };
|
|
544
|
-
// } else if (startTime > previousPlayableRegionStartTime + this._extrapolatedWindowDuration) {
|
|
545
|
-
// // start time was past the end of the old extrapolation window (so would have been capped)
|
|
546
|
-
// // see if now that time would be inside the window, and if it would be set the correlation
|
|
547
|
-
// // so that it resumes from the time it was at at the end of the old window
|
|
548
|
-
// // update the correlation so that the time starts counting again from the value it's on now
|
|
549
|
-
// this._localStartTimeCorrelation = {
|
|
550
|
-
// local: this._now,
|
|
551
|
-
// remote: Math.max(
|
|
552
|
-
// fragments[0].start,
|
|
553
|
-
// previousPlayableRegionStartTime + this._extrapolatedWindowDuration
|
|
554
|
-
// ) * 1000
|
|
555
|
-
// };
|
|
556
|
-
// }
|
|
557
|
-
// }
|
|
558
|
-
// }
|
|
559
|
-
// let newDuration = data.details.totalduration;
|
|
560
|
-
// // if it's a live stream then shorten the duration to remove access
|
|
561
|
-
// // to the area after hlsjs's live sync point
|
|
562
|
-
// // seeks to areas after this point sometimes have issues
|
|
563
|
-
// if (this._playbackType === Playback.LIVE) {
|
|
564
|
-
// const fragmentTargetDuration = data.details.targetduration;
|
|
565
|
-
// const hlsjsConfig = this.options.playback.hlsjsConfig || {};
|
|
566
|
-
// // eslint-disable-next-line no-undef
|
|
567
|
-
// const liveSyncDurationCount = hlsjsConfig.liveSyncDurationCount || HLSJS.DefaultConfig.liveSyncDurationCount;
|
|
568
|
-
// const hiddenAreaDuration = fragmentTargetDuration * liveSyncDurationCount;
|
|
569
|
-
// if (hiddenAreaDuration <= newDuration) {
|
|
570
|
-
// newDuration -= hiddenAreaDuration;
|
|
571
|
-
// this._durationExcludesAfterLiveSyncPoint = true;
|
|
572
|
-
// } else {
|
|
573
|
-
// this._durationExcludesAfterLiveSyncPoint = false;
|
|
574
|
-
// }
|
|
575
|
-
// }
|
|
576
|
-
// if (newDuration !== this._playableRegionDuration) {
|
|
577
|
-
// durationChanged = true;
|
|
578
|
-
// this._playableRegionDuration = newDuration;
|
|
579
|
-
// }
|
|
580
|
-
// // Note the end time is not the playableRegionDuration
|
|
581
|
-
// // The end time will always increase even if content is removed from the beginning
|
|
582
|
-
// const endTime = fragments[0].start + newDuration;
|
|
583
|
-
// const previousEndTime = previousPlayableRegionStartTime + previousPlayableRegionDuration;
|
|
584
|
-
// const endTimeChanged = endTime !== previousEndTime;
|
|
585
|
-
// if (endTimeChanged) {
|
|
586
|
-
// if (!this._localEndTimeCorrelation) {
|
|
587
|
-
// // set the correlation to map to the end
|
|
588
|
-
// this._localEndTimeCorrelation = {
|
|
589
|
-
// local: this._now,
|
|
590
|
-
// remote: endTime * 1000
|
|
591
|
-
// };
|
|
592
|
-
// } else {
|
|
593
|
-
// // check if the correlation still works
|
|
594
|
-
// const corr = this._localEndTimeCorrelation;
|
|
595
|
-
// const timePassed = this._now - corr.local;
|
|
596
|
-
// // this should point to a time within the extrapolation window from the end
|
|
597
|
-
// const extrapolatedEndTime = (corr.remote + timePassed) / 1000;
|
|
598
|
-
// if (extrapolatedEndTime > endTime) {
|
|
599
|
-
// this._localEndTimeCorrelation = {
|
|
600
|
-
// local: this._now,
|
|
601
|
-
// remote: endTime * 1000
|
|
602
|
-
// };
|
|
603
|
-
// } else if (extrapolatedEndTime < endTime - this._extrapolatedWindowDuration) {
|
|
604
|
-
// // our extrapolated end time is now earlier than the extrapolation window from the actual end time
|
|
605
|
-
// // (maybe a chunk became available early)
|
|
606
|
-
// // reset correlation so that it sits at the beginning of the extrapolation window from the end time
|
|
607
|
-
// this._localEndTimeCorrelation = {
|
|
608
|
-
// local: this._now,
|
|
609
|
-
// remote: (endTime - this._extrapolatedWindowDuration) * 1000
|
|
610
|
-
// };
|
|
611
|
-
// } else if (extrapolatedEndTime > previousEndTime) {
|
|
612
|
-
// // end time was past the old end time (so would have been capped)
|
|
613
|
-
// // set the correlation so that it resumes from the time it was at at the end of the old window
|
|
614
|
-
// this._localEndTimeCorrelation = {
|
|
615
|
-
// local: this._now,
|
|
616
|
-
// remote: previousEndTime * 1000
|
|
617
|
-
// };
|
|
618
|
-
// }
|
|
619
|
-
// }
|
|
620
|
-
// }
|
|
621
|
-
// // now that the values have been updated call any methods that use on them so they get the updated values
|
|
622
|
-
// // immediately
|
|
623
|
-
// durationChanged && this._onDurationChange();
|
|
624
|
-
// startTimeChanged && this._onProgress();
|
|
625
|
-
// }
|
|
626
|
-
// _onFragmentLoaded(evt, data) {
|
|
627
|
-
// this.trigger(Events.PLAYBACK_FRAGMENT_LOADED, data);
|
|
628
|
-
// }
|
|
629
457
|
onLevelSwitch(currentLevel) {
|
|
630
458
|
this.trigger(Events.PLAYBACK_BITRATE, {
|
|
631
459
|
height: currentLevel.height,
|
|
@@ -646,7 +474,6 @@ DashPlayback.canPlay = function (resource, mimeType) {
|
|
|
646
474
|
const isDash = (resourceParts.length > 1 && resourceParts[1].toLowerCase() === 'mpd') ||
|
|
647
475
|
mimeType === 'application/dash+xml' ||
|
|
648
476
|
mimeType === 'video/mp4';
|
|
649
|
-
// TODO check
|
|
650
477
|
const ms = window.MediaSource;
|
|
651
478
|
const mms = 'ManagedMediaSource' in window ? window.ManagedMediaSource : undefined;
|
|
652
479
|
const wms = 'WebKitMediaSource' in window ? window.WebKitMediaSource : undefined;
|