shaka-player 4.2.4 → 4.3.0

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 (137) hide show
  1. package/.github/workflows/sync-labels.yaml +1 -1
  2. package/.github/workflows/update-issues.yaml +1 -1
  3. package/AUTHORS +4 -0
  4. package/CHANGELOG.md +85 -54
  5. package/CONTRIBUTORS +4 -0
  6. package/README.md +14 -0
  7. package/demo/common/assets.js +58 -0
  8. package/demo/common/message_ids.js +22 -1
  9. package/demo/config.js +89 -5
  10. package/demo/demo.less +7 -1
  11. package/demo/index.html +8 -1
  12. package/demo/locales/en.json +21 -1
  13. package/demo/locales/source.json +82 -2
  14. package/demo/main.js +57 -1
  15. package/demo/search.js +2 -0
  16. package/demo/visualizer.js +337 -0
  17. package/demo/visualizer_button.js +103 -0
  18. package/dist/controls.css +1 -1
  19. package/dist/controls.css.map +1 -1
  20. package/dist/demo.compiled.debug.js +83 -58
  21. package/dist/demo.compiled.debug.map +4 -4
  22. package/dist/demo.compiled.js +83 -58
  23. package/dist/demo.compiled.map +4 -4
  24. package/dist/demo.css +1 -1
  25. package/dist/demo.css.map +1 -1
  26. package/dist/deps.js +16 -9
  27. package/dist/locales.js +32 -32
  28. package/dist/receiver.compiled.debug.js +23 -19
  29. package/dist/receiver.compiled.debug.map +3 -3
  30. package/dist/receiver.compiled.js +23 -19
  31. package/dist/receiver.compiled.map +3 -3
  32. package/dist/shaka-player.compiled.d.ts +173 -26
  33. package/dist/shaka-player.compiled.debug.d.ts +173 -26
  34. package/dist/shaka-player.compiled.debug.externs.js +161 -31
  35. package/dist/shaka-player.compiled.debug.js +464 -401
  36. package/dist/shaka-player.compiled.debug.map +4 -4
  37. package/dist/shaka-player.compiled.externs.js +161 -31
  38. package/dist/shaka-player.compiled.js +897 -862
  39. package/dist/shaka-player.compiled.map +4 -4
  40. package/dist/shaka-player.ui.d.ts +173 -26
  41. package/dist/shaka-player.ui.debug.d.ts +173 -26
  42. package/dist/shaka-player.ui.debug.externs.js +161 -31
  43. package/dist/shaka-player.ui.debug.js +488 -422
  44. package/dist/shaka-player.ui.debug.map +4 -4
  45. package/dist/shaka-player.ui.externs.js +161 -31
  46. package/dist/shaka-player.ui.js +1053 -1018
  47. package/dist/shaka-player.ui.map +4 -4
  48. package/docs/design/lcevc-architecture.png +0 -0
  49. package/docs/design/lcevc-demo.png +0 -0
  50. package/docs/design/lcevc-integration.md +72 -0
  51. package/docs/tutorials/fairplay.md +7 -0
  52. package/docs/tutorials/faq.md +1 -1
  53. package/docs/tutorials/ui.md +7 -7
  54. package/docs/tutorials/upgrade.md +6 -0
  55. package/externs/ima.js +13 -1
  56. package/externs/lcevc.js +81 -0
  57. package/externs/mux.js +1 -42
  58. package/externs/shaka/ads.js +11 -1
  59. package/externs/shaka/manifest_parser.js +5 -1
  60. package/externs/shaka/player.js +178 -15
  61. package/lib/abr/simple_abr_manager.js +7 -0
  62. package/lib/ads/ad_manager.js +0 -8
  63. package/lib/ads/client_side_ad.js +15 -0
  64. package/lib/ads/client_side_ad_manager.js +21 -8
  65. package/lib/ads/server_side_ad.js +15 -0
  66. package/lib/ads/server_side_ad_manager.js +3 -3
  67. package/lib/cast/cast_utils.js +2 -0
  68. package/lib/cea/dummy_cea_parser.js +28 -0
  69. package/lib/cea/i_cea_parser.js +14 -2
  70. package/lib/cea/mp4_cea_parser.js +87 -5
  71. package/lib/config/auto_show_text.js +33 -0
  72. package/lib/dash/dash_parser.js +1 -1
  73. package/lib/hls/hls_parser.js +790 -374
  74. package/lib/lcevc/lcevc_dil.js +152 -0
  75. package/lib/media/closed_caption_parser.js +9 -6
  76. package/lib/media/drm_engine.js +14 -6
  77. package/lib/media/media_source_engine.js +106 -26
  78. package/lib/media/presentation_timeline.js +26 -11
  79. package/lib/media/segment_reference.js +49 -1
  80. package/lib/media/streaming_engine.js +142 -12
  81. package/lib/media/transmuxer.js +73 -18
  82. package/lib/offline/storage.js +1 -0
  83. package/lib/player.js +454 -75
  84. package/lib/polyfill/patchedmediakeys_apple.js +55 -1
  85. package/lib/text/ui_text_displayer.js +5 -5
  86. package/lib/text/vtt_text_parser.js +35 -1
  87. package/lib/util/dom_utils.js +0 -1
  88. package/lib/util/error.js +17 -0
  89. package/lib/util/fake_event.js +2 -0
  90. package/lib/util/id3_utils.js +300 -0
  91. package/lib/util/mime_utils.js +3 -6
  92. package/lib/util/mp4_box_parsers.js +15 -5
  93. package/lib/util/platform.js +9 -1
  94. package/lib/util/player_configuration.js +23 -1
  95. package/lib/util/ts_parser.js +499 -0
  96. package/maintained-branches.md +2 -2
  97. package/package.json +4 -1
  98. package/roadmap.md +5 -3
  99. package/test/ads/ad_manager_unit.js +180 -29
  100. package/test/cast/cast_utils_unit.js +3 -1
  101. package/test/dash/dash_parser_content_protection_unit.js +1 -0
  102. package/test/dash/dash_parser_live_unit.js +1 -0
  103. package/test/dash/dash_parser_manifest_unit.js +93 -1
  104. package/test/dash/dash_parser_segment_base_unit.js +1 -0
  105. package/test/dash/dash_parser_segment_list_unit.js +1 -0
  106. package/test/dash/dash_parser_segment_template_unit.js +1 -0
  107. package/test/demo/demo_unit.js +2 -1
  108. package/test/hls/hls_live_unit.js +253 -19
  109. package/test/hls/hls_parser_unit.js +500 -12
  110. package/test/media/closed_caption_parser_unit.js +2 -1
  111. package/test/media/drm_engine_integration.js +3 -1
  112. package/test/media/media_source_engine_integration.js +71 -6
  113. package/test/media/media_source_engine_unit.js +10 -5
  114. package/test/media/streaming_engine_integration.js +4 -1
  115. package/test/media/streaming_engine_unit.js +144 -1
  116. package/test/media/transmuxer_integration.js +21 -10
  117. package/test/player_integration.js +224 -82
  118. package/test/player_unit.js +5 -2
  119. package/test/polyfill/patchedmediakeys_apple_unit.js +124 -0
  120. package/test/test/assets/id3-metadata.aac +0 -0
  121. package/test/test/assets/id3-metadata.ts +0 -0
  122. package/test/test/assets/thumbnails-sprites.vtt +10 -0
  123. package/test/test/assets/thumbnails.vtt +10 -0
  124. package/test/test/util/dash_parser_util.js +2 -0
  125. package/test/test/util/fake_ad.js +21 -0
  126. package/test/test/util/fake_media_source_engine.js +7 -0
  127. package/test/test/util/id3_generator.js +100 -0
  128. package/test/test/util/manifest_generator.js +3 -6
  129. package/test/test/util/simple_fakes.js +4 -0
  130. package/test/test/util/stream_generator.js +38 -0
  131. package/test/test/util/test_scheme.js +43 -14
  132. package/test/text/vtt_text_parser_unit.js +11 -0
  133. package/test/ui/text_displayer_layout_unit.js +14 -0
  134. package/test/util/id3_utils_unit.js +116 -0
  135. package/test/util/ts_parser_unit.js +77 -0
  136. package/ui/less/containers.less +7 -0
  137. package/ui/ui.js +43 -4
@@ -0,0 +1,152 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.lcevc.Dil');
8
+ goog.require('shaka.log');
9
+ goog.require('shaka.util.IReleasable');
10
+
11
+ /**
12
+ * @summary
13
+ * lcevcDil - (MPEG-5 Part 2 LCEVC - Decoder Integration Layer) provides
14
+ * all the operations related to the enhancement and rendering
15
+ * of LCEVC enabled streams and on to a canvas.
16
+ * @implements {shaka.util.IReleasable}
17
+ * @export
18
+ */
19
+ shaka.lcevc.Dil = class {
20
+ /**
21
+ * @param {HTMLVideoElement} media The video element that will be attached to
22
+ * LCEVC Dil for input.
23
+ * @param {HTMLCanvasElement} canvas The canvas element that will be attached
24
+ * to LCEVC Dil to render the enhanced frames.
25
+ * @param {shaka.extern.LcevcConfiguration} dilConfig The LCEVC DIL
26
+ * config object to initialize the LCEVC DIL.
27
+ */
28
+ constructor(media, canvas, dilConfig) {
29
+ /** @private {?LcevcDil.LcevcDIL} */
30
+ this.dil_ = null;
31
+
32
+ /** @private {number} */
33
+ this.variantId_ = -1;
34
+
35
+ /** @private {HTMLVideoElement} */
36
+ this.media_ = media;
37
+
38
+ /** @private {HTMLCanvasElement} */
39
+ this.canvas_ = canvas;
40
+
41
+ /** @private {shaka.extern.LcevcConfiguration} */
42
+ this.dilConfig_ = dilConfig;
43
+
44
+ this.create_();
45
+ }
46
+
47
+ /**
48
+ * Append data to the LCEVC Dil.
49
+ * @param {BufferSource} data
50
+ */
51
+ appendBuffer(data) {
52
+ if (this.dil_) {
53
+ this.dil_.appendBuffer(data, 'video', this.variantId_);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Hide the canvas specifically in the case of a DRM Content
59
+ */
60
+ hideCanvas() {
61
+ if (this.dil_) {
62
+ this.canvas_.classList.add('shaka-hidden');
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Create LCEVC Dil.
68
+ * @private
69
+ */
70
+ create_() {
71
+ if (this.isSupported_() && !this.dil_) {
72
+ if (LcevcDil.SupportObject.webGLSupport(this.canvas_)) {
73
+ // Make sure the canvas is not hidden from a previous playback session.
74
+ this.canvas_.classList.remove('shaka-hidden');
75
+ this.dil_ = new LcevcDil.LcevcDil(
76
+ this.media_,
77
+ this.canvas_,
78
+ this.dilConfig_);
79
+ }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Close LCEVC Dil.
85
+ * @override
86
+ * @export
87
+ */
88
+ release() {
89
+ if (this.dil_) {
90
+ this.dil_.close();
91
+ this.dil_ = null;
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Check if the LCEVC Dil lib is present and is supported by the browser.
97
+ * @return {boolean}
98
+ * @private
99
+ */
100
+ isSupported_() {
101
+ if (typeof libDPIModule === 'undefined') {
102
+ shaka.log.alwaysWarn(
103
+ 'Could not Find LCEVC Library dependencies on this page');
104
+ }
105
+
106
+ if (typeof LcevcDil === 'undefined') {
107
+ shaka.log.alwaysWarn('Could not Find LCEVC Library on this page');
108
+ } else {
109
+ if (!LcevcDil.SupportObject.SupportStatus) {
110
+ shaka.log.alwaysWarn(LcevcDil.SupportObject.SupportError);
111
+ }
112
+ }
113
+
114
+ return typeof LcevcDil !== 'undefined' &&
115
+ typeof libDPIModule !== 'undefined' &&
116
+ this.canvas_ instanceof HTMLCanvasElement &&
117
+ LcevcDil.SupportObject.SupportStatus;
118
+ }
119
+
120
+ /**
121
+ * Update current active variant
122
+ * @param {shaka.extern.Track} track
123
+ */
124
+ updateVariant(track) {
125
+ let containerFormat = shaka.lcevc.Dil.ContainerFormat.MPEG2_TS;
126
+ switch (track.mimeType) {
127
+ case 'video/webm': {
128
+ containerFormat = shaka.lcevc.Dil.ContainerFormat.WEBM;
129
+ break;
130
+ }
131
+ case 'video/mp4': {
132
+ containerFormat = shaka.lcevc.Dil.ContainerFormat.MP4;
133
+ break;
134
+ }
135
+ }
136
+ if (this.dil_) {
137
+ this.variantId_ = track.id;
138
+ this.dil_.setLevelSwitching(track.id, true);
139
+ this.dil_.setContainerFormat(containerFormat);
140
+ }
141
+ }
142
+ };
143
+
144
+ /**
145
+ * Container Formats.
146
+ * @const @enum {number}
147
+ */
148
+ shaka.lcevc.Dil.ContainerFormat = {
149
+ MPEG2_TS: 0,
150
+ WEBM: 1,
151
+ MP4: 2,
152
+ };
@@ -8,6 +8,7 @@ goog.provide('shaka.media.ClosedCaptionParser');
8
8
  goog.provide('shaka.media.IClosedCaptionParser');
9
9
 
10
10
  goog.require('shaka.cea.CeaDecoder');
11
+ goog.require('shaka.cea.DummyCeaParser');
11
12
  goog.require('shaka.cea.Mp4CeaParser');
12
13
  goog.require('shaka.util.BufferUtils');
13
14
  goog.requireType('shaka.cea.ICaptionDecoder');
@@ -54,12 +55,14 @@ shaka.media.IClosedCaptionParser = class {
54
55
  */
55
56
  shaka.media.ClosedCaptionParser = class {
56
57
  /** */
57
- constructor() {
58
- /**
59
- * MP4 Parser to extract closed caption packets from H.264 video.
60
- * @private {!shaka.cea.ICeaParser}
61
- */
62
- this.ceaParser_ = new shaka.cea.Mp4CeaParser();
58
+ constructor(mimeType) {
59
+ /** @private {!shaka.cea.ICeaParser} */
60
+ this.ceaParser_ = new shaka.cea.DummyCeaParser();
61
+
62
+ if (mimeType.includes('video/mp4')) {
63
+ // MP4 Parser to extract closed caption packets from H.264 video.
64
+ this.ceaParser_ = new shaka.cea.Mp4CeaParser();
65
+ }
63
66
 
64
67
  /**
65
68
  * Decoder for decoding CEA-X08 data from closed caption packets.
@@ -845,7 +845,7 @@ shaka.media.DrmEngine = class {
845
845
  if (shaka.media.Transmuxer.isSupported(realMimeType)) {
846
846
  // This will be handled by the Transmuxer, so use the MIME type that the
847
847
  // Transmuxer will produce.
848
- return shaka.media.Transmuxer.convertTsCodecs(stream.type, realMimeType);
848
+ return shaka.media.Transmuxer.convertCodecs(stream.type, realMimeType);
849
849
  }
850
850
  return realMimeType;
851
851
  }
@@ -1113,13 +1113,21 @@ shaka.media.DrmEngine = class {
1113
1113
  const keys = [];
1114
1114
  const keyIds = [];
1115
1115
 
1116
- clearKeys.forEach((keyHex, keyIdHex) => {
1117
- const keyId = Uint8ArrayUtils.fromHex(keyIdHex);
1118
- const key = Uint8ArrayUtils.fromHex(keyHex);
1116
+ clearKeys.forEach((key, keyId) => {
1117
+ let kid = keyId;
1118
+ if (kid.length != 22) {
1119
+ kid = Uint8ArrayUtils.toBase64(
1120
+ Uint8ArrayUtils.fromHex(keyId), false);
1121
+ }
1122
+ let k = key;
1123
+ if (k.length != 22) {
1124
+ k = Uint8ArrayUtils.toBase64(
1125
+ Uint8ArrayUtils.fromHex(key), false);
1126
+ }
1119
1127
  const keyObj = {
1120
1128
  kty: 'oct',
1121
- kid: Uint8ArrayUtils.toBase64(keyId, false),
1122
- k: Uint8ArrayUtils.toBase64(key, false),
1129
+ kid: kid,
1130
+ k: k,
1123
1131
  };
1124
1132
 
1125
1133
  keys.push(keyObj);
@@ -9,20 +9,25 @@ goog.provide('shaka.media.MediaSourceEngine');
9
9
  goog.require('goog.asserts');
10
10
  goog.require('shaka.log');
11
11
  goog.require('shaka.media.ContentWorkarounds');
12
+ goog.require('shaka.media.ClosedCaptionParser');
12
13
  goog.require('shaka.media.IClosedCaptionParser');
13
14
  goog.require('shaka.media.SegmentReference');
14
15
  goog.require('shaka.media.TimeRangesUtils');
15
16
  goog.require('shaka.media.Transmuxer');
16
17
  goog.require('shaka.text.TextEngine');
18
+ goog.require('shaka.util.BufferUtils');
17
19
  goog.require('shaka.util.Destroyer');
18
20
  goog.require('shaka.util.Error');
19
21
  goog.require('shaka.util.EventManager');
20
22
  goog.require('shaka.util.Functional');
21
23
  goog.require('shaka.util.IDestroyable');
24
+ goog.require('shaka.util.Id3Utils');
22
25
  goog.require('shaka.util.ManifestParserUtils');
23
26
  goog.require('shaka.util.MimeUtils');
24
27
  goog.require('shaka.util.Platform');
25
28
  goog.require('shaka.util.PublicPromise');
29
+ goog.require('shaka.util.TsParser');
30
+ goog.require('shaka.lcevc.Dil');
26
31
 
27
32
 
28
33
  /**
@@ -38,21 +43,22 @@ shaka.media.MediaSourceEngine = class {
38
43
  /**
39
44
  * @param {HTMLMediaElement} video The video element, whose source is tied to
40
45
  * MediaSource during the lifetime of the MediaSourceEngine.
41
- * @param {!shaka.media.IClosedCaptionParser} closedCaptionParser
42
- * The closed caption parser that should be used to parser closed captions
43
- * from the video stream. MediaSourceEngine takes ownership of the parser.
44
- * When MediaSourceEngine is destroyed, it will destroy the parser.
45
46
  * @param {!shaka.extern.TextDisplayer} textDisplayer
46
47
  * The text displayer that will be used with the text engine.
47
48
  * MediaSourceEngine takes ownership of the displayer. When
48
49
  * MediaSourceEngine is destroyed, it will destroy the displayer.
49
50
  * @param {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)=}
50
51
  * onMetadata
52
+ * @param {?shaka.lcevc.Dil} [lcevcDil] Optional - LCEVC Dil Object
53
+ *
51
54
  */
52
- constructor(video, closedCaptionParser, textDisplayer, onMetadata) {
55
+ constructor(video, textDisplayer, onMetadata, lcevcDil) {
53
56
  /** @private {HTMLMediaElement} */
54
57
  this.video_ = video;
55
58
 
59
+ /** @private {?shaka.extern.MediaSourceConfiguration} */
60
+ this.config_ = null;
61
+
56
62
  /** @private {shaka.extern.TextDisplayer} */
57
63
  this.textDisplayer_ = textDisplayer;
58
64
 
@@ -81,6 +87,9 @@ shaka.media.MediaSourceEngine = class {
81
87
  number, ?number)} */
82
88
  this.onMetadata_ = onMetadata || onMetadataNoOp;
83
89
 
90
+ /** @private {?shaka.lcevc.Dil} */
91
+ this.lcevcDil_ = lcevcDil || null;
92
+
84
93
  /**
85
94
  * @private {!Object.<string,
86
95
  * !Array.<shaka.media.MediaSourceEngine.Operation>>}
@@ -93,8 +102,8 @@ shaka.media.MediaSourceEngine = class {
93
102
  /** @private {!Object.<string, !shaka.media.Transmuxer>} */
94
103
  this.transmuxers_ = {};
95
104
 
96
- /** @private {shaka.media.IClosedCaptionParser} */
97
- this.captionParser_ = closedCaptionParser;
105
+ /** @private {?shaka.media.IClosedCaptionParser} */
106
+ this.captionParser_ = null;
98
107
 
99
108
  /** @private {!shaka.util.PublicPromise} */
100
109
  this.mediaSourceOpen_ = new shaka.util.PublicPromise();
@@ -291,6 +300,7 @@ shaka.media.MediaSourceEngine = class {
291
300
  this.video_ = null;
292
301
  }
293
302
 
303
+ this.config_ = null;
294
304
  this.mediaSource_ = null;
295
305
  this.textEngine_ = null;
296
306
  this.textDisplayer_ = null;
@@ -305,6 +315,9 @@ shaka.media.MediaSourceEngine = class {
305
315
  }
306
316
  }
307
317
  this.queues_ = {};
318
+
319
+ // This object is owned by Player
320
+ this.lcevcDil_ = null;
308
321
  }
309
322
 
310
323
  /**
@@ -325,15 +338,16 @@ shaka.media.MediaSourceEngine = class {
325
338
  * shaka.extern.Stream>} streamsByType
326
339
  * A map of content types to streams. All streams must be supported
327
340
  * according to MediaSourceEngine.isStreamSupported.
328
- * @param {boolean} forceTransmuxTS
329
- * If true, this will transmux TS content even if it is natively supported.
341
+ * @param {boolean} forceTransmux
342
+ * If true, this will transmux AAC and TS content even if it is natively
343
+ * supported.
330
344
  * @param {boolean=} sequenceMode
331
345
  * If true, the media segments are appended to the SourceBuffer in strict
332
346
  * sequence.
333
347
  *
334
348
  * @return {!Promise}
335
349
  */
336
- async init(streamsByType, forceTransmuxTS, sequenceMode=false) {
350
+ async init(streamsByType, forceTransmux, sequenceMode=false) {
337
351
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
338
352
 
339
353
  await this.mediaSourceOpen_;
@@ -351,14 +365,15 @@ shaka.media.MediaSourceEngine = class {
351
365
  if (contentType == ContentType.TEXT) {
352
366
  this.reinitText(mimeType, sequenceMode);
353
367
  } else {
354
- if ((forceTransmuxTS || !MediaSource.isTypeSupported(mimeType)) &&
368
+ if ((forceTransmux || !MediaSource.isTypeSupported(mimeType)) &&
355
369
  shaka.media.Transmuxer.isSupported(mimeType, contentType)) {
356
- this.transmuxers_[contentType] = new shaka.media.Transmuxer();
370
+ this.transmuxers_[contentType] =
371
+ new shaka.media.Transmuxer(mimeType);
357
372
  mimeType =
358
- shaka.media.Transmuxer.convertTsCodecs(contentType, mimeType);
373
+ shaka.media.Transmuxer.convertCodecs(contentType, mimeType);
359
374
  }
360
-
361
- const sourceBuffer = this.mediaSource_.addSourceBuffer(mimeType);
375
+ const type = mimeType + this.config_.sourceBufferExtraFeatures;
376
+ const sourceBuffer = this.mediaSource_.addSourceBuffer(type);
362
377
 
363
378
  this.eventManager_.listen(
364
379
  sourceBuffer, 'error',
@@ -374,6 +389,16 @@ shaka.media.MediaSourceEngine = class {
374
389
  }
375
390
  }
376
391
 
392
+ /**
393
+ * Called by the Player to provide an updated configuration any time it
394
+ * changes. Must be called at least once before init().
395
+ *
396
+ * @param {shaka.extern.MediaSourceConfiguration} config
397
+ */
398
+ configure(config) {
399
+ this.config_ = config;
400
+ }
401
+
377
402
  /**
378
403
  * Reinitialize the TextEngine for a new text type.
379
404
  * @param {string} mimeType
@@ -509,6 +534,17 @@ shaka.media.MediaSourceEngine = class {
509
534
  }
510
535
  }
511
536
 
537
+ /**
538
+ * Create a new closed caption parser. This will ONLY be replaced by tests as
539
+ * a way to inject fake closed caption parser instances.
540
+ *
541
+ * @param {string} mimeType
542
+ * @return {!shaka.media.IClosedCaptionParser}
543
+ */
544
+ getCaptionParser(mimeType) {
545
+ return new shaka.media.ClosedCaptionParser(mimeType);
546
+ }
547
+
512
548
  /**
513
549
  * Enqueue an operation to append data to the SourceBuffer.
514
550
  * Start and end times are needed for TextEngine, but not for MediaSource.
@@ -544,6 +580,37 @@ shaka.media.MediaSourceEngine = class {
544
580
  return;
545
581
  }
546
582
 
583
+ const uint8ArrayData = shaka.util.BufferUtils.toUint8(data);
584
+ let mimeType = this.sourceBufferTypes_[contentType];
585
+ if (this.transmuxers_[contentType]) {
586
+ mimeType = this.transmuxers_[contentType].getOrginalMimeType();
587
+ }
588
+ if (shaka.util.TsParser.probe(uint8ArrayData)) {
589
+ const metadata = new shaka.util.TsParser().parse(uint8ArrayData)
590
+ .getMetadata();
591
+ if (metadata.length) {
592
+ const timestampOffset =
593
+ this.sourceBuffers_[contentType].timestampOffset;
594
+ this.onMetadata_(metadata, timestampOffset,
595
+ reference ? reference.endTime : null);
596
+ }
597
+ } else {
598
+ if (shaka.media.MediaSourceEngine.RAW_FORMATS.includes(mimeType)) {
599
+ const frames = shaka.util.Id3Utils.getID3Frames(uint8ArrayData);
600
+ if (frames.length && reference) {
601
+ /** @private {shaka.extern.ID3Metadata} */
602
+ const metadata = {
603
+ cueTime: reference.startTime,
604
+ data: uint8ArrayData,
605
+ frames: frames,
606
+ dts: reference.startTime,
607
+ pts: reference.startTime,
608
+ };
609
+ this.onMetadata_([metadata], /* offset= */ 0, reference.endTime);
610
+ }
611
+ }
612
+ }
613
+
547
614
  if (this.transmuxers_[contentType]) {
548
615
  // When seeked we should reset the transmuxer captionstreams
549
616
  // so it does not ignores the captions from previous segments
@@ -558,15 +625,6 @@ shaka.media.MediaSourceEngine = class {
558
625
  if (!this.textEngine_) {
559
626
  this.reinitText('text/vtt', this.sequenceMode_);
560
627
  }
561
-
562
- if (transmuxedData.metadata) {
563
- const timestampOffset =
564
- this.sourceBuffers_[contentType].timestampOffset;
565
- this.onMetadata_(
566
- transmuxedData.metadata,
567
- timestampOffset,
568
- reference ? reference.endTime : null);
569
- }
570
628
  // This doesn't work for native TS support (ex. Edge/Chromecast),
571
629
  // since no transmuxing is needed for native TS.
572
630
  if (transmuxedData.captions && transmuxedData.captions.length) {
@@ -582,10 +640,13 @@ shaka.media.MediaSourceEngine = class {
582
640
  }
583
641
 
584
642
  data = transmuxedData.data;
585
- } else if (hasClosedCaptions) {
643
+ } else if (hasClosedCaptions && contentType == ContentType.VIDEO) {
586
644
  if (!this.textEngine_) {
587
645
  this.reinitText('text/vtt', this.sequenceMode_);
588
646
  }
647
+ if (!this.captionParser_) {
648
+ this.captionParser_ = this.getCaptionParser(mimeType);
649
+ }
589
650
  // If it is the init segment for closed captions, initialize the closed
590
651
  // caption parser.
591
652
  if (!reference) {
@@ -779,7 +840,9 @@ shaka.media.MediaSourceEngine = class {
779
840
  * Fully reset the state of the caption parser owned by MediaSourceEngine.
780
841
  */
781
842
  resetCaptionParser() {
782
- this.captionParser_.reset();
843
+ if (this.captionParser_) {
844
+ this.captionParser_.reset();
845
+ }
783
846
  }
784
847
 
785
848
  /**
@@ -918,6 +981,15 @@ shaka.media.MediaSourceEngine = class {
918
981
  * @private
919
982
  */
920
983
  append_(contentType, data) {
984
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
985
+
986
+ // Append only video data to the LCEVC Dil.
987
+ if (contentType == ContentType.VIDEO && this.lcevcDil_) {
988
+ // Append video buffers to the LCEVC Dil for parsing and storing
989
+ // of LCEVC data.
990
+ this.lcevcDil_.appendBuffer(data);
991
+ }
992
+
921
993
  // This will trigger an 'updateend' event.
922
994
  this.sourceBuffers_[contentType].appendBuffer(data);
923
995
  }
@@ -1283,6 +1355,14 @@ shaka.media.MediaSourceEngine = class {
1283
1355
 
1284
1356
  return segment;
1285
1357
  }
1358
+
1359
+ /**
1360
+ * Update LCEVC DIL object when ready for LCEVC Decodes
1361
+ * @param {?shaka.lcevc.Dil} lcevcDil
1362
+ */
1363
+ updateLcevcDil(lcevcDil) {
1364
+ this.lcevcDil_ = lcevcDil;
1365
+ }
1286
1366
  };
1287
1367
 
1288
1368
 
@@ -118,6 +118,20 @@ shaka.media.PresentationTimeline = class {
118
118
  }
119
119
 
120
120
 
121
+ /**
122
+ * Sets the presentation's start time.
123
+ *
124
+ * @param {number} presentationStartTime The wall-clock time, in seconds,
125
+ * when the presentation started or will start. Only required for live.
126
+ * @export
127
+ */
128
+ setPresentationStartTime(presentationStartTime) {
129
+ goog.asserts.assert(presentationStartTime >= 0,
130
+ 'presentationStartTime must be >= 0');
131
+ this.presentationStartTime_ = presentationStartTime;
132
+ }
133
+
134
+
121
135
  /**
122
136
  * Sets the presentation's duration.
123
137
  *
@@ -207,10 +221,10 @@ shaka.media.PresentationTimeline = class {
207
221
 
208
222
 
209
223
  /**
210
- * Gives PresentationTimeline a Stream's segments so it can size and position
224
+ * Gives PresentationTimeline an array of segments so it can size and position
211
225
  * the segment availability window, and account for missing segment
212
- * information. This function should be called once for each Stream (no more,
213
- * no less).
226
+ * information. These segments do not necessarily need to all be from the
227
+ * same stream.
214
228
  *
215
229
  * @param {!Array.<!shaka.media.SegmentReference>} references
216
230
  * @export
@@ -220,15 +234,16 @@ shaka.media.PresentationTimeline = class {
220
234
  return;
221
235
  }
222
236
 
223
- const firstReferenceStartTime = references[0].startTime;
224
- const lastReferenceEndTime = references[references.length - 1].endTime;
225
-
237
+ let firstReferenceStartTime = references[0].startTime;
238
+ let lastReferenceEndTime = references[0].endTime;
239
+ for (const reference of references) {
240
+ firstReferenceStartTime = Math.min(
241
+ firstReferenceStartTime, reference.startTime);
242
+ lastReferenceEndTime = Math.max(lastReferenceEndTime, reference.endTime);
243
+ this.maxSegmentDuration_ = Math.max(
244
+ this.maxSegmentDuration_, reference.endTime - reference.startTime);
245
+ }
226
246
  this.notifyMinSegmentStartTime(firstReferenceStartTime);
227
-
228
- this.maxSegmentDuration_ = references.reduce(
229
- (max, r) => { return Math.max(max, r.endTime - r.startTime); },
230
- this.maxSegmentDuration_);
231
-
232
247
  this.maxSegmentEndTime_ =
233
248
  Math.max(this.maxSegmentEndTime_, lastReferenceEndTime);
234
249
 
@@ -28,8 +28,9 @@ shaka.media.InitSegmentReference = class {
28
28
  * segment extends to the end of the resource.
29
29
  * @param {null|shaka.extern.MediaQualityInfo=} mediaQuality Information about
30
30
  * the quality of the media associated with this init segment.
31
+ * @param {number=} timescale
31
32
  */
32
- constructor(uris, startByte, endByte, mediaQuality = null) {
33
+ constructor(uris, startByte, endByte, mediaQuality = null, timescale) {
33
34
  /** @type {function():!Array.<string>} */
34
35
  this.getUris = uris;
35
36
 
@@ -41,6 +42,9 @@ shaka.media.InitSegmentReference = class {
41
42
 
42
43
  /** @const {shaka.extern.MediaQualityInfo|null} */
43
44
  this.mediaQuality = mediaQuality;
45
+
46
+ /** @type {number|undefined} */
47
+ this.timescale = timescale;
44
48
  }
45
49
 
46
50
  /**
@@ -239,6 +243,9 @@ shaka.media.SegmentReference = class {
239
243
 
240
244
  /** @type {?shaka.extern.HlsAes128Key} */
241
245
  this.hlsAes128Key = hlsAes128Key;
246
+
247
+ /** @type {?shaka.media.SegmentReference.ThumbnailSprite} */
248
+ this.thumbnailSprite = null;
242
249
  }
243
250
 
244
251
  /**
@@ -353,6 +360,26 @@ shaka.media.SegmentReference = class {
353
360
  markAsUnavailable() {
354
361
  this.status = shaka.media.SegmentReference.Status.UNAVAILABLE;
355
362
  }
363
+
364
+ /**
365
+ * Set the segment's thumbnail sprite.
366
+ *
367
+ * @param {shaka.media.SegmentReference.ThumbnailSprite} thumbnailSprite
368
+ * @export
369
+ */
370
+ setThumbnailSprite(thumbnailSprite) {
371
+ this.thumbnailSprite = thumbnailSprite;
372
+ }
373
+
374
+ /**
375
+ * Returns the segment's thumbnail sprite.
376
+ *
377
+ * @return {?shaka.media.SegmentReference.ThumbnailSprite}
378
+ * @export
379
+ */
380
+ getThumbnailSprite() {
381
+ return this.thumbnailSprite;
382
+ }
356
383
  };
357
384
 
358
385
 
@@ -376,3 +403,24 @@ shaka.media.SegmentReference.Status = {
376
403
  * @typedef {shaka.media.InitSegmentReference|shaka.media.SegmentReference}
377
404
  */
378
405
  shaka.media.AnySegmentReference;
406
+
407
+
408
+ /**
409
+ * @typedef {{
410
+ * height: number,
411
+ * positionX: number,
412
+ * positionY: number,
413
+ * width: number
414
+ * }}
415
+ *
416
+ * @property {number} height
417
+ * The thumbnail height in px.
418
+ * @property {number} positionX
419
+ * The thumbnail left position in px.
420
+ * @property {number} positionY
421
+ * The thumbnail top position in px.
422
+ * @property {number} width
423
+ * The thumbnail width in px.
424
+ * @export
425
+ */
426
+ shaka.media.SegmentReference.ThumbnailSprite;