shaka-player 4.2.5 → 4.3.1

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 (143) hide show
  1. package/.github/workflows/build-and-test.yaml +7 -0
  2. package/.github/workflows/sync-labels.yaml +1 -1
  3. package/.github/workflows/update-issues.yaml +1 -1
  4. package/AUTHORS +4 -0
  5. package/CHANGELOG.md +114 -74
  6. package/CONTRIBUTORS +4 -0
  7. package/README.md +14 -0
  8. package/conditional/dummy_cast_proxy.js +120 -0
  9. package/demo/common/assets.js +58 -0
  10. package/demo/common/message_ids.js +22 -1
  11. package/demo/config.js +89 -5
  12. package/demo/demo.less +7 -1
  13. package/demo/index.html +8 -1
  14. package/demo/locales/en.json +21 -1
  15. package/demo/locales/source.json +82 -2
  16. package/demo/main.js +57 -1
  17. package/demo/search.js +2 -0
  18. package/demo/visualizer.js +337 -0
  19. package/demo/visualizer_button.js +103 -0
  20. package/dist/controls.css +1 -1
  21. package/dist/controls.css.map +1 -1
  22. package/dist/demo.compiled.debug.js +107 -88
  23. package/dist/demo.compiled.debug.map +4 -4
  24. package/dist/demo.compiled.js +107 -88
  25. package/dist/demo.compiled.map +4 -4
  26. package/dist/demo.css +1 -1
  27. package/dist/demo.css.map +1 -1
  28. package/dist/deps.js +21 -13
  29. package/dist/locales.js +31 -31
  30. package/dist/receiver.compiled.debug.js +75 -77
  31. package/dist/receiver.compiled.debug.map +3 -3
  32. package/dist/receiver.compiled.js +75 -77
  33. package/dist/receiver.compiled.map +3 -3
  34. package/dist/shaka-player.compiled.d.ts +181 -27
  35. package/dist/shaka-player.compiled.debug.d.ts +181 -27
  36. package/dist/shaka-player.compiled.debug.externs.js +169 -31
  37. package/dist/shaka-player.compiled.debug.js +510 -450
  38. package/dist/shaka-player.compiled.debug.map +4 -4
  39. package/dist/shaka-player.compiled.externs.js +169 -31
  40. package/dist/shaka-player.compiled.js +912 -874
  41. package/dist/shaka-player.compiled.map +4 -4
  42. package/dist/shaka-player.ui.d.ts +181 -27
  43. package/dist/shaka-player.ui.debug.d.ts +181 -27
  44. package/dist/shaka-player.ui.debug.externs.js +169 -31
  45. package/dist/shaka-player.ui.debug.js +533 -471
  46. package/dist/shaka-player.ui.debug.map +4 -4
  47. package/dist/shaka-player.ui.externs.js +169 -31
  48. package/dist/shaka-player.ui.js +1073 -1036
  49. package/dist/shaka-player.ui.map +4 -4
  50. package/docs/design/lcevc-architecture.png +0 -0
  51. package/docs/design/lcevc-demo.png +0 -0
  52. package/docs/design/lcevc-integration.md +72 -0
  53. package/docs/tutorials/fairplay.md +7 -0
  54. package/docs/tutorials/faq.md +1 -1
  55. package/docs/tutorials/ui.md +7 -7
  56. package/docs/tutorials/upgrade.md +6 -0
  57. package/externs/ima.js +13 -1
  58. package/externs/lcevc.js +81 -0
  59. package/externs/mux.js +1 -42
  60. package/externs/shaka/ads.js +11 -1
  61. package/externs/shaka/manifest_parser.js +5 -1
  62. package/externs/shaka/mp4_parser.js +3 -0
  63. package/externs/shaka/player.js +178 -15
  64. package/lib/abr/simple_abr_manager.js +7 -0
  65. package/lib/ads/ad_manager.js +0 -8
  66. package/lib/ads/client_side_ad.js +15 -0
  67. package/lib/ads/client_side_ad_manager.js +21 -8
  68. package/lib/ads/server_side_ad.js +15 -0
  69. package/lib/ads/server_side_ad_manager.js +3 -3
  70. package/lib/cast/cast_utils.js +2 -0
  71. package/lib/cea/dummy_cea_parser.js +28 -0
  72. package/lib/cea/i_cea_parser.js +14 -2
  73. package/lib/cea/mp4_cea_parser.js +108 -5
  74. package/lib/config/auto_show_text.js +33 -0
  75. package/lib/dash/dash_parser.js +1 -1
  76. package/lib/hls/hls_parser.js +808 -384
  77. package/lib/lcevc/lcevc_dil.js +152 -0
  78. package/lib/media/closed_caption_parser.js +9 -6
  79. package/lib/media/drm_engine.js +14 -6
  80. package/lib/media/media_source_capabilities.js +36 -0
  81. package/lib/media/media_source_engine.js +113 -28
  82. package/lib/media/presentation_timeline.js +26 -11
  83. package/lib/media/segment_reference.js +49 -1
  84. package/lib/media/streaming_engine.js +142 -12
  85. package/lib/media/transmuxer.js +78 -21
  86. package/lib/offline/storage.js +1 -0
  87. package/lib/player.js +456 -77
  88. package/lib/polyfill/media_capabilities.js +9 -5
  89. package/lib/polyfill/patchedmediakeys_apple.js +63 -4
  90. package/lib/text/vtt_text_parser.js +35 -1
  91. package/lib/util/dom_utils.js +0 -1
  92. package/lib/util/error.js +17 -0
  93. package/lib/util/fake_event.js +2 -0
  94. package/lib/util/id3_utils.js +300 -0
  95. package/lib/util/mime_utils.js +3 -6
  96. package/lib/util/mp4_box_parsers.js +39 -5
  97. package/lib/util/mp4_parser.js +35 -0
  98. package/lib/util/player_configuration.js +23 -1
  99. package/lib/util/stream_utils.js +5 -3
  100. package/lib/util/ts_parser.js +499 -0
  101. package/maintained-branches.md +2 -2
  102. package/package.json +7 -4
  103. package/roadmap.md +5 -3
  104. package/test/ads/ad_manager_unit.js +182 -29
  105. package/test/cast/cast_utils_unit.js +3 -1
  106. package/test/dash/dash_parser_content_protection_unit.js +1 -0
  107. package/test/dash/dash_parser_live_unit.js +1 -0
  108. package/test/dash/dash_parser_manifest_unit.js +93 -1
  109. package/test/dash/dash_parser_segment_base_unit.js +1 -0
  110. package/test/dash/dash_parser_segment_list_unit.js +1 -0
  111. package/test/dash/dash_parser_segment_template_unit.js +1 -0
  112. package/test/demo/demo_unit.js +2 -1
  113. package/test/hls/hls_live_unit.js +253 -19
  114. package/test/hls/hls_parser_unit.js +631 -12
  115. package/test/media/closed_caption_parser_unit.js +2 -1
  116. package/test/media/drm_engine_integration.js +3 -1
  117. package/test/media/media_source_engine_integration.js +71 -6
  118. package/test/media/media_source_engine_unit.js +10 -5
  119. package/test/media/streaming_engine_integration.js +4 -1
  120. package/test/media/streaming_engine_unit.js +144 -1
  121. package/test/media/transmuxer_integration.js +21 -10
  122. package/test/player_integration.js +224 -82
  123. package/test/player_unit.js +5 -2
  124. package/test/polyfill/media_capabilities_unit.js +21 -23
  125. package/test/polyfill/patchedmediakeys_apple_unit.js +130 -0
  126. package/test/test/assets/id3-metadata.aac +0 -0
  127. package/test/test/assets/id3-metadata.ts +0 -0
  128. package/test/test/assets/thumbnails-sprites.vtt +10 -0
  129. package/test/test/assets/thumbnails.vtt +10 -0
  130. package/test/test/util/dash_parser_util.js +2 -0
  131. package/test/test/util/fake_ad.js +21 -0
  132. package/test/test/util/fake_media_source_engine.js +7 -0
  133. package/test/test/util/id3_generator.js +100 -0
  134. package/test/test/util/manifest_generator.js +3 -6
  135. package/test/test/util/simple_fakes.js +4 -0
  136. package/test/test/util/stream_generator.js +38 -0
  137. package/test/test/util/test_scheme.js +43 -14
  138. package/test/text/vtt_text_parser_unit.js +11 -0
  139. package/test/util/id3_utils_unit.js +116 -0
  140. package/test/util/ts_parser_unit.js +77 -0
  141. package/third_party/closure-uri/uri.js +1 -1
  142. package/ui/less/containers.less +7 -0
  143. 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);
@@ -0,0 +1,36 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.media.Capabilities');
8
+
9
+ /**
10
+ * @summary
11
+ * This is for capturing all media source capabilities on current platform.
12
+ * And this is for static check and can not be constructed.
13
+ */
14
+ shaka.media.Capabilities = class {
15
+ /**
16
+ * Cache browser engine call to improve performance on some poor platforms
17
+ *
18
+ * @param {string} type
19
+ * @return {boolean}
20
+ */
21
+ static isTypeSupported(type) {
22
+ const supportMap = shaka.media.Capabilities.MediaSourceTypeSupportMap;
23
+ if (supportMap.has(type)) {
24
+ return supportMap.get(type);
25
+ }
26
+ const currentSupport = MediaSource.isTypeSupported(type);
27
+ supportMap.set(type, currentSupport);
28
+ return currentSupport;
29
+ }
30
+ };
31
+
32
+ /**
33
+ * Public it for unit test, and developer could also check the support map.
34
+ * @type {!Map.<string, boolean>}
35
+ */
36
+ shaka.media.Capabilities.MediaSourceTypeSupportMap = new Map();
@@ -8,21 +8,27 @@ goog.provide('shaka.media.MediaSourceEngine');
8
8
 
9
9
  goog.require('goog.asserts');
10
10
  goog.require('shaka.log');
11
+ goog.require('shaka.media.Capabilities');
11
12
  goog.require('shaka.media.ContentWorkarounds');
13
+ goog.require('shaka.media.ClosedCaptionParser');
12
14
  goog.require('shaka.media.IClosedCaptionParser');
13
15
  goog.require('shaka.media.SegmentReference');
14
16
  goog.require('shaka.media.TimeRangesUtils');
15
17
  goog.require('shaka.media.Transmuxer');
16
18
  goog.require('shaka.text.TextEngine');
19
+ goog.require('shaka.util.BufferUtils');
17
20
  goog.require('shaka.util.Destroyer');
18
21
  goog.require('shaka.util.Error');
19
22
  goog.require('shaka.util.EventManager');
20
23
  goog.require('shaka.util.Functional');
21
24
  goog.require('shaka.util.IDestroyable');
25
+ goog.require('shaka.util.Id3Utils');
22
26
  goog.require('shaka.util.ManifestParserUtils');
23
27
  goog.require('shaka.util.MimeUtils');
24
28
  goog.require('shaka.util.Platform');
25
29
  goog.require('shaka.util.PublicPromise');
30
+ goog.require('shaka.util.TsParser');
31
+ goog.require('shaka.lcevc.Dil');
26
32
 
27
33
 
28
34
  /**
@@ -38,21 +44,22 @@ shaka.media.MediaSourceEngine = class {
38
44
  /**
39
45
  * @param {HTMLMediaElement} video The video element, whose source is tied to
40
46
  * 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
47
  * @param {!shaka.extern.TextDisplayer} textDisplayer
46
48
  * The text displayer that will be used with the text engine.
47
49
  * MediaSourceEngine takes ownership of the displayer. When
48
50
  * MediaSourceEngine is destroyed, it will destroy the displayer.
49
51
  * @param {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)=}
50
52
  * onMetadata
53
+ * @param {?shaka.lcevc.Dil} [lcevcDil] Optional - LCEVC Dil Object
54
+ *
51
55
  */
52
- constructor(video, closedCaptionParser, textDisplayer, onMetadata) {
56
+ constructor(video, textDisplayer, onMetadata, lcevcDil) {
53
57
  /** @private {HTMLMediaElement} */
54
58
  this.video_ = video;
55
59
 
60
+ /** @private {?shaka.extern.MediaSourceConfiguration} */
61
+ this.config_ = null;
62
+
56
63
  /** @private {shaka.extern.TextDisplayer} */
57
64
  this.textDisplayer_ = textDisplayer;
58
65
 
@@ -81,6 +88,9 @@ shaka.media.MediaSourceEngine = class {
81
88
  number, ?number)} */
82
89
  this.onMetadata_ = onMetadata || onMetadataNoOp;
83
90
 
91
+ /** @private {?shaka.lcevc.Dil} */
92
+ this.lcevcDil_ = lcevcDil || null;
93
+
84
94
  /**
85
95
  * @private {!Object.<string,
86
96
  * !Array.<shaka.media.MediaSourceEngine.Operation>>}
@@ -93,8 +103,8 @@ shaka.media.MediaSourceEngine = class {
93
103
  /** @private {!Object.<string, !shaka.media.Transmuxer>} */
94
104
  this.transmuxers_ = {};
95
105
 
96
- /** @private {shaka.media.IClosedCaptionParser} */
97
- this.captionParser_ = closedCaptionParser;
106
+ /** @private {?shaka.media.IClosedCaptionParser} */
107
+ this.captionParser_ = null;
98
108
 
99
109
  /** @private {!shaka.util.PublicPromise} */
100
110
  this.mediaSourceOpen_ = new shaka.util.PublicPromise();
@@ -166,7 +176,7 @@ shaka.media.MediaSourceEngine = class {
166
176
  stream.mimeType, stream.codecs);
167
177
  const extendedMimeType = shaka.util.MimeUtils.getExtendedType(stream);
168
178
  return shaka.text.TextEngine.isTypeSupported(fullMimeType) ||
169
- MediaSource.isTypeSupported(extendedMimeType) ||
179
+ shaka.media.Capabilities.isTypeSupported(extendedMimeType) ||
170
180
  shaka.media.Transmuxer.isSupported(fullMimeType, stream.type);
171
181
  }
172
182
 
@@ -222,7 +232,7 @@ shaka.media.MediaSourceEngine = class {
222
232
  if (shaka.text.TextEngine.isTypeSupported(type)) {
223
233
  support[type] = true;
224
234
  } else {
225
- support[type] = MediaSource.isTypeSupported(type) ||
235
+ support[type] = shaka.media.Capabilities.isTypeSupported(type) ||
226
236
  shaka.media.Transmuxer.isSupported(type);
227
237
  }
228
238
  } else {
@@ -291,6 +301,7 @@ shaka.media.MediaSourceEngine = class {
291
301
  this.video_ = null;
292
302
  }
293
303
 
304
+ this.config_ = null;
294
305
  this.mediaSource_ = null;
295
306
  this.textEngine_ = null;
296
307
  this.textDisplayer_ = null;
@@ -305,6 +316,9 @@ shaka.media.MediaSourceEngine = class {
305
316
  }
306
317
  }
307
318
  this.queues_ = {};
319
+
320
+ // This object is owned by Player
321
+ this.lcevcDil_ = null;
308
322
  }
309
323
 
310
324
  /**
@@ -325,15 +339,16 @@ shaka.media.MediaSourceEngine = class {
325
339
  * shaka.extern.Stream>} streamsByType
326
340
  * A map of content types to streams. All streams must be supported
327
341
  * according to MediaSourceEngine.isStreamSupported.
328
- * @param {boolean} forceTransmuxTS
329
- * If true, this will transmux TS content even if it is natively supported.
342
+ * @param {boolean} forceTransmux
343
+ * If true, this will transmux AAC and TS content even if it is natively
344
+ * supported.
330
345
  * @param {boolean=} sequenceMode
331
346
  * If true, the media segments are appended to the SourceBuffer in strict
332
347
  * sequence.
333
348
  *
334
349
  * @return {!Promise}
335
350
  */
336
- async init(streamsByType, forceTransmuxTS, sequenceMode=false) {
351
+ async init(streamsByType, forceTransmux, sequenceMode=false) {
337
352
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
338
353
 
339
354
  await this.mediaSourceOpen_;
@@ -351,14 +366,16 @@ shaka.media.MediaSourceEngine = class {
351
366
  if (contentType == ContentType.TEXT) {
352
367
  this.reinitText(mimeType, sequenceMode);
353
368
  } else {
354
- if ((forceTransmuxTS || !MediaSource.isTypeSupported(mimeType)) &&
369
+ if ((forceTransmux ||
370
+ !shaka.media.Capabilities.isTypeSupported(mimeType)) &&
355
371
  shaka.media.Transmuxer.isSupported(mimeType, contentType)) {
356
- this.transmuxers_[contentType] = new shaka.media.Transmuxer();
372
+ this.transmuxers_[contentType] =
373
+ new shaka.media.Transmuxer(mimeType);
357
374
  mimeType =
358
- shaka.media.Transmuxer.convertTsCodecs(contentType, mimeType);
375
+ shaka.media.Transmuxer.convertCodecs(contentType, mimeType);
359
376
  }
360
-
361
- const sourceBuffer = this.mediaSource_.addSourceBuffer(mimeType);
377
+ const type = mimeType + this.config_.sourceBufferExtraFeatures;
378
+ const sourceBuffer = this.mediaSource_.addSourceBuffer(type);
362
379
 
363
380
  this.eventManager_.listen(
364
381
  sourceBuffer, 'error',
@@ -374,6 +391,16 @@ shaka.media.MediaSourceEngine = class {
374
391
  }
375
392
  }
376
393
 
394
+ /**
395
+ * Called by the Player to provide an updated configuration any time it
396
+ * changes. Must be called at least once before init().
397
+ *
398
+ * @param {shaka.extern.MediaSourceConfiguration} config
399
+ */
400
+ configure(config) {
401
+ this.config_ = config;
402
+ }
403
+
377
404
  /**
378
405
  * Reinitialize the TextEngine for a new text type.
379
406
  * @param {string} mimeType
@@ -509,6 +536,17 @@ shaka.media.MediaSourceEngine = class {
509
536
  }
510
537
  }
511
538
 
539
+ /**
540
+ * Create a new closed caption parser. This will ONLY be replaced by tests as
541
+ * a way to inject fake closed caption parser instances.
542
+ *
543
+ * @param {string} mimeType
544
+ * @return {!shaka.media.IClosedCaptionParser}
545
+ */
546
+ getCaptionParser(mimeType) {
547
+ return new shaka.media.ClosedCaptionParser(mimeType);
548
+ }
549
+
512
550
  /**
513
551
  * Enqueue an operation to append data to the SourceBuffer.
514
552
  * Start and end times are needed for TextEngine, but not for MediaSource.
@@ -544,6 +582,40 @@ shaka.media.MediaSourceEngine = class {
544
582
  return;
545
583
  }
546
584
 
585
+ const uint8ArrayData = shaka.util.BufferUtils.toUint8(data);
586
+ let mimeType = this.sourceBufferTypes_[contentType];
587
+ if (this.transmuxers_[contentType]) {
588
+ mimeType = this.transmuxers_[contentType].getOrginalMimeType();
589
+ }
590
+ if (shaka.util.TsParser.probe(uint8ArrayData)) {
591
+ const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
592
+ // The SourceBuffer timestampOffset may or may not be set yet, so this is
593
+ // the timestamp offset that would eventually compute for this segment
594
+ // either way.
595
+ const timestampOffset =
596
+ reference.startTime - (tsParser.getStartTime()[contentType] || 0);
597
+ const metadata = tsParser.getMetadata();
598
+ if (metadata.length) {
599
+ this.onMetadata_(metadata, timestampOffset,
600
+ reference ? reference.endTime : null);
601
+ }
602
+ } else {
603
+ if (shaka.media.MediaSourceEngine.RAW_FORMATS.includes(mimeType)) {
604
+ const frames = shaka.util.Id3Utils.getID3Frames(uint8ArrayData);
605
+ if (frames.length && reference) {
606
+ /** @private {shaka.extern.ID3Metadata} */
607
+ const metadata = {
608
+ cueTime: reference.startTime,
609
+ data: uint8ArrayData,
610
+ frames: frames,
611
+ dts: reference.startTime,
612
+ pts: reference.startTime,
613
+ };
614
+ this.onMetadata_([metadata], /* offset= */ 0, reference.endTime);
615
+ }
616
+ }
617
+ }
618
+
547
619
  if (this.transmuxers_[contentType]) {
548
620
  // When seeked we should reset the transmuxer captionstreams
549
621
  // so it does not ignores the captions from previous segments
@@ -558,15 +630,6 @@ shaka.media.MediaSourceEngine = class {
558
630
  if (!this.textEngine_) {
559
631
  this.reinitText('text/vtt', this.sequenceMode_);
560
632
  }
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
633
  // This doesn't work for native TS support (ex. Edge/Chromecast),
571
634
  // since no transmuxing is needed for native TS.
572
635
  if (transmuxedData.captions && transmuxedData.captions.length) {
@@ -582,10 +645,13 @@ shaka.media.MediaSourceEngine = class {
582
645
  }
583
646
 
584
647
  data = transmuxedData.data;
585
- } else if (hasClosedCaptions) {
648
+ } else if (hasClosedCaptions && contentType == ContentType.VIDEO) {
586
649
  if (!this.textEngine_) {
587
650
  this.reinitText('text/vtt', this.sequenceMode_);
588
651
  }
652
+ if (!this.captionParser_) {
653
+ this.captionParser_ = this.getCaptionParser(mimeType);
654
+ }
589
655
  // If it is the init segment for closed captions, initialize the closed
590
656
  // caption parser.
591
657
  if (!reference) {
@@ -779,7 +845,9 @@ shaka.media.MediaSourceEngine = class {
779
845
  * Fully reset the state of the caption parser owned by MediaSourceEngine.
780
846
  */
781
847
  resetCaptionParser() {
782
- this.captionParser_.reset();
848
+ if (this.captionParser_) {
849
+ this.captionParser_.reset();
850
+ }
783
851
  }
784
852
 
785
853
  /**
@@ -918,6 +986,15 @@ shaka.media.MediaSourceEngine = class {
918
986
  * @private
919
987
  */
920
988
  append_(contentType, data) {
989
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
990
+
991
+ // Append only video data to the LCEVC Dil.
992
+ if (contentType == ContentType.VIDEO && this.lcevcDil_) {
993
+ // Append video buffers to the LCEVC Dil for parsing and storing
994
+ // of LCEVC data.
995
+ this.lcevcDil_.appendBuffer(data);
996
+ }
997
+
921
998
  // This will trigger an 'updateend' event.
922
999
  this.sourceBuffers_[contentType].appendBuffer(data);
923
1000
  }
@@ -1283,6 +1360,14 @@ shaka.media.MediaSourceEngine = class {
1283
1360
 
1284
1361
  return segment;
1285
1362
  }
1363
+
1364
+ /**
1365
+ * Update LCEVC DIL object when ready for LCEVC Decodes
1366
+ * @param {?shaka.lcevc.Dil} lcevcDil
1367
+ */
1368
+ updateLcevcDil(lcevcDil) {
1369
+ this.lcevcDil_ = lcevcDil;
1370
+ }
1286
1371
  };
1287
1372
 
1288
1373
 
@@ -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;