shaka-player 4.10.2 → 4.10.4

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.
@@ -108,7 +108,8 @@ shaka.ads.InterstitialAdManager = class {
108
108
  const interstitials = Array.from(this.interstitials_);
109
109
  const seekRange = this.basePlayer_.seekRange();
110
110
  for (const interstitial of interstitials) {
111
- if ((seekRange.start - interstitial.startTime) >= 1) {
111
+ const comparisonTime = interstitial.endTime || interstitial.startTime;
112
+ if ((seekRange.start - comparisonTime) >= 1) {
112
113
  if (this.preloadManagerInterstitials_.has(interstitial)) {
113
114
  const preloadManager =
114
115
  // eslint-disable-next-line no-await-in-loop
@@ -646,12 +647,12 @@ shaka.ads.InterstitialAdManager = class {
646
647
  const dataAsJson =
647
648
  /** @type {!shaka.ads.InterstitialAdManager.AssetsList} */ (
648
649
  JSON.parse(data));
649
- for (const asset of dataAsJson.ASSETS) {
650
- if (asset.URI) {
650
+ for (const asset of dataAsJson['ASSETS']) {
651
+ if (asset['URI']) {
651
652
  interstitialsAd.push({
652
653
  startTime: interstitial.startTime,
653
654
  endTime: interstitial.endTime,
654
- uri: asset.URI,
655
+ uri: asset['URI'],
655
656
  isSkippable,
656
657
  canJump,
657
658
  resumeOffset,
@@ -1019,7 +1019,7 @@ shaka.hls.HlsParser = class {
1019
1019
  if (!segments.length) {
1020
1020
  return defaultBasicInfo;
1021
1021
  }
1022
- const segment = this.getAvailableSegment_(segments);
1022
+ const {segment, segmentIndex} = this.getAvailableSegment_(segments);
1023
1023
  const segmentUris = segment.getUris();
1024
1024
  const segmentUri = segmentUris[0];
1025
1025
  const parsedUri = new goog.Uri(segmentUri);
@@ -1044,6 +1044,10 @@ shaka.hls.HlsParser = class {
1044
1044
  const initResponse = await this.makeNetworkRequest_(
1045
1045
  initSegmentRequest, requestType, {type: initType});
1046
1046
  initData = initResponse.data;
1047
+ if (initSegmentRef.aesKey) {
1048
+ initData = await shaka.media.SegmentUtils.aesDecrypt(
1049
+ initData, initSegmentRef.aesKey, 0);
1050
+ }
1047
1051
 
1048
1052
  initMimeType = initResponse.headers['content-type'];
1049
1053
  if (initMimeType) {
@@ -1058,6 +1062,11 @@ shaka.hls.HlsParser = class {
1058
1062
  const type = shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT;
1059
1063
  const response = await this.makeNetworkRequest_(
1060
1064
  segmentRequest, requestType, {type});
1065
+ let data = response.data;
1066
+ if (segment.aesKey) {
1067
+ data = await shaka.media.SegmentUtils.aesDecrypt(
1068
+ data, segment.aesKey, segmentIndex);
1069
+ }
1061
1070
 
1062
1071
  let contentMimeType = response.headers['content-type'];
1063
1072
  if (contentMimeType) {
@@ -1085,9 +1094,9 @@ shaka.hls.HlsParser = class {
1085
1094
  ];
1086
1095
 
1087
1096
  if (shaka.util.TsParser.probe(
1088
- shaka.util.BufferUtils.toUint8(response.data))) {
1097
+ shaka.util.BufferUtils.toUint8(data))) {
1089
1098
  const basicInfo =
1090
- shaka.media.SegmentUtils.getBasicInfoFromTs(response.data);
1099
+ shaka.media.SegmentUtils.getBasicInfoFromTs(data);
1091
1100
  if (basicInfo) {
1092
1101
  return basicInfo;
1093
1102
  }
@@ -1095,7 +1104,7 @@ shaka.hls.HlsParser = class {
1095
1104
  validMp4MimeType.includes(contentMimeType) ||
1096
1105
  (initMimeType && validMp4MimeType.includes(initMimeType))) {
1097
1106
  const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromMp4(
1098
- initData, response.data);
1107
+ initData, data);
1099
1108
  if (basicInfo) {
1100
1109
  return basicInfo;
1101
1110
  }
@@ -1579,7 +1588,7 @@ shaka.hls.HlsParser = class {
1579
1588
  videoLayout = videoLayout || 'CH-MONO';
1580
1589
 
1581
1590
  const streamInfos = this.createStreamInfosForVariantTags_(tags,
1582
- mediaTags, resolution, frameRate, bandwidth);
1591
+ mediaTags, resolution, frameRate);
1583
1592
 
1584
1593
  goog.asserts.assert(streamInfos.audio.length ||
1585
1594
  streamInfos.video.length, 'We should have created a stream!');
@@ -1607,12 +1616,10 @@ shaka.hls.HlsParser = class {
1607
1616
  * @param {!Array.<!shaka.hls.Tag>} mediaTags
1608
1617
  * @param {?string} resolution
1609
1618
  * @param {?string} frameRate
1610
- * @param {number} bandwidth
1611
1619
  * @return {!shaka.hls.HlsParser.StreamInfos}
1612
1620
  * @private
1613
1621
  */
1614
- createStreamInfosForVariantTags_(
1615
- tags, mediaTags, resolution, frameRate, bandwidth) {
1622
+ createStreamInfosForVariantTags_(tags, mediaTags, resolution, frameRate) {
1616
1623
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
1617
1624
 
1618
1625
  /** @type {shaka.hls.HlsParser.StreamInfos} */
@@ -1747,9 +1754,6 @@ shaka.hls.HlsParser = class {
1747
1754
  if (globalGroupId) {
1748
1755
  streamInfo.stream.groupId = globalGroupId;
1749
1756
  }
1750
- if (!streamInfos.length) {
1751
- streamInfo.stream.bandwidth = bandwidth;
1752
- }
1753
1757
  res[streamInfo.stream.type] = [streamInfo];
1754
1758
  }
1755
1759
  return res;
@@ -1971,6 +1975,12 @@ shaka.hls.HlsParser = class {
1971
1975
  videoStream.drmInfos = drmInfos;
1972
1976
  videoStream.keyIds = keyIds;
1973
1977
  }
1978
+ if (videoStream && !audioStream) {
1979
+ videoStream.bandwidth = bandwidth;
1980
+ }
1981
+ if (!videoStream && audioStream) {
1982
+ audioStream.bandwidth = bandwidth;
1983
+ }
1974
1984
  const audioDrmInfos = audioInfo ? audioInfo.stream.drmInfos : null;
1975
1985
  const videoDrmInfos = videoInfo ? videoInfo.stream.drmInfos : null;
1976
1986
  const videoStreamUri =
@@ -4224,7 +4234,7 @@ shaka.hls.HlsParser = class {
4224
4234
 
4225
4235
  /**
4226
4236
  * @param {!Array.<!shaka.media.SegmentReference>} segments
4227
- * @return {!shaka.media.SegmentReference}
4237
+ * @return {{segment: !shaka.media.SegmentReference, segmentIndex: number}}
4228
4238
  * @private
4229
4239
  */
4230
4240
  getAvailableSegment_(segments) {
@@ -4241,7 +4251,7 @@ shaka.hls.HlsParser = class {
4241
4251
  segmentIndex ++;
4242
4252
  segment = segments[segmentIndex];
4243
4253
  }
4244
- return segment;
4254
+ return {segment, segmentIndex};
4245
4255
  }
4246
4256
 
4247
4257
  /**
@@ -4257,7 +4267,7 @@ shaka.hls.HlsParser = class {
4257
4267
  const HlsParser = shaka.hls.HlsParser;
4258
4268
  const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
4259
4269
 
4260
- const segment = this.getAvailableSegment_(segments);
4270
+ const {segment} = this.getAvailableSegment_(segments);
4261
4271
 
4262
4272
  if (segment.status == shaka.media.SegmentReference.Status.MISSING) {
4263
4273
  return this.guessMimeTypeFallback_(contentType);
@@ -151,6 +151,15 @@ shaka.media.MediaSourceEngine = class {
151
151
 
152
152
  /** @private {?shaka.util.TsParser} */
153
153
  this.tsParser_ = null;
154
+
155
+ /** @private {?number} */
156
+ this.firstVideoTimestamp_ = null;
157
+
158
+ /** @private {?number} */
159
+ this.firstAudioTimestamp_ = null;
160
+
161
+ /** @private {!shaka.util.PublicPromise.<number>} */
162
+ this.audioCompensation_ = new shaka.util.PublicPromise();
154
163
  }
155
164
 
156
165
  /**
@@ -924,6 +933,24 @@ shaka.media.MediaSourceEngine = class {
924
933
  const timestamp = this.getTimestampAndDispatchMetadata_(
925
934
  contentType, data, reference, mimeType, timestampOffset);
926
935
  if (timestamp != null) {
936
+ if (this.firstVideoTimestamp_ == null &&
937
+ contentType == ContentType.VIDEO) {
938
+ this.firstVideoTimestamp_ = timestamp;
939
+ if (this.firstAudioTimestamp_ != null) {
940
+ const compensation =
941
+ this.firstVideoTimestamp_ - this.firstAudioTimestamp_;
942
+ this.audioCompensation_.resolve(compensation);
943
+ }
944
+ }
945
+ if (this.firstAudioTimestamp_ == null &&
946
+ contentType == ContentType.AUDIO) {
947
+ this.firstAudioTimestamp_ = timestamp;
948
+ if (this.firstVideoTimestamp_ != null) {
949
+ const compensation =
950
+ this.firstVideoTimestamp_ - this.firstAudioTimestamp_;
951
+ this.audioCompensation_.resolve(compensation);
952
+ }
953
+ }
927
954
  const calculatedTimestampOffset = reference.startTime - timestamp;
928
955
  const timestampOffsetDifference =
929
956
  Math.abs(timestampOffset - calculatedTimestampOffset);
@@ -992,7 +1019,19 @@ shaka.media.MediaSourceEngine = class {
992
1019
  // and are either performing an unbuffered seek or handling an automatic
993
1020
  // adaptation, we need to set a new timestampOffset on the sourceBuffer.
994
1021
  if (seeked || adaptation) {
995
- const timestampOffset = reference.startTime;
1022
+ let timestampOffset = reference.startTime;
1023
+ // Audio and video may not be aligned, so we will compensate for audio
1024
+ // if necessary.
1025
+ if (this.manifestType_ == shaka.media.ManifestParser.HLS &&
1026
+ !this.needSplitMuxedContent_ &&
1027
+ contentType == ContentType.AUDIO &&
1028
+ this.sourceBuffers_[ContentType.VIDEO]) {
1029
+ const compensation = await this.audioCompensation_;
1030
+ // Only apply compensation if the difference is greater than 100ms
1031
+ if (Math.abs(compensation) > 0.1) {
1032
+ timestampOffset -= compensation;
1033
+ }
1034
+ }
996
1035
  // The logic to call abort() before setting the timestampOffset is
997
1036
  // extended during unbuffered seeks or automatic adaptations; it is
998
1037
  // possible for the append state to be PARSING_MEDIA_SEGMENT from the
@@ -18,6 +18,7 @@ goog.require('shaka.media.VideoWrapper');
18
18
  goog.require('shaka.util.EventManager');
19
19
  goog.require('shaka.util.IReleasable');
20
20
  goog.require('shaka.util.MediaReadyState');
21
+ goog.require('shaka.util.Platform');
21
22
  goog.require('shaka.util.Timer');
22
23
  goog.requireType('shaka.media.PresentationTimeline');
23
24
 
@@ -420,12 +421,20 @@ shaka.media.MediaSourcePlayhead = class {
420
421
 
421
422
  const gapLimit = shaka.media.GapJumpingController.BROWSER_GAP_TOLERANCE;
422
423
  if (Math.abs(targetTime - currentTime) > gapLimit) {
423
- // You can only seek like this every so often. This is to prevent an
424
- // infinite loop on systems where changing currentTime takes a significant
425
- // amount of time (e.g. Chromecast).
426
- const time = Date.now() / 1000;
427
- if (!this.lastCorrectiveSeek_ || this.lastCorrectiveSeek_ < time - 1) {
428
- this.lastCorrectiveSeek_ = time;
424
+ let canCorrectiveSeek = false;
425
+ if (shaka.util.Platform.isSeekingSlow()) {
426
+ // You can only seek like this every so often. This is to prevent an
427
+ // infinite loop on systems where changing currentTime takes a
428
+ // significant amount of time (e.g. Chromecast).
429
+ const time = Date.now() / 1000;
430
+ if (!this.lastCorrectiveSeek_ || this.lastCorrectiveSeek_ < time - 1) {
431
+ this.lastCorrectiveSeek_ = time;
432
+ canCorrectiveSeek = true;
433
+ }
434
+ } else {
435
+ canCorrectiveSeek = true;
436
+ }
437
+ if (canCorrectiveSeek) {
429
438
  this.videoWrapper_.setTime(targetTime);
430
439
  return;
431
440
  }
@@ -218,21 +218,18 @@ shaka.media.SegmentUtils = class {
218
218
 
219
219
  const genericVideoBox = (box) => {
220
220
  baseBox = box.name;
221
- Mp4Parser.visualSampleEntry(box);
221
+ const parsedVisualSampleEntryBox =
222
+ shaka.util.Mp4BoxParsers.visualSampleEntry(box.reader);
223
+ width = String(parsedVisualSampleEntryBox.width);
224
+ height = String(parsedVisualSampleEntryBox.height);
225
+ if (box.reader.hasMoreData()) {
226
+ Mp4Parser.children(box);
227
+ }
222
228
  };
223
229
 
224
230
  new Mp4Parser()
225
231
  .box('moov', Mp4Parser.children)
226
232
  .box('trak', Mp4Parser.children)
227
- .fullBox('tkhd', (box) => {
228
- goog.asserts.assert(
229
- box.version != null,
230
- 'TKHD is a full box and should have a valid version.');
231
- const parsedTKHDBox = shaka.util.Mp4BoxParsers.parseTKHD(
232
- box.reader, box.version);
233
- height = String(parsedTKHDBox.height);
234
- width = String(parsedTKHDBox.width);
235
- })
236
233
  .box('mdia', Mp4Parser.children)
237
234
  .fullBox('mdhd', (box) => {
238
235
  goog.asserts.assert(
@@ -537,6 +534,47 @@ shaka.media.SegmentUtils = class {
537
534
  .parse(data, /* partialOkay= */ true);
538
535
  return defaultKID;
539
536
  }
537
+
538
+ /**
539
+ * @param {!BufferSource} rawResult
540
+ * @param {shaka.extern.aesKey} aesKey
541
+ * @param {number} position
542
+ * @return {!Promise.<!BufferSource>}
543
+ */
544
+ static async aesDecrypt(rawResult, aesKey, position) {
545
+ const key = aesKey;
546
+ if (!key.cryptoKey) {
547
+ goog.asserts.assert(key.fetchKey, 'If AES cryptoKey was not ' +
548
+ 'preloaded, fetchKey function should be provided');
549
+ await key.fetchKey();
550
+ goog.asserts.assert(key.cryptoKey, 'AES cryptoKey should now be set');
551
+ }
552
+ let iv = key.iv;
553
+ if (!iv) {
554
+ iv = shaka.util.BufferUtils.toUint8(new ArrayBuffer(16));
555
+ let sequence = key.firstMediaSequenceNumber + position;
556
+ for (let i = iv.byteLength - 1; i >= 0; i--) {
557
+ iv[i] = sequence & 0xff;
558
+ sequence >>= 8;
559
+ }
560
+ }
561
+ let algorithm;
562
+ if (aesKey.blockCipherMode == 'CBC') {
563
+ algorithm = {
564
+ name: 'AES-CBC',
565
+ iv,
566
+ };
567
+ } else {
568
+ algorithm = {
569
+ name: 'AES-CTR',
570
+ counter: iv,
571
+ // NIST SP800-38A standard suggests that the counter should occupy half
572
+ // of the counter block
573
+ length: 64,
574
+ };
575
+ }
576
+ return window.crypto.subtle.decrypt(algorithm, key.cryptoKey, rawResult);
577
+ }
540
578
  };
541
579
 
542
580
 
@@ -18,9 +18,9 @@ goog.require('shaka.media.MediaSourceEngine');
18
18
  goog.require('shaka.media.SegmentIterator');
19
19
  goog.require('shaka.media.SegmentReference');
20
20
  goog.require('shaka.media.SegmentPrefetch');
21
+ goog.require('shaka.media.SegmentUtils');
21
22
  goog.require('shaka.net.Backoff');
22
23
  goog.require('shaka.net.NetworkingEngine');
23
- goog.require('shaka.util.BufferUtils');
24
24
  goog.require('shaka.util.DelayedTick');
25
25
  goog.require('shaka.util.Destroyer');
26
26
  goog.require('shaka.util.Error');
@@ -769,25 +769,16 @@ shaka.media.StreamingEngine = class {
769
769
  const mediaState = this.mediaStates_.get(type);
770
770
  const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState);
771
771
 
772
- let segment = null;
773
- if (mediaState.segmentIterator) {
774
- segment = mediaState.segmentIterator.current();
775
- }
776
- if (mediaState.segmentPrefetch) {
777
- mediaState.segmentPrefetch.resetPosition();
778
- }
779
- if (mediaState.type === ContentType.AUDIO) {
780
- for (const prefetch of this.audioPrefetchMap_.values()) {
781
- prefetch.resetPosition();
772
+ if (!newTimeIsBuffered(type)) {
773
+ if (mediaState.segmentPrefetch) {
774
+ mediaState.segmentPrefetch.resetPosition();
775
+ }
776
+ if (mediaState.type === ContentType.AUDIO) {
777
+ for (const prefetch of this.audioPrefetchMap_.values()) {
778
+ prefetch.resetPosition();
779
+ }
782
780
  }
783
- }
784
- // Only reset the iterator if we seek outside the current segment.
785
- if (!segment || segment.startTime > presentationTime ||
786
- segment.endTime < presentationTime) {
787
781
  mediaState.segmentIterator = null;
788
- }
789
-
790
- if (!newTimeIsBuffered(type)) {
791
782
  const bufferEnd =
792
783
  this.playerInterface_.mediaSourceEngine.bufferEnd(type);
793
784
  const somethingBuffered = bufferEnd != null;
@@ -1400,7 +1391,7 @@ shaka.media.StreamingEngine = class {
1400
1391
 
1401
1392
  if (mediaState.segmentPrefetch && mediaState.segmentIterator &&
1402
1393
  !this.audioPrefetchMap_.has(mediaState.stream)) {
1403
- mediaState.segmentPrefetch.evict(presentationTime);
1394
+ mediaState.segmentPrefetch.evict(reference.startTime);
1404
1395
  mediaState.segmentPrefetch.prefetchSegmentsByTime(reference.startTime);
1405
1396
  }
1406
1397
 
@@ -1758,48 +1749,6 @@ shaka.media.StreamingEngine = class {
1758
1749
  }
1759
1750
  }
1760
1751
 
1761
- /**
1762
- * @param {!BufferSource} rawResult
1763
- * @param {shaka.extern.aesKey} aesKey
1764
- * @param {number} position
1765
- * @return {!Promise.<!BufferSource>} finalResult
1766
- * @private
1767
- */
1768
- async aesDecrypt_(rawResult, aesKey, position) {
1769
- const key = aesKey;
1770
- if (!key.cryptoKey) {
1771
- goog.asserts.assert(key.fetchKey, 'If AES cryptoKey was not ' +
1772
- 'preloaded, fetchKey function should be provided');
1773
- await key.fetchKey();
1774
- goog.asserts.assert(key.cryptoKey, 'AES cryptoKey should now be set');
1775
- }
1776
- let iv = key.iv;
1777
- if (!iv) {
1778
- iv = shaka.util.BufferUtils.toUint8(new ArrayBuffer(16));
1779
- let sequence = key.firstMediaSequenceNumber + position;
1780
- for (let i = iv.byteLength - 1; i >= 0; i--) {
1781
- iv[i] = sequence & 0xff;
1782
- sequence >>= 8;
1783
- }
1784
- }
1785
- let algorithm;
1786
- if (aesKey.blockCipherMode == 'CBC') {
1787
- algorithm = {
1788
- name: 'AES-CBC',
1789
- iv,
1790
- };
1791
- } else {
1792
- algorithm = {
1793
- name: 'AES-CTR',
1794
- counter: iv,
1795
- // NIST SP800-38A standard suggests that the counter should occupy half
1796
- // of the counter block
1797
- length: 64,
1798
- };
1799
- }
1800
- return window.crypto.subtle.decrypt(algorithm, key.cryptoKey, rawResult);
1801
- }
1802
-
1803
1752
 
1804
1753
  /**
1805
1754
  * Clear per-stream error states and retry any failed streams.
@@ -2576,7 +2525,8 @@ shaka.media.StreamingEngine = class {
2576
2525
  mediaState.operation = null;
2577
2526
  let result = response.data;
2578
2527
  if (reference.aesKey) {
2579
- result = await this.aesDecrypt_(result, reference.aesKey, position);
2528
+ result = await shaka.media.SegmentUtils.aesDecrypt(
2529
+ result, reference.aesKey, position);
2580
2530
  }
2581
2531
  return result;
2582
2532
  }
package/lib/player.js CHANGED
@@ -4862,13 +4862,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4862
4862
  */
4863
4863
  selectVariantTrack(track, clearBuffer = false, safeMargin = 0) {
4864
4864
  if (this.manifest_ && this.streamingEngine_) {
4865
- if (this.config_.abr.enabled) {
4866
- shaka.log.alwaysWarn('Changing tracks while abr manager is enabled ' +
4867
- 'will likely result in the selected track ' +
4868
- 'being overriden. Consider disabling abr before ' +
4869
- 'calling selectVariantTrack().');
4870
- }
4871
-
4872
4865
  const variant = this.manifest_.variants.find(
4873
4866
  (variant) => variant.id == track.id);
4874
4867
  if (!variant) {
@@ -4885,6 +4878,17 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4885
4878
  return;
4886
4879
  }
4887
4880
 
4881
+ const active = this.streamingEngine_.getCurrentVariant();
4882
+ if (this.config_.abr.enabled && (active.video != variant.video ||
4883
+ (active.audio && variant.audio &&
4884
+ active.audio.language == variant.audio.language &&
4885
+ active.audio.channelsCount == variant.audio.channelsCount))) {
4886
+ shaka.log.alwaysWarn('Changing tracks while abr manager is enabled ' +
4887
+ 'will likely result in the selected track ' +
4888
+ 'being overriden. Consider disabling abr before ' +
4889
+ 'calling selectVariantTrack().');
4890
+ }
4891
+
4888
4892
  this.switchVariant_(
4889
4893
  variant, /* fromAdaptation= */ false, clearBuffer, safeMargin);
4890
4894
 
@@ -7809,7 +7813,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
7809
7813
  * @export
7810
7814
  */
7811
7815
  // eslint-disable-next-line no-useless-concat
7812
- shaka.Player.version = 'v4.10.2' + '-uncompiled'; // x-release-please-version
7816
+ shaka.Player.version = 'v4.10.4' + '-uncompiled'; // x-release-please-version
7813
7817
 
7814
7818
  // Initialize the deprecation system using the version string we just set
7815
7819
  // on the player.
package/lib/text/cue.js CHANGED
@@ -5,8 +5,8 @@
5
5
  */
6
6
 
7
7
  goog.provide('shaka.text.Cue');
8
- goog.provide('shaka.text.CueRegion');
9
8
 
9
+ goog.require('shaka.text.CueRegion');
10
10
  goog.require('shaka.util.ArrayUtils');
11
11
 
12
12
 
@@ -553,119 +553,3 @@ shaka.text.Cue.textDecoration = {
553
553
  'LINE_THROUGH': 'lineThrough',
554
554
  'OVERLINE': 'overline',
555
555
  };
556
-
557
-
558
- /**
559
- * @export
560
- */
561
- shaka.text.CueRegion = class {
562
- /** */
563
- constructor() {
564
- const CueRegion = shaka.text.CueRegion;
565
-
566
- /**
567
- * Region identifier.
568
- * @type {string}
569
- * @export
570
- */
571
- this.id = '';
572
-
573
- /**
574
- * The X offset to start the rendering area in viewportAnchorUnits of the
575
- * video width.
576
- * @type {number}
577
- * @export
578
- */
579
- this.viewportAnchorX = 0;
580
-
581
- /**
582
- * The X offset to start the rendering area in viewportAnchorUnits of the
583
- * video height.
584
- * @type {number}
585
- * @export
586
- */
587
- this.viewportAnchorY = 0;
588
-
589
- /**
590
- * The X offset to start the rendering area in percentage (0-100) of this
591
- * region width.
592
- * @type {number}
593
- * @export
594
- */
595
- this.regionAnchorX = 0;
596
-
597
- /**
598
- * The Y offset to start the rendering area in percentage (0-100) of the
599
- * region height.
600
- * @type {number}
601
- * @export
602
- */
603
- this.regionAnchorY = 0;
604
-
605
- /**
606
- * The width of the rendering area in widthUnits.
607
- * @type {number}
608
- * @export
609
- */
610
- this.width = 100;
611
-
612
- /**
613
- * The width of the rendering area in heightUnits.
614
- * @type {number}
615
- * @export
616
- */
617
- this.height = 100;
618
-
619
- /**
620
- * The units (percentage, pixels or lines) the region height is in.
621
- * @type {shaka.text.CueRegion.units}
622
- * @export
623
- */
624
- this.heightUnits = CueRegion.units.PERCENTAGE;
625
-
626
- /**
627
- * The units (percentage or pixels) the region width is in.
628
- * @type {shaka.text.CueRegion.units}
629
- * @export
630
- */
631
- this.widthUnits = CueRegion.units.PERCENTAGE;
632
-
633
- /**
634
- * The units (percentage or pixels) the region viewportAnchors are in.
635
- * @type {shaka.text.CueRegion.units}
636
- * @export
637
- */
638
- this.viewportAnchorUnits = CueRegion.units.PERCENTAGE;
639
-
640
- /**
641
- * If scroll=UP, it means that cues in the region will be added to the
642
- * bottom of the region and will push any already displayed cues in the
643
- * region up. Otherwise (scroll=NONE) cues will stay fixed at the location
644
- * they were first painted in.
645
- * @type {shaka.text.CueRegion.scrollMode}
646
- * @export
647
- */
648
- this.scroll = CueRegion.scrollMode.NONE;
649
- }
650
- };
651
-
652
-
653
- /**
654
- * @enum {number}
655
- * @export
656
- */
657
- shaka.text.CueRegion.units = {
658
- 'PX': 0,
659
- 'PERCENTAGE': 1,
660
- 'LINES': 2,
661
- };
662
-
663
-
664
- /**
665
- * @enum {string}
666
- * @export
667
- */
668
- shaka.text.CueRegion.scrollMode = {
669
- 'NONE': '',
670
- 'UP': 'up',
671
- };