shaka-player 4.10.2 → 4.10.3

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
@@ -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
@@ -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(
package/lib/player.js CHANGED
@@ -7809,7 +7809,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
7809
7809
  * @export
7810
7810
  */
7811
7811
  // eslint-disable-next-line no-useless-concat
7812
- shaka.Player.version = 'v4.10.2' + '-uncompiled'; // x-release-please-version
7812
+ shaka.Player.version = 'v4.10.3' + '-uncompiled'; // x-release-please-version
7813
7813
 
7814
7814
  // Initialize the deprecation system using the version string we just set
7815
7815
  // 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
- };
@@ -0,0 +1,123 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.text.CueRegion');
8
+
9
+
10
+ /**
11
+ * @export
12
+ */
13
+ shaka.text.CueRegion = class {
14
+ /** */
15
+ constructor() {
16
+ const CueRegion = shaka.text.CueRegion;
17
+
18
+ /**
19
+ * Region identifier.
20
+ * @type {string}
21
+ * @export
22
+ */
23
+ this.id = '';
24
+
25
+ /**
26
+ * The X offset to start the rendering area in viewportAnchorUnits of the
27
+ * video width.
28
+ * @type {number}
29
+ * @export
30
+ */
31
+ this.viewportAnchorX = 0;
32
+
33
+ /**
34
+ * The X offset to start the rendering area in viewportAnchorUnits of the
35
+ * video height.
36
+ * @type {number}
37
+ * @export
38
+ */
39
+ this.viewportAnchorY = 0;
40
+
41
+ /**
42
+ * The X offset to start the rendering area in percentage (0-100) of this
43
+ * region width.
44
+ * @type {number}
45
+ * @export
46
+ */
47
+ this.regionAnchorX = 0;
48
+
49
+ /**
50
+ * The Y offset to start the rendering area in percentage (0-100) of the
51
+ * region height.
52
+ * @type {number}
53
+ * @export
54
+ */
55
+ this.regionAnchorY = 0;
56
+
57
+ /**
58
+ * The width of the rendering area in widthUnits.
59
+ * @type {number}
60
+ * @export
61
+ */
62
+ this.width = 100;
63
+
64
+ /**
65
+ * The width of the rendering area in heightUnits.
66
+ * @type {number}
67
+ * @export
68
+ */
69
+ this.height = 100;
70
+
71
+ /**
72
+ * The units (percentage, pixels or lines) the region height is in.
73
+ * @type {shaka.text.CueRegion.units}
74
+ * @export
75
+ */
76
+ this.heightUnits = CueRegion.units.PERCENTAGE;
77
+
78
+ /**
79
+ * The units (percentage or pixels) the region width is in.
80
+ * @type {shaka.text.CueRegion.units}
81
+ * @export
82
+ */
83
+ this.widthUnits = CueRegion.units.PERCENTAGE;
84
+
85
+ /**
86
+ * The units (percentage or pixels) the region viewportAnchors are in.
87
+ * @type {shaka.text.CueRegion.units}
88
+ * @export
89
+ */
90
+ this.viewportAnchorUnits = CueRegion.units.PERCENTAGE;
91
+
92
+ /**
93
+ * If scroll=UP, it means that cues in the region will be added to the
94
+ * bottom of the region and will push any already displayed cues in the
95
+ * region up. Otherwise (scroll=NONE) cues will stay fixed at the location
96
+ * they were first painted in.
97
+ * @type {shaka.text.CueRegion.scrollMode}
98
+ * @export
99
+ */
100
+ this.scroll = CueRegion.scrollMode.NONE;
101
+ }
102
+ };
103
+
104
+
105
+ /**
106
+ * @enum {number}
107
+ * @export
108
+ */
109
+ shaka.text.CueRegion.units = {
110
+ 'PX': 0,
111
+ 'PERCENTAGE': 1,
112
+ 'LINES': 2,
113
+ };
114
+
115
+
116
+ /**
117
+ * @enum {string}
118
+ * @export
119
+ */
120
+ shaka.text.CueRegion.scrollMode = {
121
+ 'NONE': '',
122
+ 'UP': 'up',
123
+ };
@@ -468,7 +468,9 @@ shaka.text.UITextDisplayer = class {
468
468
 
469
469
  const regionElement = shaka.util.Dom.createHTMLElement('span');
470
470
 
471
+ const linesUnit = shaka.text.CueRegion.units.LINES;
471
472
  const percentageUnit = shaka.text.CueRegion.units.PERCENTAGE;
473
+ const pixelUnit = shaka.text.CueRegion.units.PX;
472
474
  const heightUnit = region.heightUnits == percentageUnit ? '%' : 'px';
473
475
  const widthUnit = region.widthUnits == percentageUnit ? '%' : 'px';
474
476
  const viewportAnchorUnit =
@@ -479,12 +481,14 @@ shaka.text.UITextDisplayer = class {
479
481
 
480
482
  regionElement.style.position = 'absolute';
481
483
 
482
- const linesUnit = shaka.text.CueRegion.units.LINES;
483
- if (region.heightUnits === linesUnit && region.widthUnits === linesUnit) {
484
+ if (region.heightUnits === linesUnit) {
484
485
  regionElement.style.height = region.height * lineHeightMultiple + '%';
485
- regionElement.style.width = region.width * lineWidthMultiple + '%';
486
486
  } else {
487
487
  regionElement.style.height = region.height + heightUnit;
488
+ }
489
+ if (region.widthUnits === linesUnit) {
490
+ regionElement.style.width = region.width * lineWidthMultiple + '%';
491
+ } else {
488
492
  regionElement.style.width = region.width + widthUnit;
489
493
  }
490
494
 
@@ -504,6 +508,19 @@ shaka.text.UITextDisplayer = class {
504
508
  regionElement.style.left = region.viewportAnchorX -
505
509
  region.regionAnchorX * region.width / 100 + viewportAnchorUnit;
506
510
  }
511
+ if (region.heightUnits !== pixelUnit &&
512
+ region.widthUnits !== pixelUnit &&
513
+ region.viewportAnchorUnits !== pixelUnit) {
514
+ // Clip region
515
+ const top = parseInt(regionElement.style.top.slice(0, -1), 10) || 0;
516
+ const left = parseInt(regionElement.style.left.slice(0, -1), 10) || 0;
517
+ const height = parseInt(regionElement.style.height.slice(0, -1), 10) || 0;
518
+ const width = parseInt(regionElement.style.width.slice(0, -1), 10) || 0;
519
+ const realTop = Math.max(0, Math.min(100 - height, top));
520
+ const realLeft = Math.max(0, Math.min(100 - width, left));
521
+ regionElement.style.top = realTop + '%';
522
+ regionElement.style.left = realLeft + '%';
523
+ }
507
524
 
508
525
  regionElement.style.display = 'flex';
509
526
  regionElement.style.flexDirection = 'column';
@@ -274,6 +274,35 @@ shaka.util.Mp4BoxParsers = class {
274
274
  };
275
275
  }
276
276
 
277
+
278
+ /**
279
+ * Parses an visual sample entry box.
280
+ * @param {!shaka.util.DataViewReader} reader
281
+ * @return {!shaka.util.ParsedVisualSampleEntryBox}
282
+ */
283
+ static visualSampleEntry(reader) {
284
+ // Skip 6 reserved bytes.
285
+ // Skip 2-byte data reference index.
286
+ // Skip 16 more reserved bytes.
287
+ reader.skip(24);
288
+ // 4 bytes for width/height.
289
+ const width = reader.readUint16();
290
+ const height = reader.readUint16();
291
+ // Skip 8 bytes for horizontal/vertical resolution.
292
+ // Skip 4 more reserved bytes (0)
293
+ // Skip 2-byte frame count.
294
+ // Skip 32-byte compressor name (length byte, then name, then 0-padding).
295
+ // Skip 2-byte depth.
296
+ // Skip 2 more reserved bytes (0xff)
297
+ reader.skip(50);
298
+
299
+ return {
300
+ width: width,
301
+ height: height,
302
+ };
303
+ }
304
+
305
+
277
306
  /**
278
307
  * Parses an audio sample entry box.
279
308
  * @param {!shaka.util.DataViewReader} reader
@@ -866,6 +895,19 @@ shaka.util.ParsedFRMABox;
866
895
  */
867
896
  shaka.util.ParsedTENCBox;
868
897
 
898
+ /**
899
+ * @typedef {{
900
+ * width: number,
901
+ * height: number
902
+ * }}
903
+ *
904
+ * @property {number} width
905
+ * @property {number} height
906
+ *
907
+ * @exportDoc
908
+ */
909
+ shaka.util.ParsedVisualSampleEntryBox;
910
+
869
911
  /**
870
912
  * @typedef {{
871
913
  * channelCount: number,
@@ -727,15 +727,17 @@ shaka.util.Platform = class {
727
727
  'screen size 1920x1080.');
728
728
  }
729
729
  } else if (Platform.isXboxOne()) {
730
- const protectionCapabilities =
731
- new Windows.Media.Protection.ProtectionCapabilities();
732
- const protectionResult =
733
- Windows.Media.Protection.ProtectionCapabilityResult;
734
- // isTypeSupported may return "maybe", which means the operation is not
735
- // completed. This means we need to retry
736
- // https://learn.microsoft.com/en-us/uwp/api/windows.media.protection.protectioncapabilityresult?view=winrt-22621
737
- let result = null;
730
+ maxResolution.width = 1920;
731
+ maxResolution.height = 1080;
738
732
  try {
733
+ const protectionCapabilities =
734
+ new Windows.Media.Protection.ProtectionCapabilities();
735
+ const protectionResult =
736
+ Windows.Media.Protection.ProtectionCapabilityResult;
737
+ // isTypeSupported may return "maybe", which means the operation is not
738
+ // completed. This means we need to retry
739
+ // https://learn.microsoft.com/en-us/uwp/api/windows.media.protection.protectioncapabilityresult?view=winrt-22621
740
+ let result = null;
739
741
  const type =
740
742
  'video/mp4;codecs="hvc1,mp4a";features="decode-res-x=3840,' +
741
743
  'decode-res-y=2160,decode-bitrate=20000,decode-fps=30,' +
@@ -745,15 +747,13 @@ shaka.util.Platform = class {
745
747
  do {
746
748
  result = protectionCapabilities.isTypeSupported(type, keySystem);
747
749
  } while (result === protectionResult.maybe);
750
+ if (result === protectionResult.probably) {
751
+ maxResolution.width = 3840;
752
+ maxResolution.height = 2160;
753
+ }
748
754
  } catch (e) {
749
- result = protectionResult.notSupported;
750
- }
751
- if (result === protectionResult.probably) {
752
- maxResolution.width = 3840;
753
- maxResolution.height = 2160;
754
- } else {
755
- maxResolution.width = 1920;
756
- maxResolution.height = 1080;
755
+ shaka.log.alwaysWarn('Xbox: Error detecting screen size, default ' +
756
+ 'screen size 1920x1080.');
757
757
  }
758
758
  } else if (Platform.isWebOS()) {
759
759
  try {
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.10.2",
4
+ "version": "4.10.3",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
package/ui/seek_bar.js CHANGED
@@ -396,15 +396,14 @@ shaka.ui.SeekBar = class extends shaka.ui.RangeElement {
396
396
  // Post-roll ads are marked as starting at -1 in CS IMA ads.
397
397
  if (point.start == -1 && !point.end) {
398
398
  postRollAd = true;
399
+ continue;
399
400
  }
400
401
  // Filter point within the seek range. For points with no endpoint
401
402
  // (client side ads) check that the start point is within range.
402
- if (point.start >= seekRange.start && point.start < seekRange.end) {
403
- if (point.end && point.end > seekRange.end) {
404
- continue;
405
- }
406
-
407
- const startDist = point.start - seekRange.start;
403
+ if ((!point.end && point.start >= seekRange.start) ||
404
+ (typeof point.end == 'number' && point.end > seekRange.start)) {
405
+ const startDist =
406
+ Math.max(point.start, seekRange.start) - seekRange.start;
408
407
  const startFrac = (startDist / seekRangeSize) || 0;
409
408
  // For points with no endpoint assume a 1% length: not too much,
410
409
  // but enough to be visible on the timeline.