shaka-player 4.9.21 → 4.9.23
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/AUTHORS +2 -0
- package/CONTRIBUTORS +3 -0
- package/dist/controls.css +1 -1
- package/dist/deps.js +11 -11
- package/dist/locales.js +35 -35
- package/dist/shaka-player.compiled.debug.js +469 -471
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +1231 -1226
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +515 -518
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +1422 -1417
- package/dist/shaka-player.ui.map +3 -3
- package/externs/xbox.js +20 -0
- package/lib/abr/simple_abr_manager.js +1 -1
- package/lib/dash/dash_parser.js +31 -7
- package/lib/hls/hls_classes.js +5 -1
- package/lib/hls/hls_parser.js +2 -2
- package/lib/media/closed_caption_parser.js +1 -1
- package/lib/media/media_source_engine.js +7 -5
- package/lib/media/streaming_engine.js +106 -19
- package/lib/media/video_wrapper.js +2 -1
- package/lib/player.js +29 -9
- package/lib/polyfill/abort_controller.js +24 -16
- package/lib/text/ui_text_displayer.js +16 -13
- package/lib/text/vtt_text_parser.js +16 -1
- package/lib/util/platform.js +13 -2
- package/lib/util/stream_utils.js +44 -0
- package/lib/util/tXml.js +40 -1
- package/package.json +5 -5
- package/ui/presentation_time.js +4 -1
- package/ui/resolution_selection.js +11 -3
- package/ui/seek_bar.js +2 -1
|
@@ -58,14 +58,11 @@ shaka.polyfill.AbortController = class {
|
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
60
|
* @summary A polyfill for AbortSignal, part of the AbortController API.
|
|
61
|
-
* @
|
|
61
|
+
* @extends AbortSignal
|
|
62
62
|
*/
|
|
63
|
-
shaka.polyfill.AbortController.AbortSignal =
|
|
64
|
-
class extends shaka.util.FakeEventTarget {
|
|
63
|
+
shaka.polyfill.AbortController.AbortSignal = class {
|
|
65
64
|
/** */
|
|
66
65
|
constructor() {
|
|
67
|
-
super();
|
|
68
|
-
|
|
69
66
|
/** @private {boolean} */
|
|
70
67
|
this.aborted_ = false;
|
|
71
68
|
|
|
@@ -74,6 +71,24 @@ class extends shaka.util.FakeEventTarget {
|
|
|
74
71
|
|
|
75
72
|
/** @type {?function(!Event)} */
|
|
76
73
|
this.onabort = null;
|
|
74
|
+
|
|
75
|
+
/** @private {!shaka.util.FakeEventTarget} */
|
|
76
|
+
this.eventTarget_ = new shaka.util.FakeEventTarget();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @override */
|
|
80
|
+
addEventListener(type, listener, options) {
|
|
81
|
+
return this.eventTarget_.addEventListener(type, listener, options);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** @override */
|
|
85
|
+
removeEventListener(type, listener, options) {
|
|
86
|
+
return this.eventTarget_.removeEventListener(type, listener, options);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @override */
|
|
90
|
+
dispatchEvent(event) {
|
|
91
|
+
return this.eventTarget_.dispatchEvent(event);
|
|
77
92
|
}
|
|
78
93
|
|
|
79
94
|
/** @override */
|
|
@@ -81,12 +96,12 @@ class extends shaka.util.FakeEventTarget {
|
|
|
81
96
|
return this.aborted_;
|
|
82
97
|
}
|
|
83
98
|
|
|
84
|
-
/** @
|
|
99
|
+
/** @override */
|
|
85
100
|
get reason() {
|
|
86
101
|
return this.reason_;
|
|
87
102
|
}
|
|
88
103
|
|
|
89
|
-
/** @
|
|
104
|
+
/** @override */
|
|
90
105
|
throwIfAborted() {
|
|
91
106
|
if (this.aborted_) {
|
|
92
107
|
throw this.reason_;
|
|
@@ -119,21 +134,14 @@ class extends shaka.util.FakeEventTarget {
|
|
|
119
134
|
this.dispatchEvent(event);
|
|
120
135
|
}
|
|
121
136
|
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* @param {*=} reason
|
|
125
|
-
* @return {!AbortSignal}
|
|
126
|
-
*/
|
|
137
|
+
/** @override */
|
|
127
138
|
static abort(reason) {
|
|
128
139
|
const signal = new shaka.polyfill.AbortController.AbortSignal();
|
|
129
140
|
signal.doAbort_(reason);
|
|
130
141
|
return signal;
|
|
131
142
|
}
|
|
132
143
|
|
|
133
|
-
/**
|
|
134
|
-
* @param {number} timeMs
|
|
135
|
-
* @return {!AbortSignal}
|
|
136
|
-
*/
|
|
144
|
+
/** @override */
|
|
137
145
|
static timeout(timeMs) {
|
|
138
146
|
const signal = new shaka.polyfill.AbortController.AbortSignal();
|
|
139
147
|
|
|
@@ -471,8 +471,8 @@ shaka.text.UITextDisplayer = class {
|
|
|
471
471
|
const linesUnit = shaka.text.CueRegion.units.LINES;
|
|
472
472
|
const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
|
|
473
473
|
const pixelUnit = shaka.text.CueRegion.units.PX;
|
|
474
|
-
|
|
475
|
-
|
|
474
|
+
let heightUnit = region.heightUnits == percentageUnit ? '%' : 'px';
|
|
475
|
+
let widthUnit = region.widthUnits == percentageUnit ? '%' : 'px';
|
|
476
476
|
const viewportAnchorUnit =
|
|
477
477
|
region.viewportAnchorUnits == percentageUnit ? '%' : 'px';
|
|
478
478
|
|
|
@@ -481,16 +481,19 @@ shaka.text.UITextDisplayer = class {
|
|
|
481
481
|
|
|
482
482
|
regionElement.style.position = 'absolute';
|
|
483
483
|
|
|
484
|
+
let regionHeight = region.height;
|
|
485
|
+
let regionWidth = region.width;
|
|
486
|
+
|
|
484
487
|
if (region.heightUnits === linesUnit) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
regionElement.style.height = region.height + heightUnit;
|
|
488
|
+
regionHeight = region.height * lineHeightMultiple;
|
|
489
|
+
heightUnit = '%';
|
|
488
490
|
}
|
|
489
491
|
if (region.widthUnits === linesUnit) {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
regionElement.style.width = region.width + widthUnit;
|
|
492
|
+
regionWidth = region.width * lineWidthMultiple;
|
|
493
|
+
widthUnit = '%';
|
|
493
494
|
}
|
|
495
|
+
regionElement.style.height = regionHeight + heightUnit;
|
|
496
|
+
regionElement.style.width = regionWidth + widthUnit;
|
|
494
497
|
|
|
495
498
|
if (region.viewportAnchorUnits === linesUnit) {
|
|
496
499
|
// from https://dvcs.w3.org/hg/text-tracks/raw-file/default/608toVTT/608toVTT.html#positioning-in-cea-708
|
|
@@ -498,15 +501,15 @@ shaka.text.UITextDisplayer = class {
|
|
|
498
501
|
const windowWidth = this.aspectRatio_ === 4/3 ? 160 : 210;
|
|
499
502
|
let left = region.viewportAnchorX / windowWidth * 100;
|
|
500
503
|
// adjust top and left values based on the region anchor and window size
|
|
501
|
-
top -= region.regionAnchorY *
|
|
502
|
-
left -= region.regionAnchorX *
|
|
504
|
+
top -= region.regionAnchorY * regionHeight / 100;
|
|
505
|
+
left -= region.regionAnchorX * regionWidth / 100;
|
|
503
506
|
regionElement.style.top = top + '%';
|
|
504
507
|
regionElement.style.left = left + '%';
|
|
505
508
|
} else {
|
|
506
509
|
regionElement.style.top = region.viewportAnchorY -
|
|
507
|
-
region.regionAnchorY *
|
|
510
|
+
region.regionAnchorY * regionHeight / 100 + viewportAnchorUnit;
|
|
508
511
|
regionElement.style.left = region.viewportAnchorX -
|
|
509
|
-
region.regionAnchorX *
|
|
512
|
+
region.regionAnchorX * regionWidth / 100 + viewportAnchorUnit;
|
|
510
513
|
}
|
|
511
514
|
if (region.heightUnits !== pixelUnit &&
|
|
512
515
|
region.widthUnits !== pixelUnit &&
|
|
@@ -839,7 +842,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
839
842
|
if (cue.position !== null) {
|
|
840
843
|
style.position = 'absolute';
|
|
841
844
|
if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
|
|
842
|
-
style.right = cue.position + '%';
|
|
845
|
+
style.right = (100 - cue.position) + '%';
|
|
843
846
|
style.width = 'auto';
|
|
844
847
|
} else {
|
|
845
848
|
style.bottom = cue.position + '%';
|
|
@@ -160,9 +160,17 @@ shaka.text.VttTextParser = class {
|
|
|
160
160
|
shaka.util.Error.Code.INVALID_TEXT_HEADER);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
let mpegTime = Number(mpegTimeMatch[1]);
|
|
164
164
|
const mpegTimescale = shaka.text.VttTextParser.MPEG_TIMESCALE_;
|
|
165
165
|
|
|
166
|
+
const rolloverSeconds =
|
|
167
|
+
shaka.text.VttTextParser.TS_ROLLOVER_ / mpegTimescale;
|
|
168
|
+
let segmentStart = time.segmentStart - time.periodStart;
|
|
169
|
+
while (segmentStart >= rolloverSeconds) {
|
|
170
|
+
segmentStart -= rolloverSeconds;
|
|
171
|
+
mpegTime += shaka.text.VttTextParser.TS_ROLLOVER_;
|
|
172
|
+
}
|
|
173
|
+
|
|
166
174
|
return time.periodStart + mpegTime / mpegTimescale - cueTime;
|
|
167
175
|
}
|
|
168
176
|
|
|
@@ -1007,6 +1015,13 @@ shaka.text.VttTextParser = class {
|
|
|
1007
1015
|
*/
|
|
1008
1016
|
shaka.text.VttTextParser.MPEG_TIMESCALE_ = 90000;
|
|
1009
1017
|
|
|
1018
|
+
/**
|
|
1019
|
+
* At this value, timestamps roll over in TS content.
|
|
1020
|
+
* @const {number}
|
|
1021
|
+
* @private
|
|
1022
|
+
*/
|
|
1023
|
+
shaka.text.VttTextParser.TS_ROLLOVER_ = 0x200000000;
|
|
1024
|
+
|
|
1010
1025
|
/**
|
|
1011
1026
|
* @const
|
|
1012
1027
|
* @private {!RegExp}
|
package/lib/util/platform.js
CHANGED
|
@@ -749,10 +749,21 @@ shaka.util.Platform = class {
|
|
|
749
749
|
maxResolution.width = 1920;
|
|
750
750
|
maxResolution.height = 1080;
|
|
751
751
|
try {
|
|
752
|
+
let winRT = undefined;
|
|
753
|
+
|
|
754
|
+
// Try to access to WinRT for WebView, if it's not defined,
|
|
755
|
+
// try to access to WinRT for WebView2, if it's not defined either,
|
|
756
|
+
// let it throw.
|
|
757
|
+
if (typeof Windows !== 'undefined') {
|
|
758
|
+
winRT = Windows;
|
|
759
|
+
} else {
|
|
760
|
+
winRT = chrome.webview.hostObjects.sync.Windows;
|
|
761
|
+
}
|
|
762
|
+
|
|
752
763
|
const protectionCapabilities =
|
|
753
|
-
new
|
|
764
|
+
new winRT.Media.Protection.ProtectionCapabilities();
|
|
754
765
|
const protectionResult =
|
|
755
|
-
|
|
766
|
+
winRT.Media.Protection.ProtectionCapabilityResult;
|
|
756
767
|
// isTypeSupported may return "maybe", which means the operation is not
|
|
757
768
|
// completed. This means we need to retry
|
|
758
769
|
// https://learn.microsoft.com/en-us/uwp/api/windows.media.protection.protectioncapabilityresult?view=winrt-22621
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -374,6 +374,9 @@ shaka.util.StreamUtils = class {
|
|
|
374
374
|
goog.asserts.assert(navigator.mediaCapabilities,
|
|
375
375
|
'MediaCapabilities should be valid.');
|
|
376
376
|
|
|
377
|
+
if (shaka.util.Platform.isXboxOne()) {
|
|
378
|
+
shaka.util.StreamUtils.overrideDolbyVisionCodecs(manifest.variants);
|
|
379
|
+
}
|
|
377
380
|
await shaka.util.StreamUtils.getDecodingInfosForVariants(
|
|
378
381
|
manifest.variants, usePersistentLicenses, /* srcEquals= */ false,
|
|
379
382
|
preferredKeySystems);
|
|
@@ -400,6 +403,40 @@ shaka.util.StreamUtils = class {
|
|
|
400
403
|
}
|
|
401
404
|
|
|
402
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Maps Dolby Vision codecs to H.264 and H.265 equivalents as a workaround
|
|
408
|
+
* to make Dolby Vision playback work on some platforms.
|
|
409
|
+
*
|
|
410
|
+
* Mapping is done according to the relevant Dolby documentation found here:
|
|
411
|
+
* https://professionalsupport.dolby.com/s/article/How-to-signal-Dolby-Vision-in-MPEG-DASH?language=en_US
|
|
412
|
+
* @param {!Array<!shaka.extern.Variant>} variants
|
|
413
|
+
*/
|
|
414
|
+
static overrideDolbyVisionCodecs(variants) {
|
|
415
|
+
/** @type {!Object<string, string>} */
|
|
416
|
+
const codecMap = {
|
|
417
|
+
'dvav': 'avc3',
|
|
418
|
+
'dva1': 'avc1',
|
|
419
|
+
'dvhe': 'hev1',
|
|
420
|
+
'dvh1': 'hvc1',
|
|
421
|
+
};
|
|
422
|
+
/** @type {!Set<!shaka.extern.Stream>} */
|
|
423
|
+
const streams = new Set();
|
|
424
|
+
for (const variant of variants) {
|
|
425
|
+
if (variant.video) {
|
|
426
|
+
streams.add(variant.video);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
for (const video of streams) {
|
|
430
|
+
for (const dvCodec of Object.keys(codecMap)) {
|
|
431
|
+
if (video.codecs.includes(dvCodec)) {
|
|
432
|
+
video.codecs = video.codecs.replace(dvCodec, codecMap[dvCodec]);
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
|
|
403
440
|
/**
|
|
404
441
|
* @param {!shaka.extern.Variant} variant
|
|
405
442
|
* @param {?string} keySystem
|
|
@@ -1345,6 +1382,13 @@ shaka.util.StreamUtils = class {
|
|
|
1345
1382
|
track.hdr = video.hdr || null;
|
|
1346
1383
|
track.colorGamut = video.colorGamut || null;
|
|
1347
1384
|
track.videoLayout = video.videoLayout || null;
|
|
1385
|
+
|
|
1386
|
+
if (videoCodec.includes(',')) {
|
|
1387
|
+
track.channelsCount = video.channelsCount;
|
|
1388
|
+
track.audioSamplingRate = video.audioSamplingRate;
|
|
1389
|
+
track.spatialAudio = video.spatialAudio;
|
|
1390
|
+
track.originalLanguage = video.originalLanguage;
|
|
1391
|
+
}
|
|
1348
1392
|
}
|
|
1349
1393
|
|
|
1350
1394
|
if (audio) {
|
package/lib/util/tXml.js
CHANGED
|
@@ -753,11 +753,18 @@ shaka.util.TXml = class {
|
|
|
753
753
|
// We only want the id attribute in which case
|
|
754
754
|
// /'(.*?)'/ will suffice to get it.
|
|
755
755
|
const idAttr = path.match(/(@id='(.*?)')/);
|
|
756
|
+
const tAttr = path.match(/(@t='(\d+)')/);
|
|
757
|
+
const numberIndex = path.match(/(@n='(\d+)')/);
|
|
756
758
|
const position = path.match(/\[(\d+)\]/);
|
|
757
759
|
returnPaths.push({
|
|
758
760
|
name: nodeName[0],
|
|
759
761
|
id: idAttr ?
|
|
760
762
|
idAttr[0].match(/'(.*?)'/)[0].replace(/'/gm, '') : null,
|
|
763
|
+
t: tAttr ?
|
|
764
|
+
Number(tAttr[0].match(/'(.*?)'/)[0].replace(/'/gm, '')) : null,
|
|
765
|
+
n: numberIndex ?
|
|
766
|
+
Number(numberIndex[0].match(/'(.*?)'/)[0].replace(/'/gm, '')):
|
|
767
|
+
null,
|
|
761
768
|
// position is counted from 1, so make it readable for devs
|
|
762
769
|
position: position ? Number(position[1]) - 1 : null,
|
|
763
770
|
attribute: path.split('/@')[1] || null,
|
|
@@ -787,6 +794,14 @@ shaka.util.TXml = class {
|
|
|
787
794
|
const position = patchNode.attributes['pos'] || null;
|
|
788
795
|
|
|
789
796
|
let index = lastNode.position;
|
|
797
|
+
if (index == null) {
|
|
798
|
+
if (lastNode.t !== null) {
|
|
799
|
+
index = TXml.nodePositionByAttribute_(nodes, 't', lastNode.t);
|
|
800
|
+
}
|
|
801
|
+
if (lastNode.n !== null) {
|
|
802
|
+
index = TXml.nodePositionByAttribute_(nodes, 'n', lastNode.n);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
790
805
|
if (index === null) {
|
|
791
806
|
index = position === 'prepend' ? 0 : nodes.length;
|
|
792
807
|
} else if (position === 'prepend') {
|
|
@@ -798,7 +813,7 @@ shaka.util.TXml = class {
|
|
|
798
813
|
const attribute = lastNode.attribute;
|
|
799
814
|
|
|
800
815
|
// Modify attribute
|
|
801
|
-
if (attribute) {
|
|
816
|
+
if (attribute && nodes[index]) {
|
|
802
817
|
TXml.modifyNodeAttribute(nodes[index], action, attribute,
|
|
803
818
|
TXml.getContents(patchNode) || '');
|
|
804
819
|
// Rearrange nodes
|
|
@@ -814,6 +829,28 @@ shaka.util.TXml = class {
|
|
|
814
829
|
}
|
|
815
830
|
|
|
816
831
|
|
|
832
|
+
/**
|
|
833
|
+
* Search the node index by the t attribute
|
|
834
|
+
* and return the index. if not found return null
|
|
835
|
+
* @param {!Array<shaka.extern.xml.Node>} nodes
|
|
836
|
+
* @param {!string} attribute
|
|
837
|
+
* @param {!number} value
|
|
838
|
+
* @private
|
|
839
|
+
*/
|
|
840
|
+
static nodePositionByAttribute_(nodes, attribute, value) {
|
|
841
|
+
let index = 0;
|
|
842
|
+
for (const node of nodes) {
|
|
843
|
+
const attrs = node.attributes;
|
|
844
|
+
const val = Number(attrs[attribute]);
|
|
845
|
+
if (val === value) {
|
|
846
|
+
return index;
|
|
847
|
+
}
|
|
848
|
+
index++;
|
|
849
|
+
}
|
|
850
|
+
return null;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
|
|
817
854
|
/**
|
|
818
855
|
* @param {!shaka.extern.xml.Node} node
|
|
819
856
|
* @param {string} action
|
|
@@ -875,6 +912,8 @@ shaka.util.TXml.knownNameSpaces_ = new Map([]);
|
|
|
875
912
|
* @typedef {{
|
|
876
913
|
* name: string,
|
|
877
914
|
* id: ?string,
|
|
915
|
+
* t: ?number,
|
|
916
|
+
* n: ?number,
|
|
878
917
|
* position: ?number,
|
|
879
918
|
* attribute: ?string
|
|
880
919
|
* }}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shaka-player",
|
|
3
3
|
"description": "DASH/EME video player library",
|
|
4
|
-
"version": "4.9.
|
|
4
|
+
"version": "4.9.23",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -31,12 +31,12 @@
|
|
|
31
31
|
"eslint-plugin-shaka-rules": "file:./build/eslint-plugin-shaka-rules",
|
|
32
32
|
"esprima": "^4.0.1",
|
|
33
33
|
"fontfaceonload": "^1.0.2",
|
|
34
|
-
"google-closure-compiler-java": "^
|
|
35
|
-
"google-closure-deps": "^
|
|
34
|
+
"google-closure-compiler-java": "^20240317.0.0",
|
|
35
|
+
"google-closure-deps": "^20230802.0.0",
|
|
36
36
|
"google-closure-library": "^20221102.0.0",
|
|
37
37
|
"htmlhint": "^1.1.3",
|
|
38
38
|
"jasmine-ajax": "^4.0.0",
|
|
39
|
-
"jimp": "^0.
|
|
39
|
+
"jimp": "^0.22.12",
|
|
40
40
|
"js-yaml": "^4.1.0",
|
|
41
41
|
"jsdoc": "github:joeyparrish/jsdoc#2ca85bb6",
|
|
42
42
|
"karma": "github:joeyparrish/karma#shaka-fixes",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"karma-webdriver-launcher": "^1.0.8",
|
|
51
51
|
"lcevc_dec.js": "^1.1.3",
|
|
52
52
|
"less": "^4.2.0",
|
|
53
|
-
"less-plugin-clean-css": "
|
|
53
|
+
"less-plugin-clean-css": "^1.6.0",
|
|
54
54
|
"material-design-lite": "^1.3.0",
|
|
55
55
|
"open-sans-fonts": "^1.6.2",
|
|
56
56
|
"postcss-less": "^6.0.0",
|
package/ui/presentation_time.js
CHANGED
|
@@ -83,7 +83,10 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
|
|
|
83
83
|
const seekRangeSize = seekRange.end - seekRange.start;
|
|
84
84
|
const Utils = shaka.ui.Utils;
|
|
85
85
|
|
|
86
|
-
if (
|
|
86
|
+
if (!isFinite(seekRangeSize)) {
|
|
87
|
+
this.setValue_(this.localization.resolve(shaka.ui.Locales.Ids.LIVE));
|
|
88
|
+
this.currentTime_.disabled = true;
|
|
89
|
+
} else if (this.player.isLive()) {
|
|
87
90
|
// The amount of time we are behind the live edge.
|
|
88
91
|
const behindLive = Math.floor(seekRange.end - displayTime);
|
|
89
92
|
displayTime = Math.max(0, behindLive);
|
|
@@ -259,9 +259,17 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
|
|
|
259
259
|
if (height == 2160) {
|
|
260
260
|
text = '4K';
|
|
261
261
|
}
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
const frameRates = new Set();
|
|
263
|
+
for (const item of tracks) {
|
|
264
|
+
if (item.frameRate) {
|
|
265
|
+
frameRates.add(Math.round(item.frameRate));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (frameRates.size > 1) {
|
|
269
|
+
const frameRate = track.frameRate;
|
|
270
|
+
if (frameRate && (frameRate >= 50 || frameRate <= 20)) {
|
|
271
|
+
text += Math.round(track.frameRate);
|
|
272
|
+
}
|
|
265
273
|
}
|
|
266
274
|
if (track.hdr == 'PQ' || track.hdr == 'HLG') {
|
|
267
275
|
text += ' (HDR)';
|
package/ui/seek_bar.js
CHANGED
|
@@ -470,7 +470,8 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
|
|
|
470
470
|
const seekRangeSize = seekRange.end - seekRange.start;
|
|
471
471
|
|
|
472
472
|
if (this.player.isLive() &&
|
|
473
|
-
seekRangeSize < shaka.ui.Constants.MIN_SEEK_WINDOW_TO_SHOW_SEEKBAR
|
|
473
|
+
(seekRangeSize < shaka.ui.Constants.MIN_SEEK_WINDOW_TO_SHOW_SEEKBAR ||
|
|
474
|
+
!isFinite(seekRangeSize))) {
|
|
474
475
|
return false;
|
|
475
476
|
}
|
|
476
477
|
|