shaka-player 4.6.1 → 4.6.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/CONTRIBUTORS +1 -0
  3. package/demo/config.js +5 -0
  4. package/demo/custom.js +2 -0
  5. package/dist/demo.compiled.debug.js +29 -28
  6. package/dist/demo.compiled.debug.map +2 -2
  7. package/dist/demo.compiled.js +29 -28
  8. package/dist/demo.compiled.map +2 -2
  9. package/dist/locales.js +32 -32
  10. package/dist/shaka-player.compiled.d.ts +1 -0
  11. package/dist/shaka-player.compiled.debug.d.ts +1 -0
  12. package/dist/shaka-player.compiled.debug.externs.js +1 -0
  13. package/dist/shaka-player.compiled.debug.js +274 -270
  14. package/dist/shaka-player.compiled.debug.map +3 -3
  15. package/dist/shaka-player.compiled.externs.js +1 -0
  16. package/dist/shaka-player.compiled.js +862 -860
  17. package/dist/shaka-player.compiled.map +3 -3
  18. package/dist/shaka-player.ui.d.ts +1 -0
  19. package/dist/shaka-player.ui.debug.d.ts +1 -0
  20. package/dist/shaka-player.ui.debug.externs.js +1 -0
  21. package/dist/shaka-player.ui.debug.js +188 -184
  22. package/dist/shaka-player.ui.debug.map +3 -3
  23. package/dist/shaka-player.ui.externs.js +1 -0
  24. package/dist/shaka-player.ui.js +1000 -997
  25. package/dist/shaka-player.ui.map +3 -3
  26. package/docs/tutorials/lcevc.md +2 -2
  27. package/externs/lcevc.js +6 -0
  28. package/externs/shaka/codecs.js +6 -0
  29. package/externs/shaka/transmuxer.js +6 -0
  30. package/lib/cea/cea608_memory.js +13 -2
  31. package/lib/dash/dash_parser.js +2 -2
  32. package/lib/hls/hls_parser.js +2 -1
  33. package/lib/media/media_source_engine.js +11 -5
  34. package/lib/media/segment_reference.js +2 -1
  35. package/lib/media/streaming_engine.js +1 -1
  36. package/lib/player.js +1 -1
  37. package/lib/text/ui_text_displayer.js +50 -4
  38. package/lib/transmuxer/ts_transmuxer.js +15 -0
  39. package/lib/util/error.js +6 -0
  40. package/lib/util/mp4_box_parsers.js +39 -5
  41. package/package.json +2 -2
  42. package/test/cea/cea608_memory_unit.js +8 -8
  43. package/test/cea/cea_decoder_unit.js +11 -11
  44. package/test/demo/demo_unit.js +0 -3
  45. package/test/test/assets/audio-xhe-aac.mp4 +0 -0
  46. package/test/util/mp4_box_parsers_unit.js +36 -0
  47. package/ui/presentation_time.js +5 -5
@@ -24,7 +24,7 @@ LCEVC Decoder library needs to be included in the HTML page:
24
24
  ```
25
25
  - Or use `unpkg.com` for latest LCEVC Decoder libraries.
26
26
  ```html
27
- <script src="https://unpkg.com/lcevc_dec.js@1.0.0/dist/lcevc_dec.min.js"></script>
27
+ <script src="https://unpkg.com/lcevc_dec.js@1.0.1/dist/lcevc_dec.min.js"></script>
28
28
  ```
29
29
 
30
30
  Configuration to enable LCEVC enhancement:
@@ -45,7 +45,7 @@ Sample setup using the Shaka Player UI library:
45
45
  <link rel="stylesheet" href="dist/controls.css" />
46
46
 
47
47
  <!-- LCEVC decoder compiled library -->
48
- <script src="https://unpkg.com/lcevc_dec.js@1.0.0/dist/lcevc_dec.min.js"></script>
48
+ <script src="https://unpkg.com/lcevc_dec.js@1.0.1/dist/lcevc_dec.min.js"></script>
49
49
 
50
50
  <!-- Application source: -->
51
51
  <script src="app.js"></script>
package/externs/lcevc.js CHANGED
@@ -1,3 +1,9 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
1
7
  /**
2
8
  * @fileoverview Externs for LcevcDec
3
9
  * compiler.
@@ -1,3 +1,9 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
1
7
  /**
2
8
  * @typedef {{
3
9
  * data: !Uint8Array,
@@ -1,3 +1,9 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2023 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
1
7
  /**
2
8
  * @fileoverview Externs for Transmuxer.
3
9
  *
@@ -84,8 +84,10 @@ shaka.cea.Cea608Memory = class {
84
84
  startTime, endTime, /* payload= */ '');
85
85
  topLevelCue.lineInterpretation =
86
86
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
87
- const maxRows = shaka.cea.Cea608Memory.CC_ROWS + 1;
88
- topLevelCue.line = this.row_ / maxRows * 100;
87
+ const line = shaka.cea.Cea608Memory.ROW_TO_LINE_CONVERSION_.get(this.row_);
88
+ if (line) {
89
+ topLevelCue.line = line;
90
+ }
89
91
  return shaka.cea.CeaUtils.getParsedCaption(
90
92
  topLevelCue, stream, this.rows_, startTime, endTime);
91
93
  }
@@ -320,3 +322,12 @@ shaka.cea.Cea608Memory.CharSet.ExtendedPortugueseGerman = new Map([
320
322
  [0x38, 'Å'], [0x39, 'å'], [0x3a, 'Ø'], [0x3b, 'ø'], [0x3c, '┌'], [0x3d, '┐'],
321
323
  [0x3e, '└'], [0x3f, '┘'],
322
324
  ]);
325
+
326
+ /**
327
+ * @private @const {!Map<number, number>}
328
+ */
329
+ shaka.cea.Cea608Memory.ROW_TO_LINE_CONVERSION_ = new Map([
330
+ [1, 10], [2, 15.33], [3, 20.66], [4, 26], [5, 31.33], [6, 36.66], [7, 42],
331
+ [8, 47.33], [9, 52.66], [10, 58], [11, 63.33], [12, 68.66], [13, 74],
332
+ [14, 79.33], [15, 84.66],
333
+ ]);
@@ -1433,11 +1433,11 @@ shaka.dash.DashParser = class {
1433
1433
  'Must have Segment* with non-text streams.');
1434
1434
 
1435
1435
  const duration = context.periodInfo.duration || 0;
1436
+ const getBaseUris = context.representation.getBaseUris;
1436
1437
  streamInfo = {
1437
1438
  generateSegmentIndex: () => {
1438
- const baseUris = context.representation.getBaseUris();
1439
1439
  return Promise.resolve(shaka.media.SegmentIndex.forSingleSegment(
1440
- periodStart, duration, baseUris));
1440
+ periodStart, duration, getBaseUris()));
1441
1441
  },
1442
1442
  };
1443
1443
  }
@@ -934,7 +934,8 @@ shaka.hls.HlsParser = class {
934
934
  return basicInfo;
935
935
  }
936
936
  } else if (extension == 'mp4' || extension == 'cmfv' ||
937
- contentMimeType == 'video/mp4' || contentMimeType == 'audio/mp4' ||
937
+ extension == 'm4s' || contentMimeType == 'video/mp4' ||
938
+ contentMimeType == 'audio/mp4' ||
938
939
  contentMimeType == 'video/iso.segment') {
939
940
  const basicInfo = shaka.media.SegmentUtils.getBasicInfoFromMp4(
940
941
  initData, response.data);
@@ -1661,6 +1661,7 @@ shaka.media.MediaSourceEngine = class {
1661
1661
  if (shaka.media.Capabilities.isChangeTypeSupported()) {
1662
1662
  if (this.transmuxers_[contentType]) {
1663
1663
  this.transmuxers_[contentType].destroy();
1664
+ delete this.transmuxers_[contentType];
1664
1665
  }
1665
1666
  if (transmuxer) {
1666
1667
  this.transmuxers_[contentType] = transmuxer;
@@ -1859,8 +1860,8 @@ shaka.media.MediaSourceEngine = class {
1859
1860
  }
1860
1861
  }
1861
1862
 
1862
- const newCodec = MimeUtils.getCodecBase(
1863
- MimeUtils.getCodecs(newMimeType));
1863
+ const newAllCodecs = MimeUtils.getCodecs(newMimeType);
1864
+ const newCodec = MimeUtils.getCodecBase(newAllCodecs);
1864
1865
  const newBasicType = MimeUtils.getBasicType(newMimeType);
1865
1866
 
1866
1867
  // Current/new codecs base and basic type match then no need to switch
@@ -1868,10 +1869,15 @@ shaka.media.MediaSourceEngine = class {
1868
1869
  return false;
1869
1870
  }
1870
1871
 
1871
- if (this.config_.codecSwitchingStrategy ===
1872
+ let allowChangeType = true;
1873
+ if (this.needSplitMuxedContent_ || (newAllCodecs.split(',').length &&
1874
+ transmuxer && !this.transmuxers_[contentType])) {
1875
+ allowChangeType = false;
1876
+ }
1877
+
1878
+ if (allowChangeType && this.config_.codecSwitchingStrategy ===
1872
1879
  shaka.config.CodecSwitchingStrategy.SMOOTH &&
1873
- shaka.media.Capabilities.isChangeTypeSupported() &&
1874
- !this.needSplitMuxedContent_) {
1880
+ shaka.media.Capabilities.isChangeTypeSupported()) {
1875
1881
  await this.changeType(contentType, newMimeType, transmuxer);
1876
1882
  } else {
1877
1883
  if (transmuxer) {
@@ -128,7 +128,8 @@ shaka.media.InitSegmentReference = class {
128
128
  } else {
129
129
  return reference1.getStartByte() == reference2.getStartByte() &&
130
130
  reference1.getEndByte() == reference2.getEndByte() &&
131
- ArrayUtils.equal(reference1.getUris(), reference2.getUris()) &&
131
+ ArrayUtils.equal(
132
+ reference1.getUris().sort(), reference2.getUris().sort()) &&
132
133
  BufferUtils.equal(reference1.getSegmentData(),
133
134
  reference2.getSegmentData());
134
135
  }
@@ -1792,7 +1792,7 @@ shaka.media.StreamingEngine = class {
1792
1792
  reference.initSegmentReference, mediaState.lastInitSegmentReference)) {
1793
1793
  mediaState.lastInitSegmentReference = reference.initSegmentReference;
1794
1794
 
1795
- if (reference.initSegmentReference) {
1795
+ if (reference.isIndependent() && reference.initSegmentReference) {
1796
1796
  shaka.log.v1(logPrefix, 'fetching init segment');
1797
1797
 
1798
1798
  const fetchInit =
package/lib/player.js CHANGED
@@ -6781,7 +6781,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6781
6781
  * @export
6782
6782
  */
6783
6783
  // eslint-disable-next-line no-useless-concat
6784
- shaka.Player.version = 'v4.6.1' + '-uncompiled'; // x-release-please-version
6784
+ shaka.Player.version = 'v4.6.3' + '-uncompiled'; // x-release-please-version
6785
6785
 
6786
6786
  // Initialize the deprecation system using the version string we just set
6787
6787
  // on the player.
@@ -44,6 +44,9 @@ shaka.text.UITextDisplayer = class {
44
44
  /** @private {HTMLElement} */
45
45
  this.videoContainer_ = videoContainer;
46
46
 
47
+ /** @private {?number} */
48
+ this.aspectRatio_ = null;
49
+
47
50
  /** @type {HTMLElement} */
48
51
  this.textContainer_ = shaka.util.Dom.createHTMLElement('div');
49
52
  this.textContainer_.classList.add('shaka-text-container');
@@ -90,6 +93,23 @@ shaka.text.UITextDisplayer = class {
90
93
  this.updateCaptions_(/* forceUpdate= */ true);
91
94
  });
92
95
 
96
+ // From: https://html.spec.whatwg.org/multipage/media.html#dom-video-videowidth
97
+ // Whenever the natural width or natural height of the video changes
98
+ // (including, for example, because the selected video track was changed),
99
+ // if the element's readyState attribute is not HAVE_NOTHING, the user
100
+ // agent must queue a media element task given the media element to fire an
101
+ // event named resize at the media element.
102
+ this.eventManager_.listen(this.video_, 'resize', () => {
103
+ const element = /** @type {!HTMLVideoElement} */ (this.video_);
104
+ const width = element.videoWidth;
105
+ const height = element.videoHeight;
106
+ if (width && height) {
107
+ this.aspectRatio_ = width / height;
108
+ } else {
109
+ this.aspectRatio_ = null;
110
+ }
111
+ });
112
+
93
113
  /** @private {ResizeObserver} */
94
114
  this.resizeObserver_ = null;
95
115
  if ('ResizeObserver' in window) {
@@ -400,6 +420,10 @@ shaka.text.UITextDisplayer = class {
400
420
  */
401
421
  getRegionElement_(cue) {
402
422
  const region = cue.region;
423
+ // from https://dvcs.w3.org/hg/text-tracks/raw-file/default/608toVTT/608toVTT.html#caption-window-size
424
+ // if aspect ratio is 4/3, use that value, otherwise, use the 16:9 value
425
+ const lineWidthMultiple = this.aspectRatio_ === 4/3 ? 2.5 : 1.9;
426
+ const lineHeightMultiple = 5.33;
403
427
 
404
428
  const regionId = this.generateRegionId_(region);
405
429
  if (this.regionElements_.has(regionId)) {
@@ -417,11 +441,33 @@ shaka.text.UITextDisplayer = class {
417
441
  regionElement.id = 'shaka-text-region---' + regionId;
418
442
  regionElement.classList.add('shaka-text-region');
419
443
 
420
- regionElement.style.height = region.height + heightUnit;
421
- regionElement.style.width = region.width + widthUnit;
422
444
  regionElement.style.position = 'absolute';
423
- regionElement.style.top = region.viewportAnchorY + viewportAnchorUnit;
424
- regionElement.style.left = region.viewportAnchorX + viewportAnchorUnit;
445
+
446
+ const linesUnit = shaka.text.CueRegion.units.LINES;
447
+ if (region.heightUnits === linesUnit && region.widthUnits === linesUnit) {
448
+ regionElement.style.height = region.height * lineHeightMultiple + '%';
449
+ regionElement.style.width = region.width * lineWidthMultiple + '%';
450
+ } else {
451
+ regionElement.style.height = region.height + heightUnit;
452
+ regionElement.style.width = region.width + widthUnit;
453
+ }
454
+
455
+ if (region.viewportAnchorUnits === linesUnit) {
456
+ // from https://dvcs.w3.org/hg/text-tracks/raw-file/default/608toVTT/608toVTT.html#positioning-in-cea-708
457
+ let top = region.viewportAnchorY / 75 * 100;
458
+ const windowWidth = this.aspectRatio_ === 4/3 ? 160 : 210;
459
+ let left = region.viewportAnchorX / windowWidth * 100;
460
+ // adjust top and left values based on the region anchor and window size
461
+ top -= region.regionAnchorY * region.height * lineHeightMultiple / 100;
462
+ left -= region.regionAnchorX * region.width * lineWidthMultiple / 100;
463
+ regionElement.style.top = top + '%';
464
+ regionElement.style.left = left + '%';
465
+ } else {
466
+ regionElement.style.top = region.viewportAnchorY -
467
+ region.regionAnchorY * region.height / 100 + viewportAnchorUnit;
468
+ regionElement.style.left = region.viewportAnchorX -
469
+ region.regionAnchorX * region.width / 100 + viewportAnchorUnit;
470
+ }
425
471
 
426
472
  regionElement.style.display = 'flex';
427
473
  regionElement.style.flexDirection = 'column';
@@ -242,6 +242,9 @@ shaka.transmuxer.TsTransmuxer = class {
242
242
  }
243
243
  }
244
244
  } catch (e) {
245
+ if (e && e.code == shaka.util.Error.Code.TRANSMUXING_NO_VIDEO_DATA) {
246
+ return Promise.resolve(new Uint8Array([]));
247
+ }
245
248
  return Promise.reject(e);
246
249
  }
247
250
 
@@ -704,6 +707,12 @@ shaka.transmuxer.TsTransmuxer = class {
704
707
 
705
708
  let nalus = [];
706
709
  const videoData = tsParser.getVideoData();
710
+ if (!videoData.length) {
711
+ throw new shaka.util.Error(
712
+ shaka.util.Error.Severity.CRITICAL,
713
+ shaka.util.Error.Category.MEDIA,
714
+ shaka.util.Error.Code.TRANSMUXING_NO_VIDEO_DATA);
715
+ }
707
716
  for (let i = 0; i < videoData.length; i++) {
708
717
  const pes = videoData[i];
709
718
  const dataNalus = pes.nalus;
@@ -790,6 +799,12 @@ shaka.transmuxer.TsTransmuxer = class {
790
799
 
791
800
  let nalus = [];
792
801
  const videoData = tsParser.getVideoData();
802
+ if (!videoData.length) {
803
+ throw new shaka.util.Error(
804
+ shaka.util.Error.Severity.CRITICAL,
805
+ shaka.util.Error.Category.MEDIA,
806
+ shaka.util.Error.Code.TRANSMUXING_NO_VIDEO_DATA);
807
+ }
793
808
  for (let i = 0; i < videoData.length; i++) {
794
809
  const pes = videoData[i];
795
810
  const dataNalus = pes.nalus;
package/lib/util/error.js CHANGED
@@ -511,6 +511,12 @@ shaka.util.Error.Code = {
511
511
  */
512
512
  'MSS_TRANSMUXING_FAILED': 3022,
513
513
 
514
+ /**
515
+ * An internal error which indicates that transmuxing operation has no video
516
+ * data. This should not be seen by applications.
517
+ */
518
+ 'TRANSMUXING_NO_VIDEO_DATA': 3023,
519
+
514
520
 
515
521
  /**
516
522
  * The Player was unable to guess the manifest type based on file extension
@@ -301,11 +301,45 @@ shaka.util.Mp4BoxParsers = class {
301
301
  */
302
302
  static parseESDS(reader) {
303
303
  let codec = 'mp4a';
304
- reader.skip(11);
305
- codec += '.' + this.toHex_(reader.readUint8());
306
- // this value is only a single digit
307
- codec += '.' +
308
- this.toHex_((reader.readUint8() >>> 2) & 0x3f).replace(/^0/, '');
304
+ let tag;
305
+ let oti;
306
+ while (reader.hasMoreData()) {
307
+ tag = reader.readUint8();
308
+ let byteRead = reader.readUint8();
309
+ while (byteRead & 0x80) {
310
+ byteRead = reader.readUint8();
311
+ }
312
+ if (tag == 0x03) {
313
+ reader.readUint16();
314
+ const flags = reader.readUint8();
315
+ if (flags & 0x80) {
316
+ reader.readUint16();
317
+ }
318
+ if (flags & 0x40) {
319
+ reader.skip(reader.readUint8());
320
+ }
321
+ if (flags & 0x20) {
322
+ reader.readUint16();
323
+ }
324
+ } else if (tag == 0x04) {
325
+ oti = reader.readUint8();
326
+ reader.skip(12);
327
+ } else if (tag == 0x05) {
328
+ break;
329
+ }
330
+ }
331
+ if (oti) {
332
+ codec += '.' + this.toHex_(oti);
333
+ if (tag == 0x05 && reader.hasMoreData()) {
334
+ const firstData = reader.readUint8();
335
+ let audioObjectType = (firstData & 0xF8) >> 3;
336
+ if (audioObjectType === 31 && reader.hasMoreData()) {
337
+ audioObjectType = 32 + ((firstData & 0x7) << 3) +
338
+ ((reader.readUint8() & 0xE0) >> 5);
339
+ }
340
+ codec += '.' + audioObjectType;
341
+ }
342
+ }
309
343
  return {codec};
310
344
  }
311
345
 
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.6.1",
4
+ "version": "4.6.3",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -48,7 +48,7 @@
48
48
  "karma-sourcemap-loader": "^0.3.8",
49
49
  "karma-spec-reporter": "^0.0.34",
50
50
  "karma-webdriver-launcher": "^1.0.8",
51
- "lcevc_dec.js": "^1.0.0",
51
+ "lcevc_dec.js": "^1.0.1",
52
52
  "less": "https://gitpkg.now.sh/joeyparrish/less.js/packages/less?28c63a43",
53
53
  "less-plugin-clean-css": "github:austingardner/less-plugin-clean-css#4e9e77bf",
54
54
  "material-design-lite": "^1.3.0",
@@ -31,7 +31,7 @@ describe('Cea608Memory', () => {
31
31
  const caption = memory.forceEmit(startTime, endTime);
32
32
 
33
33
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
34
- topLevelCue.line = 6.25;
34
+ topLevelCue.line = 10;
35
35
  topLevelCue.lineInterpretation =
36
36
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
37
37
  topLevelCue.nestedCues = [
@@ -82,7 +82,7 @@ describe('Cea608Memory', () => {
82
82
  }
83
83
 
84
84
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
85
- topLevelCue.line = 6.25;
85
+ topLevelCue.line = 10;
86
86
  topLevelCue.lineInterpretation =
87
87
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
88
88
  topLevelCue.nestedCues = [
@@ -119,7 +119,7 @@ describe('Cea608Memory', () => {
119
119
  }
120
120
 
121
121
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
122
- topLevelCue.line = 6.25;
122
+ topLevelCue.line = 10;
123
123
  topLevelCue.lineInterpretation =
124
124
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
125
125
  topLevelCue.nestedCues = [
@@ -173,7 +173,7 @@ describe('Cea608Memory', () => {
173
173
  // ...
174
174
  // So we expect that test\n\ntest is emitted
175
175
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
176
- topLevelCue.line = 37.5;
176
+ topLevelCue.line = 36.66;
177
177
  topLevelCue.lineInterpretation =
178
178
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
179
179
  topLevelCue.nestedCues = [
@@ -217,7 +217,7 @@ describe('Cea608Memory', () => {
217
217
  memory.eraseChar(); // Erase the last 't' from 'testt'
218
218
 
219
219
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
220
- topLevelCue.line = 6.25;
220
+ topLevelCue.line = 10;
221
221
  topLevelCue.lineInterpretation =
222
222
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
223
223
  topLevelCue.nestedCues = [
@@ -291,7 +291,7 @@ describe('Cea608Memory', () => {
291
291
 
292
292
  // Expected text is 's\nt\nt\ne'
293
293
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
294
- topLevelCue.line = 31.25;
294
+ topLevelCue.line = 31.33;
295
295
  topLevelCue.lineInterpretation =
296
296
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
297
297
  topLevelCue.nestedCues = [
@@ -338,7 +338,7 @@ describe('Cea608Memory', () => {
338
338
 
339
339
  // Expected text is 't\ne\ns\nt'
340
340
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
341
- topLevelCue.line = 31.25;
341
+ topLevelCue.line = 31.33;
342
342
  topLevelCue.lineInterpretation =
343
343
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
344
344
  topLevelCue.nestedCues = [
@@ -385,7 +385,7 @@ describe('Cea608Memory', () => {
385
385
 
386
386
  // Expected text is 't\ne\ns\nt'
387
387
  const topLevelCue = new shaka.text.Cue(startTime, endTime, '');
388
- topLevelCue.line = 31.25;
388
+ topLevelCue.line = 31.33;
389
389
  topLevelCue.lineInterpretation =
390
390
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
391
391
  topLevelCue.nestedCues = [
@@ -65,7 +65,7 @@ describe('CeaDecoder', () => {
65
65
 
66
66
  const topLevelCue = new shaka.text.Cue(
67
67
  startTimeCaption1, startTimeCaption2, '');
68
- topLevelCue.line = 81.25;
68
+ topLevelCue.line = 74;
69
69
  topLevelCue.lineInterpretation =
70
70
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
71
71
  topLevelCue.nestedCues = [
@@ -113,7 +113,7 @@ describe('CeaDecoder', () => {
113
113
  // Since there are three style changes, there should be three nested cues.
114
114
  const topLevelCue = new shaka.text.Cue(
115
115
  startTimeCaption1, startTimeCaption2, '');
116
- topLevelCue.line = 6.25;
116
+ topLevelCue.line = 10;
117
117
  topLevelCue.lineInterpretation =
118
118
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
119
119
 
@@ -166,7 +166,7 @@ describe('CeaDecoder', () => {
166
166
  // A single nested cue containing yellow, italicized text.
167
167
  const topLevelCue = new shaka.text.Cue(startTimeCaption1,
168
168
  startTimeCaption2, '');
169
- topLevelCue.line = 12.5;
169
+ topLevelCue.line = 15.33;
170
170
  topLevelCue.lineInterpretation =
171
171
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
172
172
  topLevelCue.nestedCues = [
@@ -208,7 +208,7 @@ describe('CeaDecoder', () => {
208
208
 
209
209
  const topLevelCue = new shaka.text.Cue(startTimeCaption1,
210
210
  startTimeCaption2, '');
211
- topLevelCue.line = 6.25;
211
+ topLevelCue.line = 10;
212
212
  topLevelCue.lineInterpretation =
213
213
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
214
214
  topLevelCue.nestedCues = [
@@ -243,7 +243,7 @@ describe('CeaDecoder', () => {
243
243
 
244
244
  const topLevelCue = new shaka.text.Cue(startTimeCaption1,
245
245
  startTimeCaption2, '');
246
- topLevelCue.line = 6.25;
246
+ topLevelCue.line = 10;
247
247
  topLevelCue.lineInterpretation =
248
248
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
249
249
  topLevelCue.nestedCues = [
@@ -315,7 +315,7 @@ describe('CeaDecoder', () => {
315
315
  // Top level cue corresponding to the first closed caption.
316
316
  const topLevelCue1 = new shaka.text.Cue(
317
317
  /* startTime= */ time1, /* endTime= */ time2, '');
318
- topLevelCue1.line = 93.75;
318
+ topLevelCue1.line = 84.66;
319
319
  topLevelCue1.lineInterpretation =
320
320
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
321
321
  topLevelCue1.nestedCues = [
@@ -326,7 +326,7 @@ describe('CeaDecoder', () => {
326
326
  // Top level cue corresponding to the second closed caption.
327
327
  const topLevelCue2 = new shaka.text.Cue(
328
328
  /* startTime= */ time2, /* endTime= */ time3, '');
329
- topLevelCue2.line = 93.75;
329
+ topLevelCue2.line = 84.66;
330
330
  topLevelCue2.lineInterpretation =
331
331
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
332
332
  topLevelCue2.nestedCues = [
@@ -343,7 +343,7 @@ describe('CeaDecoder', () => {
343
343
  // Top level cue corresponding to the third closed caption.
344
344
  const topLevelCue3 = new shaka.text.Cue(
345
345
  /* startTime= */ time3, /* endTime= */ time4, '');
346
- topLevelCue3.line = 93.75;
346
+ topLevelCue3.line = 84.66;
347
347
  topLevelCue3.lineInterpretation =
348
348
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
349
349
  topLevelCue3.nestedCues = [
@@ -360,7 +360,7 @@ describe('CeaDecoder', () => {
360
360
  // Top level cue corresponding to the fourth closed caption.
361
361
  const topLevelCue4 = new shaka.text.Cue(
362
362
  /* startTime= */ time4, /* endTime= */ time5, '');
363
- topLevelCue4.line = 93.75;
363
+ topLevelCue4.line = 84.66;
364
364
  topLevelCue4.lineInterpretation =
365
365
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
366
366
  topLevelCue4.nestedCues = [
@@ -433,7 +433,7 @@ describe('CeaDecoder', () => {
433
433
  // Top level cue corresponding to the first closed caption.
434
434
  const topLevelCue1 = new shaka.text.Cue(/* startTime= */ 1,
435
435
  /* endTime= */ 2, '');
436
- topLevelCue1.line = 93.75;
436
+ topLevelCue1.line = 84.66;
437
437
  topLevelCue1.lineInterpretation =
438
438
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
439
439
  topLevelCue1.nestedCues = [
@@ -444,7 +444,7 @@ describe('CeaDecoder', () => {
444
444
  // Top level cue corresponding to the second closed caption.
445
445
  const topLevelCue2 = new shaka.text.Cue(/* startTime= */ 2,
446
446
  /* endTime= */ 3, '');
447
- topLevelCue2.line = 25;
447
+ topLevelCue2.line = 26;
448
448
  topLevelCue2.lineInterpretation =
449
449
  shaka.text.Cue.lineInterpretation.PERCENTAGE;
450
450
  topLevelCue2.nestedCues = [
@@ -74,14 +74,11 @@ describe('Demo', () => {
74
74
  function checkConfig(checkValueNameFn) {
75
75
  const configPrimitives = new Set(['number', 'string', 'boolean']);
76
76
  const exceptions = new Set()
77
- .add('preferredVariantRole')
78
77
  .add('playRangeStart')
79
78
  .add('playRangeEnd')
80
79
  .add('manifest.dash.keySystemsByURI')
81
- .add('manifest.hls.mediaPlaylistFullMimeType')
82
80
  .add('manifest.mss.keySystemsBySystemId')
83
81
  .add('drm.keySystemsMapping')
84
- .add('streaming.parsePrftBox')
85
82
  .add('manifest.raiseFatalErrorOnManifestUpdateRequestFailure')
86
83
  .add('drm.persistentSessionOnlinePlayback')
87
84
  .add('drm.persistentSessionsMetadata');
@@ -8,18 +8,24 @@ describe('Mp4BoxParsers', () => {
8
8
  const videoInitSegmentUri = '/base/test/test/assets/sintel-video-init.mp4';
9
9
  const videoSegmentUri = '/base/test/test/assets/sintel-video-segment.mp4';
10
10
 
11
+ const audioInitSegmentXheAacUri = '/base/test/test/assets/audio-xhe-aac.mp4';
12
+
11
13
  /** @type {!ArrayBuffer} */
12
14
  let videoInitSegment;
13
15
  /** @type {!ArrayBuffer} */
14
16
  let videoSegment;
17
+ /** @type {!ArrayBuffer} */
18
+ let audioInitSegmentXheAac;
15
19
 
16
20
  beforeAll(async () => {
17
21
  const responses = await Promise.all([
18
22
  shaka.test.Util.fetch(videoInitSegmentUri),
19
23
  shaka.test.Util.fetch(videoSegmentUri),
24
+ shaka.test.Util.fetch(audioInitSegmentXheAacUri),
20
25
  ]);
21
26
  videoInitSegment = responses[0];
22
27
  videoSegment = responses[1];
28
+ audioInitSegmentXheAac = responses[2];
23
29
  });
24
30
 
25
31
  it('parses init segment', () => {
@@ -157,6 +163,36 @@ describe('Mp4BoxParsers', () => {
157
163
  expect(baseMediaDecodeTime).toBe(expectedBaseMediaDecodeTime);
158
164
  });
159
165
 
166
+ it('parses ESDS box for xHE-AAC segment', () => {
167
+ let channelCount;
168
+ let sampleRate;
169
+ let codec;
170
+
171
+ const Mp4Parser = shaka.util.Mp4Parser;
172
+ new Mp4Parser()
173
+ .box('moov', Mp4Parser.children)
174
+ .box('trak', Mp4Parser.children)
175
+ .box('mdia', Mp4Parser.children)
176
+ .box('minf', Mp4Parser.children)
177
+ .box('stbl', Mp4Parser.children)
178
+ .fullBox('stsd', Mp4Parser.sampleDescription)
179
+ .box('mp4a', (box) => {
180
+ const parsedMP4ABox = shaka.util.Mp4BoxParsers.parseMP4A(box.reader);
181
+ channelCount = parsedMP4ABox.channelCount;
182
+ sampleRate = parsedMP4ABox.sampleRate;
183
+ if (box.reader.hasMoreData()) {
184
+ Mp4Parser.children(box);
185
+ }
186
+ })
187
+ .box('esds', (box) => {
188
+ const parsedESDSBox = shaka.util.Mp4BoxParsers.parseESDS(box.reader);
189
+ codec = parsedESDSBox.codec;
190
+ }).parse(audioInitSegmentXheAac, /* partialOkay= */ false);
191
+ expect(channelCount).toBe(2);
192
+ expect(sampleRate).toBe(48000);
193
+ expect(codec).toBe('mp4a.40.42');
194
+ });
195
+
160
196
  /**
161
197
  *
162
198
  * Explanation on the Uint8Array:
@@ -64,7 +64,6 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
64
64
  updateTime_() {
65
65
  const isSeeking = this.controls.isSeeking();
66
66
  let displayTime = this.controls.getDisplayTime();
67
- const duration = this.video.duration;
68
67
  const seekRange = this.player.seekRange();
69
68
  const seekRangeSize = seekRange.end - seekRange.start;
70
69
  const Utils = shaka.ui.Utils;
@@ -89,11 +88,12 @@ shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
89
88
  this.currentTime_.disabled = true;
90
89
  }
91
90
  } else {
92
- const showHour = duration >= 3600;
91
+ const showHour = seekRangeSize >= 3600;
93
92
 
94
- let value = Utils.buildTimeString(displayTime, showHour);
95
- if (duration) {
96
- value += ' / ' + Utils.buildTimeString(duration, showHour);
93
+ const currentTime = Math.max(0, displayTime - seekRange.start);
94
+ let value = Utils.buildTimeString(currentTime, showHour);
95
+ if (seekRangeSize) {
96
+ value += ' / ' + Utils.buildTimeString(seekRangeSize, showHour);
97
97
  }
98
98
  this.setValue_(value);
99
99
  this.currentTime_.disabled = true;