shaka-player 4.9.21 → 4.9.22
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 +1 -1
- package/dist/locales.js +36 -36
- package/dist/shaka-player.compiled.debug.js +357 -355
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +1135 -1133
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +249 -247
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +1292 -1290
- 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/media/closed_caption_parser.js +1 -1
- package/lib/media/media_source_engine.js +4 -4
- package/lib/media/streaming_engine.js +92 -18
- package/lib/media/video_wrapper.js +2 -1
- package/lib/player.js +1 -1
- package/lib/text/ui_text_displayer.js +15 -12
- package/lib/text/vtt_text_parser.js +16 -1
- package/lib/util/platform.js +13 -2
- package/lib/util/stream_utils.js +37 -0
- package/package.json +3 -3
package/externs/xbox.js
CHANGED
|
@@ -41,3 +41,23 @@ Windows.Media.Protection.ProtectionCapabilityResult = {
|
|
|
41
41
|
maybe: 'Maybe',
|
|
42
42
|
probably: 'Probably',
|
|
43
43
|
};
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
/** @const */
|
|
47
|
+
var chrome = {};
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/** @const */
|
|
51
|
+
chrome.webview = {};
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
/** @const */
|
|
55
|
+
chrome.webview.hostObjects = {};
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
/** @const */
|
|
59
|
+
chrome.webview.hostObjects.sync = {};
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
/** @const */
|
|
63
|
+
chrome.webview.hostObjects.sync.Windows = Windows;
|
|
@@ -107,7 +107,7 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
107
107
|
|
|
108
108
|
/** @private {shaka.util.Timer} */
|
|
109
109
|
this.resizeObserverTimer_ = new shaka.util.Timer(() => {
|
|
110
|
-
if (this.config_.restrictToElementSize) {
|
|
110
|
+
if (this.enabled_ && this.config_.restrictToElementSize) {
|
|
111
111
|
const chosenVariant = this.chooseVariant();
|
|
112
112
|
if (chosenVariant) {
|
|
113
113
|
this.switch_(chosenVariant, this.config_.clearBufferSwitch,
|
|
@@ -99,8 +99,8 @@ shaka.media.ClosedCaptionParser = class {
|
|
|
99
99
|
// This is necessary when a new Period comes in DASH or a discontinuity
|
|
100
100
|
// in HLS.
|
|
101
101
|
this.reset();
|
|
102
|
-
this.ceaParser_.init(initSegment);
|
|
103
102
|
}
|
|
103
|
+
this.ceaParser_.init(initSegment);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
/**
|
|
@@ -2012,7 +2012,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2012
2012
|
return false;
|
|
2013
2013
|
}
|
|
2014
2014
|
const MimeUtils = shaka.util.MimeUtils;
|
|
2015
|
-
const currentCodec = MimeUtils.
|
|
2015
|
+
const currentCodec = MimeUtils.getNormalizedCodec(
|
|
2016
2016
|
MimeUtils.getCodecs(this.sourceBufferTypes_[contentType]));
|
|
2017
2017
|
const currentBasicType = MimeUtils.getBasicType(
|
|
2018
2018
|
this.sourceBufferTypes_[contentType]);
|
|
@@ -2054,7 +2054,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2054
2054
|
}
|
|
2055
2055
|
}
|
|
2056
2056
|
|
|
2057
|
-
const newCodec = MimeUtils.
|
|
2057
|
+
const newCodec = MimeUtils.getNormalizedCodec(
|
|
2058
2058
|
MimeUtils.getCodecs(newMimeType));
|
|
2059
2059
|
const newBasicType = MimeUtils.getBasicType(newMimeType);
|
|
2060
2060
|
|
|
@@ -2113,7 +2113,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2113
2113
|
return false;
|
|
2114
2114
|
}
|
|
2115
2115
|
const MimeUtils = shaka.util.MimeUtils;
|
|
2116
|
-
const currentCodec = MimeUtils.
|
|
2116
|
+
const currentCodec = MimeUtils.getNormalizedCodec(
|
|
2117
2117
|
MimeUtils.getCodecs(this.sourceBufferTypes_[contentType]));
|
|
2118
2118
|
const currentBasicType = MimeUtils.getBasicType(
|
|
2119
2119
|
this.sourceBufferTypes_[contentType]);
|
|
@@ -2140,7 +2140,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
2140
2140
|
}
|
|
2141
2141
|
}
|
|
2142
2142
|
|
|
2143
|
-
const newCodec = MimeUtils.
|
|
2143
|
+
const newCodec = MimeUtils.getNormalizedCodec(
|
|
2144
2144
|
MimeUtils.getCodecs(newMimeType));
|
|
2145
2145
|
const newBasicType = MimeUtils.getBasicType(newMimeType);
|
|
2146
2146
|
|
|
@@ -15,9 +15,10 @@ goog.require('shaka.log');
|
|
|
15
15
|
goog.require('shaka.media.InitSegmentReference');
|
|
16
16
|
goog.require('shaka.media.ManifestParser');
|
|
17
17
|
goog.require('shaka.media.MediaSourceEngine');
|
|
18
|
+
goog.require('shaka.media.SegmentIndex');
|
|
18
19
|
goog.require('shaka.media.SegmentIterator');
|
|
19
|
-
goog.require('shaka.media.SegmentReference');
|
|
20
20
|
goog.require('shaka.media.SegmentPrefetch');
|
|
21
|
+
goog.require('shaka.media.SegmentReference');
|
|
21
22
|
goog.require('shaka.net.Backoff');
|
|
22
23
|
goog.require('shaka.net.NetworkingEngine');
|
|
23
24
|
goog.require('shaka.util.BufferUtils');
|
|
@@ -73,6 +74,20 @@ shaka.media.StreamingEngine = class {
|
|
|
73
74
|
/** @private {?shaka.extern.StreamingConfiguration} */
|
|
74
75
|
this.config_ = null;
|
|
75
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Retains deferred SegmentIndex objects for streams which were switched
|
|
79
|
+
* away from during an ongoing fetchAndAppend_().
|
|
80
|
+
* They are released and cleared from this map when the next onUpdate_() for
|
|
81
|
+
* a stream's content type occurs.
|
|
82
|
+
* This is because at that point, it is guaranteed no logic is actively
|
|
83
|
+
* using information for these old streams.
|
|
84
|
+
*
|
|
85
|
+
* Lastly, the operations are stored in arrays in the off chance multiple
|
|
86
|
+
* ABR switches happen during an ongoing fetchAndAppend_().
|
|
87
|
+
* @private {!Map.<string, !Array.<?shaka.media.SegmentIndex>>}
|
|
88
|
+
*/
|
|
89
|
+
this.deferredCloseSegmentIndex_ = new Map();
|
|
90
|
+
|
|
76
91
|
/** @private {number} */
|
|
77
92
|
this.bufferingGoalScale_ = 1;
|
|
78
93
|
|
|
@@ -161,6 +176,7 @@ shaka.media.StreamingEngine = class {
|
|
|
161
176
|
state.segmentPrefetch.clearAll();
|
|
162
177
|
state.segmentPrefetch = null;
|
|
163
178
|
}
|
|
179
|
+
this.handleDeferredCloseSegmentIndexes_(state);
|
|
164
180
|
}
|
|
165
181
|
for (const prefetch of this.audioPrefetchMap_.values()) {
|
|
166
182
|
prefetch.clearAll();
|
|
@@ -170,6 +186,7 @@ shaka.media.StreamingEngine = class {
|
|
|
170
186
|
|
|
171
187
|
this.mediaStates_.clear();
|
|
172
188
|
this.audioPrefetchMap_.clear();
|
|
189
|
+
this.deferredCloseSegmentIndex_.clear();
|
|
173
190
|
|
|
174
191
|
this.playerInterface_ = null;
|
|
175
192
|
this.manifest_ = null;
|
|
@@ -504,6 +521,29 @@ shaka.media.StreamingEngine = class {
|
|
|
504
521
|
}
|
|
505
522
|
|
|
506
523
|
|
|
524
|
+
/**
|
|
525
|
+
* Handles deferred releases of old SegmentIndexes for the mediaState's
|
|
526
|
+
* content type from a previous update.
|
|
527
|
+
* @param {!shaka.media.StreamingEngine.MediaState_} mediaState
|
|
528
|
+
* @private
|
|
529
|
+
*/
|
|
530
|
+
handleDeferredCloseSegmentIndexes_(mediaState) {
|
|
531
|
+
for (const [key, value] of this.deferredCloseSegmentIndex_.entries()) {
|
|
532
|
+
const streamId = /** @type {string} */ (key);
|
|
533
|
+
const segmentIndexArray =
|
|
534
|
+
/** @type {!Array.<?shaka.media.SegmentIndex>} */ (value);
|
|
535
|
+
if (streamId.includes(mediaState.type)) {
|
|
536
|
+
for (const segmentIndex of segmentIndexArray) {
|
|
537
|
+
if (segmentIndex) {
|
|
538
|
+
segmentIndex.release();
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
this.deferredCloseSegmentIndex_.delete(streamId);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
|
|
507
547
|
/**
|
|
508
548
|
* Switches to the given Stream. |stream| may be from any Variant.
|
|
509
549
|
*
|
|
@@ -572,11 +612,30 @@ shaka.media.StreamingEngine = class {
|
|
|
572
612
|
fullMimeType, this.manifest_.sequenceMode, stream.external);
|
|
573
613
|
}
|
|
574
614
|
|
|
575
|
-
// Releases the segmentIndex of the old stream.
|
|
615
|
+
// Releases the segmentIndex of the old stream if safe to do so.
|
|
576
616
|
// Do not close segment indexes we are prefetching.
|
|
577
617
|
if (!this.audioPrefetchMap_.has(mediaState.stream)) {
|
|
578
618
|
if (mediaState.stream.closeSegmentIndex) {
|
|
579
|
-
mediaState.
|
|
619
|
+
if (mediaState.performingUpdate) {
|
|
620
|
+
const oldStreamTag =
|
|
621
|
+
shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
622
|
+
// The ongoing update is still using the old stream's segment
|
|
623
|
+
// reference information.
|
|
624
|
+
// If we close the old stream now, the update will not complete
|
|
625
|
+
// correctly.
|
|
626
|
+
// onUpdate_() will resume the closeSegmentIndex() operation for the
|
|
627
|
+
// old stream when the update has finished.
|
|
628
|
+
if (!this.deferredCloseSegmentIndex_.has(oldStreamTag)) {
|
|
629
|
+
this.deferredCloseSegmentIndex_.set(
|
|
630
|
+
oldStreamTag, [mediaState.stream.segmentIndex]);
|
|
631
|
+
} else {
|
|
632
|
+
// We switched from stream A -> B -> back to A.
|
|
633
|
+
this.deferredCloseSegmentIndex_.get(oldStreamTag).push(
|
|
634
|
+
mediaState.stream.segmentIndex);
|
|
635
|
+
}
|
|
636
|
+
} else {
|
|
637
|
+
mediaState.stream.closeSegmentIndex();
|
|
638
|
+
}
|
|
580
639
|
}
|
|
581
640
|
}
|
|
582
641
|
|
|
@@ -584,8 +643,8 @@ shaka.media.StreamingEngine = class {
|
|
|
584
643
|
mediaState.segmentIterator = null;
|
|
585
644
|
mediaState.adaptation = !!adaptation;
|
|
586
645
|
|
|
587
|
-
const
|
|
588
|
-
shaka.log.debug('switch: switching to Stream ' +
|
|
646
|
+
const newStreamTag = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
647
|
+
shaka.log.debug('switch: switching to Stream ' + newStreamTag);
|
|
589
648
|
|
|
590
649
|
if (clearBuffer) {
|
|
591
650
|
if (mediaState.clearingBuffer) {
|
|
@@ -1169,6 +1228,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1169
1228
|
return;
|
|
1170
1229
|
}
|
|
1171
1230
|
|
|
1231
|
+
this.handleDeferredCloseSegmentIndexes_(mediaState);
|
|
1232
|
+
|
|
1172
1233
|
// Make sure the segment index exists. If not, create the segment index.
|
|
1173
1234
|
if (!mediaState.stream.segmentIndex) {
|
|
1174
1235
|
const thisStream = mediaState.stream;
|
|
@@ -1343,6 +1404,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1343
1404
|
return this.config_.updateIntervalSeconds / 2;
|
|
1344
1405
|
}
|
|
1345
1406
|
|
|
1407
|
+
// Lack of segment iterator is the best indicator stream has changed.
|
|
1408
|
+
const streamChanged = !mediaState.segmentIterator;
|
|
1346
1409
|
const reference = this.getSegmentReferenceNeeded_(
|
|
1347
1410
|
mediaState, presentationTime, bufferEnd);
|
|
1348
1411
|
if (!reference) {
|
|
@@ -1352,6 +1415,14 @@ shaka.media.StreamingEngine = class {
|
|
|
1352
1415
|
// a SegmentReference eventually.
|
|
1353
1416
|
return this.config_.updateIntervalSeconds;
|
|
1354
1417
|
}
|
|
1418
|
+
// Get media state adaptation and reset this value. By guarding it during
|
|
1419
|
+
// actual stream change we ensure it won't be cleaned by accident on regular
|
|
1420
|
+
// append.
|
|
1421
|
+
let adaptation = false;
|
|
1422
|
+
if (streamChanged && mediaState.adaptation) {
|
|
1423
|
+
adaptation = true;
|
|
1424
|
+
mediaState.adaptation = false;
|
|
1425
|
+
}
|
|
1355
1426
|
|
|
1356
1427
|
// Do not let any one stream get far ahead of any other.
|
|
1357
1428
|
let minTimeNeeded = Infinity;
|
|
@@ -1390,7 +1461,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1390
1461
|
mediaState.segmentPrefetch.prefetchSegmentsByTime(reference.startTime);
|
|
1391
1462
|
}
|
|
1392
1463
|
|
|
1393
|
-
const p = this.fetchAndAppend_(mediaState, presentationTime, reference
|
|
1464
|
+
const p = this.fetchAndAppend_(mediaState, presentationTime, reference,
|
|
1465
|
+
adaptation);
|
|
1394
1466
|
p.catch(() => {}); // TODO(#1993): Handle asynchronous errors.
|
|
1395
1467
|
return null;
|
|
1396
1468
|
}
|
|
@@ -1512,9 +1584,10 @@ shaka.media.StreamingEngine = class {
|
|
|
1512
1584
|
* @param {!shaka.media.StreamingEngine.MediaState_} mediaState
|
|
1513
1585
|
* @param {number} presentationTime
|
|
1514
1586
|
* @param {!shaka.media.SegmentReference} reference
|
|
1587
|
+
* @param {boolean} adaptation
|
|
1515
1588
|
* @private
|
|
1516
1589
|
*/
|
|
1517
|
-
async fetchAndAppend_(mediaState, presentationTime, reference) {
|
|
1590
|
+
async fetchAndAppend_(mediaState, presentationTime, reference, adaptation) {
|
|
1518
1591
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
1519
1592
|
const StreamingEngine = shaka.media.StreamingEngine;
|
|
1520
1593
|
const logPrefix = StreamingEngine.logPrefix_(mediaState);
|
|
@@ -1543,7 +1616,7 @@ shaka.media.StreamingEngine = class {
|
|
|
1543
1616
|
shaka.util.Error.Category.NETWORK,
|
|
1544
1617
|
shaka.util.Error.Code.SEGMENT_MISSING);
|
|
1545
1618
|
}
|
|
1546
|
-
await this.initSourceBuffer_(mediaState, reference);
|
|
1619
|
+
await this.initSourceBuffer_(mediaState, reference, adaptation);
|
|
1547
1620
|
this.destroyer_.ensureNotDestroyed();
|
|
1548
1621
|
if (this.fatalError_) {
|
|
1549
1622
|
return;
|
|
@@ -1598,7 +1671,7 @@ shaka.media.StreamingEngine = class {
|
|
|
1598
1671
|
remaining = remaining.subarray(offset);
|
|
1599
1672
|
await this.append_(
|
|
1600
1673
|
mediaState, presentationTime, stream, reference, dataToAppend,
|
|
1601
|
-
/* isChunkedData= */ true);
|
|
1674
|
+
/* isChunkedData= */ true, adaptation);
|
|
1602
1675
|
|
|
1603
1676
|
if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
|
|
1604
1677
|
mediaState.segmentPrefetch.prefetchSegmentsByTime(
|
|
@@ -1637,8 +1710,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1637
1710
|
return;
|
|
1638
1711
|
}
|
|
1639
1712
|
|
|
1640
|
-
await this.append_(
|
|
1641
|
-
|
|
1713
|
+
await this.append_(mediaState, presentationTime, stream, reference,
|
|
1714
|
+
result, /* chunkedData= */ false, adaptation);
|
|
1642
1715
|
}
|
|
1643
1716
|
|
|
1644
1717
|
if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
|
|
@@ -1669,8 +1742,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1669
1742
|
return;
|
|
1670
1743
|
}
|
|
1671
1744
|
|
|
1672
|
-
await this.append_(
|
|
1673
|
-
|
|
1745
|
+
await this.append_(mediaState, presentationTime, stream, reference,
|
|
1746
|
+
result, /* chunkedData= */ false, adaptation);
|
|
1674
1747
|
}
|
|
1675
1748
|
|
|
1676
1749
|
this.destroyer_.ensureNotDestroyed();
|
|
@@ -1911,10 +1984,11 @@ shaka.media.StreamingEngine = class {
|
|
|
1911
1984
|
*
|
|
1912
1985
|
* @param {shaka.media.StreamingEngine.MediaState_} mediaState
|
|
1913
1986
|
* @param {!shaka.media.SegmentReference} reference
|
|
1987
|
+
* @param {boolean} adaptation
|
|
1914
1988
|
* @return {!Promise}
|
|
1915
1989
|
* @private
|
|
1916
1990
|
*/
|
|
1917
|
-
async initSourceBuffer_(mediaState, reference) {
|
|
1991
|
+
async initSourceBuffer_(mediaState, reference, adaptation) {
|
|
1918
1992
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
1919
1993
|
const MimeUtils = shaka.util.MimeUtils;
|
|
1920
1994
|
const StreamingEngine = shaka.media.StreamingEngine;
|
|
@@ -2109,7 +2183,8 @@ shaka.media.StreamingEngine = class {
|
|
|
2109
2183
|
mediaState.type, initSegment);
|
|
2110
2184
|
await this.playerInterface_.mediaSourceEngine.appendBuffer(
|
|
2111
2185
|
mediaState.type, initSegment, /* reference= */ null,
|
|
2112
|
-
mediaState.stream, hasClosedCaptions
|
|
2186
|
+
mediaState.stream, hasClosedCaptions, mediaState.seeked,
|
|
2187
|
+
adaptation);
|
|
2113
2188
|
} catch (error) {
|
|
2114
2189
|
mediaState.lastInitSegmentReference = null;
|
|
2115
2190
|
throw error;
|
|
@@ -2147,11 +2222,12 @@ shaka.media.StreamingEngine = class {
|
|
|
2147
2222
|
* @param {!shaka.media.SegmentReference} reference
|
|
2148
2223
|
* @param {BufferSource} segment
|
|
2149
2224
|
* @param {boolean=} isChunkedData
|
|
2225
|
+
* @param {boolean=} adaptation
|
|
2150
2226
|
* @return {!Promise}
|
|
2151
2227
|
* @private
|
|
2152
2228
|
*/
|
|
2153
2229
|
async append_(mediaState, presentationTime, stream, reference, segment,
|
|
2154
|
-
isChunkedData = false) {
|
|
2230
|
+
isChunkedData = false, adaptation = false) {
|
|
2155
2231
|
const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
2156
2232
|
|
|
2157
2233
|
const hasClosedCaptions = stream.closedCaptions &&
|
|
@@ -2195,8 +2271,6 @@ shaka.media.StreamingEngine = class {
|
|
|
2195
2271
|
// appendBuffer() call.
|
|
2196
2272
|
const seeked = mediaState.seeked;
|
|
2197
2273
|
mediaState.seeked = false;
|
|
2198
|
-
const adaptation = mediaState.adaptation;
|
|
2199
|
-
mediaState.adaptation = false;
|
|
2200
2274
|
|
|
2201
2275
|
await this.playerInterface_.beforeAppendSegment(mediaState.type, segment);
|
|
2202
2276
|
await this.playerInterface_.mediaSourceEngine.appendBuffer(
|
|
@@ -275,7 +275,8 @@ shaka.media.VideoWrapper.PlayheadMover = class {
|
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
// Yay! We were successful.
|
|
278
|
-
if (this.mediaElement_.currentTime != this.originTime_
|
|
278
|
+
if (this.mediaElement_.currentTime != this.originTime_ ||
|
|
279
|
+
this.mediaElement_.currentTime === this.targetTime_) {
|
|
279
280
|
this.timer_.stop();
|
|
280
281
|
return;
|
|
281
282
|
}
|
package/lib/player.js
CHANGED
|
@@ -7484,7 +7484,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
7484
7484
|
* @export
|
|
7485
7485
|
*/
|
|
7486
7486
|
// eslint-disable-next-line no-useless-concat
|
|
7487
|
-
shaka.Player.version = 'v4.9.
|
|
7487
|
+
shaka.Player.version = 'v4.9.22' + '-uncompiled'; // x-release-please-version
|
|
7488
7488
|
|
|
7489
7489
|
// Initialize the deprecation system using the version string we just set
|
|
7490
7490
|
// on the player.
|
|
@@ -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 &&
|
|
@@ -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
|
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.22",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -36,7 +36,7 @@
|
|
|
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",
|