shaka-player 3.1.5 → 3.2.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 (134) hide show
  1. package/CHANGELOG.md +129 -6
  2. package/README.md +4 -4
  3. package/build/types/polyfill +1 -0
  4. package/demo/common/asset.js +9 -7
  5. package/demo/common/assets.js +10 -1
  6. package/demo/common/message_ids.js +2 -1
  7. package/demo/config.js +5 -2
  8. package/demo/index.html +1 -1
  9. package/demo/locales/en.json +2 -1
  10. package/demo/locales/source.json +8 -4
  11. package/demo/main.js +2 -1
  12. package/dist/demo.compiled.debug.js +14 -14
  13. package/dist/demo.compiled.debug.map +2 -2
  14. package/dist/demo.compiled.js +14 -14
  15. package/dist/demo.compiled.map +2 -2
  16. package/dist/deps.js +21 -20
  17. package/dist/locales.js +30 -30
  18. package/dist/receiver.compiled.debug.js +8 -8
  19. package/dist/receiver.compiled.debug.map +2 -2
  20. package/dist/receiver.compiled.js +8 -8
  21. package/dist/receiver.compiled.map +2 -2
  22. package/dist/shaka-player.compiled.d.ts +63 -10
  23. package/dist/shaka-player.compiled.debug.d.ts +63 -10
  24. package/dist/shaka-player.compiled.debug.externs.js +786 -716
  25. package/dist/shaka-player.compiled.debug.js +563 -534
  26. package/dist/shaka-player.compiled.debug.map +4 -4
  27. package/dist/shaka-player.compiled.externs.js +786 -716
  28. package/dist/shaka-player.compiled.js +820 -809
  29. package/dist/shaka-player.compiled.map +4 -4
  30. package/dist/shaka-player.ui.d.ts +63 -10
  31. package/dist/shaka-player.ui.debug.d.ts +63 -10
  32. package/dist/shaka-player.ui.debug.externs.js +542 -472
  33. package/dist/shaka-player.ui.debug.js +594 -566
  34. package/dist/shaka-player.ui.debug.map +4 -4
  35. package/dist/shaka-player.ui.externs.js +542 -472
  36. package/dist/shaka-player.ui.js +938 -927
  37. package/dist/shaka-player.ui.map +4 -4
  38. package/docs/tutorials/ui.md +5 -5
  39. package/externs/aria.js +6 -0
  40. package/externs/shaka/ads.js +24 -1
  41. package/externs/shaka/manifest.js +6 -1
  42. package/externs/shaka/offline.js +5 -0
  43. package/externs/shaka/player.js +61 -9
  44. package/externs/shaka/text.js +10 -10
  45. package/externs/texttrack.js +3 -0
  46. package/lib/ads/ad_manager.js +16 -15
  47. package/lib/ads/client_side_ad_manager.js +6 -2
  48. package/lib/ads/server_side_ad_manager.js +19 -2
  49. package/lib/cast/cast_proxy.js +8 -0
  50. package/lib/cast/cast_utils.js +6 -1
  51. package/lib/cea/cea608_data_channel.js +56 -56
  52. package/lib/cea/cea608_memory.js +33 -33
  53. package/lib/cea/cea708_service.js +43 -43
  54. package/lib/cea/cea708_window.js +38 -38
  55. package/lib/cea/cea_decoder.js +13 -14
  56. package/lib/cea/cea_utils.js +23 -23
  57. package/lib/cea/dtvcc_packet_builder.js +7 -7
  58. package/lib/cea/i_caption_decoder.js +2 -3
  59. package/lib/cea/i_cea_parser.js +2 -2
  60. package/lib/cea/mp4_cea_parser.js +6 -6
  61. package/lib/dash/dash_parser.js +5 -0
  62. package/lib/hls/hls_parser.js +159 -12
  63. package/lib/media/closed_caption_parser.js +1 -2
  64. package/lib/media/drm_engine.js +162 -192
  65. package/lib/media/segment_index.js +4 -1
  66. package/lib/media/segment_reference.js +37 -2
  67. package/lib/media/streaming_engine.js +6 -6
  68. package/lib/net/networking_engine.js +1 -0
  69. package/lib/offline/download_manager.js +1 -2
  70. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  71. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  72. package/lib/offline/manifest_converter.js +3 -1
  73. package/lib/offline/storage.js +12 -14
  74. package/lib/player.js +426 -149
  75. package/lib/polyfill/aria.js +82 -0
  76. package/lib/routing/walker.js +2 -3
  77. package/lib/text/srt_text_parser.js +4 -4
  78. package/lib/text/text_engine.js +2 -2
  79. package/lib/text/vtt_text_parser.js +2 -2
  80. package/lib/text/web_vtt_generator.js +55 -12
  81. package/lib/util/error.js +6 -0
  82. package/lib/util/manifest_parser_utils.js +1 -0
  83. package/lib/util/mp4_box_parsers.js +20 -20
  84. package/lib/util/multi_map.js +8 -0
  85. package/lib/util/player_configuration.js +13 -1
  86. package/lib/util/stream_utils.js +168 -88
  87. package/lib/util/xml_utils.js +31 -12
  88. package/package.json +1 -1
  89. package/roadmap.md +24 -22
  90. package/shaka-player.uncompiled.js +1 -0
  91. package/test/cast/cast_utils_unit.js +1 -0
  92. package/test/cea/cea608_memory_unit.js +1 -1
  93. package/test/cea/cea708_service_unit.js +8 -8
  94. package/test/cea/cea708_window_unit.js +6 -6
  95. package/test/cea/cea_decoder_unit.js +1 -1
  96. package/test/cea/dtvcc_packet_builder_unit.js +2 -2
  97. package/test/dash/dash_parser_manifest_unit.js +43 -1
  98. package/test/hls/hls_parser_unit.js +250 -0
  99. package/test/media/drm_engine_integration.js +86 -12
  100. package/test/media/drm_engine_unit.js +310 -450
  101. package/test/offline/manifest_convert_unit.js +2 -0
  102. package/test/offline/storage_integration.js +9 -19
  103. package/test/player_integration.js +85 -0
  104. package/test/player_src_equals_integration.js +85 -0
  105. package/test/player_unit.js +25 -37
  106. package/test/test/assets/chapters.srt +11 -0
  107. package/test/test/assets/chapters.vtt +10 -0
  108. package/test/test/assets/chapters2.vtt +10 -0
  109. package/test/test/util/cea_utils.js +12 -12
  110. package/test/test/util/fake_ad_manager.js +7 -0
  111. package/test/test/util/manifest_generator.js +2 -0
  112. package/test/test/util/manifest_parser_util.js +3 -1
  113. package/test/text/web_vtt_generator_unit.js +81 -7
  114. package/test/util/stream_utils_unit.js +118 -10
  115. package/ui/airplay_button.js +1 -1
  116. package/ui/audio_language_selection.js +2 -5
  117. package/ui/cast_button.js +4 -6
  118. package/ui/constants.js +0 -3
  119. package/ui/fast_forward_button.js +2 -3
  120. package/ui/fullscreen_button.js +1 -3
  121. package/ui/language_utils.js +1 -1
  122. package/ui/loop_button.js +1 -3
  123. package/ui/mute_button.js +1 -3
  124. package/ui/overflow_menu.js +2 -3
  125. package/ui/pip_button.js +5 -7
  126. package/ui/playback_rate_selection.js +3 -6
  127. package/ui/presentation_time.js +1 -3
  128. package/ui/resolution_selection.js +4 -7
  129. package/ui/rewind_button.js +2 -3
  130. package/ui/seek_bar.js +2 -4
  131. package/ui/spacer.js +1 -1
  132. package/ui/text_selection.js +8 -11
  133. package/ui/ui_utils.js +1 -1
  134. package/ui/volume_bar.js +1 -3
@@ -8,7 +8,6 @@ goog.provide('shaka.util.StreamUtils');
8
8
 
9
9
  goog.require('goog.asserts');
10
10
  goog.require('shaka.log');
11
- goog.require('shaka.media.MediaSourceEngine');
12
11
  goog.require('shaka.text.TextEngine');
13
12
  goog.require('shaka.util.Functional');
14
13
  goog.require('shaka.util.LanguageUtils');
@@ -28,30 +27,43 @@ shaka.util.StreamUtils = class {
28
27
  * bandwidth and filter out the rest.
29
28
  * Also filters out variants that have too many audio channels.
30
29
  * @param {!shaka.extern.Manifest} manifest
30
+ * @param {!Array.<string>} preferredVideoCodecs
31
+ * @param {!Array.<string>} preferredAudioCodecs
31
32
  * @param {number} preferredAudioChannelCount
33
+ * @param {!Array.<string>} preferredDecodingAttributes
32
34
  */
33
- static chooseCodecsAndFilterManifest(manifest, preferredAudioChannelCount) {
35
+ static chooseCodecsAndFilterManifest(manifest, preferredVideoCodecs,
36
+ preferredAudioCodecs, preferredAudioChannelCount,
37
+ preferredDecodingAttributes) {
34
38
  const StreamUtils = shaka.util.StreamUtils;
35
39
 
36
- // To start, consider a subset of variants based on audio channel
40
+ let variants = manifest.variants;
41
+ // To start, choose the codecs based on configured preferences if available.
42
+ if (preferredVideoCodecs.length || preferredAudioCodecs.length) {
43
+ variants = StreamUtils.choosePreferredCodecs(variants,
44
+ preferredVideoCodecs, preferredAudioCodecs);
45
+ }
46
+
47
+ // Consider a subset of variants based on audio channel
37
48
  // preferences.
38
49
  // For some content (#1013), surround-sound variants will use a different
39
50
  // codec than stereo variants, so it is important to choose codecs **after**
40
51
  // considering the audio channel config.
41
- const variants = StreamUtils.filterVariantsByAudioChannelCount(
42
- manifest.variants, preferredAudioChannelCount);
52
+ variants = StreamUtils.filterVariantsByAudioChannelCount(
53
+ variants, preferredAudioChannelCount);
43
54
 
44
55
  // Now organize variants into buckets by codecs.
45
56
  /** @type {!shaka.util.MultiMap.<shaka.extern.Variant>} */
46
57
  let variantsByCodecs = StreamUtils.getVariantsByCodecs_(variants);
47
58
  variantsByCodecs = StreamUtils.filterVariantsByDensity_(variantsByCodecs);
48
59
 
49
- const bestCodecs = StreamUtils.findBestCodecs_(variantsByCodecs);
60
+ const bestCodecs = StreamUtils.chooseCodecsByDecodingAttributes_(
61
+ variantsByCodecs, preferredDecodingAttributes);
50
62
 
51
63
  // Filter out any variants that don't match, forcing AbrManager to choose
52
- // from the most efficient variants possible.
64
+ // from a single video codec and a single audio codec possible.
53
65
  manifest.variants = manifest.variants.filter((variant) => {
54
- const codecs = StreamUtils.getGroupVariantCodecs_(variant);
66
+ const codecs = StreamUtils.getVariantCodecs_(variant);
55
67
  if (codecs == bestCodecs) {
56
68
  return true;
57
69
  }
@@ -71,8 +83,8 @@ shaka.util.StreamUtils = class {
71
83
  static getVariantsByCodecs_(variants) {
72
84
  const variantsByCodecs = new shaka.util.MultiMap();
73
85
  for (const variant of variants) {
74
- const group = shaka.util.StreamUtils.getGroupVariantCodecs_(variant);
75
- variantsByCodecs.push(group, variant);
86
+ const variantCodecs = shaka.util.StreamUtils.getVariantCodecs_(variant);
87
+ variantsByCodecs.push(variantCodecs, variant);
76
88
  }
77
89
 
78
90
  return variantsByCodecs;
@@ -80,6 +92,8 @@ shaka.util.StreamUtils = class {
80
92
 
81
93
  /**
82
94
  * Filters variants by density.
95
+ * Get variants by codecs map with the max density where all codecs are
96
+ * present.
83
97
  *
84
98
  * @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
85
99
  * @return {!shaka.util.MultiMap.<shaka.extern.Variant>}
@@ -120,6 +134,107 @@ shaka.util.StreamUtils = class {
120
134
  return maxDensity ? codecGroupsByDensity.get(maxDensity) : variantsByCodecs;
121
135
  }
122
136
 
137
+ /**
138
+ * Choose the codecs by configured preferred audio and video codecs.
139
+ *
140
+ * @param {!Array<shaka.extern.Variant>} variants
141
+ * @param {!Array.<string>} preferredVideoCodecs
142
+ * @param {!Array.<string>} preferredAudioCodecs
143
+ * @return {!Array<shaka.extern.Variant>}
144
+ */
145
+ static choosePreferredCodecs(variants, preferredVideoCodecs,
146
+ preferredAudioCodecs) {
147
+ let subset = variants;
148
+ for (const videoCodec of preferredVideoCodecs) {
149
+ const filtered = subset.filter((variant) => {
150
+ return variant.video && variant.video.codecs.startsWith(videoCodec);
151
+ });
152
+ if (filtered.length) {
153
+ subset = filtered;
154
+ break;
155
+ }
156
+ }
157
+
158
+ for (const audioCodec of preferredAudioCodecs) {
159
+ const filtered = subset.filter((variant) => {
160
+ return variant.audio && variant.audio.codecs.startsWith(audioCodec);
161
+ });
162
+ if (filtered.length) {
163
+ subset = filtered;
164
+ break;
165
+ }
166
+ }
167
+ return subset;
168
+ }
169
+
170
+ /**
171
+ * Choose the codecs by configured preferred decoding attributes.
172
+ *
173
+ * @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
174
+ * @param {!Array.<string>} attributes
175
+ * @return {string}
176
+ * @private
177
+ */
178
+ static chooseCodecsByDecodingAttributes_(variantsByCodecs, attributes) {
179
+ const StreamUtils = shaka.util.StreamUtils;
180
+
181
+ for (const attribute of attributes) {
182
+ if (attribute == StreamUtils.DecodingAttributes.SMOOTH ||
183
+ attribute == StreamUtils.DecodingAttributes.POWER) {
184
+ variantsByCodecs = StreamUtils.chooseCodecsByMediaCapabilitiesInfo_(
185
+ variantsByCodecs, attribute);
186
+ // If we only have one smooth or powerEfficient codecs, choose it as the
187
+ // best codecs.
188
+ if (variantsByCodecs.size() == 1) {
189
+ return variantsByCodecs.keys()[0];
190
+ }
191
+ } else if (attribute == StreamUtils.DecodingAttributes.BANDWIDTH) {
192
+ return StreamUtils.findCodecsByLowestBandwidth_(variantsByCodecs);
193
+ }
194
+ }
195
+ // If there's no configured decoding preferences, or we have multiple codecs
196
+ // that meets the configured decoding preferences, choose the one with
197
+ // the lowest bandwidth.
198
+ return StreamUtils.findCodecsByLowestBandwidth_(variantsByCodecs);
199
+ }
200
+
201
+ /**
202
+ * Choose the best codecs by configured preferred MediaCapabilitiesInfo
203
+ * attributes.
204
+ *
205
+ * @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
206
+ * @param {string} attribute
207
+ * @return {!shaka.util.MultiMap.<shaka.extern.Variant>}
208
+ * @private
209
+ */
210
+ static chooseCodecsByMediaCapabilitiesInfo_(variantsByCodecs, attribute) {
211
+ let highestScore = 0;
212
+ const bestVariantsByCodecs = new shaka.util.MultiMap();
213
+ variantsByCodecs.forEach((codecs, variants) => {
214
+ let sum = 0;
215
+ let num = 0;
216
+
217
+ for (const variant of variants) {
218
+ if (variant.decodingInfos.length) {
219
+ sum += variant.decodingInfos[0][attribute] ? 1 : 0;
220
+ num++;
221
+ }
222
+ }
223
+
224
+ const averageScore = sum / num;
225
+ shaka.log.debug('codecs', codecs, 'avg', attribute, averageScore);
226
+
227
+ if (averageScore > highestScore) {
228
+ bestVariantsByCodecs.clear();
229
+ bestVariantsByCodecs.push(codecs, variants);
230
+ highestScore = averageScore;
231
+ } else if (averageScore == highestScore) {
232
+ bestVariantsByCodecs.push(codecs, variants);
233
+ }
234
+ });
235
+ return bestVariantsByCodecs;
236
+ }
237
+
123
238
  /**
124
239
  * Find the lowest-bandwidth (best) codecs.
125
240
  * Compute the average bandwidth for each group of variants.
@@ -128,7 +243,7 @@ shaka.util.StreamUtils = class {
128
243
  * @return {string}
129
244
  * @private
130
245
  */
131
- static findBestCodecs_(variantsByCodecs) {
246
+ static findCodecsByLowestBandwidth_(variantsByCodecs) {
132
247
  let bestCodecs = '';
133
248
  let lowestAverageBandwidth = Infinity;
134
249
 
@@ -163,7 +278,7 @@ shaka.util.StreamUtils = class {
163
278
  * @return {string}
164
279
  * @private
165
280
  */
166
- static getGroupVariantCodecs_(variant) {
281
+ static getVariantCodecs_(variant) {
167
282
  // Only consider the base of the codec string. For example, these should
168
283
  // both be considered the same codec: avc1.42c01e, avc1.4d401f
169
284
  let baseVideoCodec = '';
@@ -183,7 +298,7 @@ shaka.util.StreamUtils = class {
183
298
  * Filter the variants in |manifest| to only include the variants that meet
184
299
  * the given restrictions.
185
300
  *
186
- * @param {shaka.extern.Manifest} manifest
301
+ * @param {!shaka.extern.Manifest} manifest
187
302
  * @param {shaka.extern.Restrictions} restrictions
188
303
  * @param {{width: number, height:number}} maxHwResolution
189
304
  */
@@ -283,17 +398,11 @@ shaka.util.StreamUtils = class {
283
398
  * @param {shaka.media.DrmEngine} drmEngine
284
399
  * @param {?shaka.extern.Variant} currentVariant
285
400
  * @param {shaka.extern.Manifest} manifest
286
- * @param {boolean=} useMediaCapabilities
287
401
  */
288
402
  static async filterManifest(
289
- drmEngine, currentVariant, manifest, useMediaCapabilities) {
290
- if (useMediaCapabilities) {
291
- await shaka.util.StreamUtils.filterManifestByMediaCapabilities(manifest,
292
- manifest.offlineSessionIds.length > 0);
293
- } else {
294
- shaka.util.StreamUtils.filterManifestByDrm(manifest, drmEngine);
295
- shaka.util.StreamUtils.filterManifestByMediaSource(manifest);
296
- }
403
+ drmEngine, currentVariant, manifest) {
404
+ await shaka.util.StreamUtils.filterManifestByMediaCapabilities(manifest,
405
+ manifest.offlineSessionIds.length > 0);
297
406
  shaka.util.StreamUtils.filterManifestByCurrentVariant(
298
407
  currentVariant, manifest);
299
408
  shaka.util.StreamUtils.filterTextStreams_(manifest);
@@ -301,29 +410,6 @@ shaka.util.StreamUtils = class {
301
410
  }
302
411
 
303
412
 
304
- /**
305
- * Filter the variants in |manifest| to only include those that are supported
306
- * by |drm|.
307
- * @param {shaka.extern.Manifest} manifest
308
- * @param {shaka.media.DrmEngine} drmEngine
309
- */
310
- static filterManifestByDrm(manifest, drmEngine) {
311
- manifest.variants = manifest.variants.filter((variant) => {
312
- if (drmEngine && drmEngine.initialized()) {
313
- if (!drmEngine.supportsVariant(variant)) {
314
- shaka.log.debug('Dropping variant - not compatible with key system',
315
- variant);
316
- return false;
317
- }
318
- return true;
319
- }
320
-
321
- shaka.log.debug('DrmEngine is not initialized yet.');
322
- return true;
323
- });
324
- }
325
-
326
-
327
413
  /**
328
414
  * Alters the given Manifest to filter out any streams unsupported by the
329
415
  * platform via MediaCapabilities.decodingInfo() API.
@@ -398,46 +484,6 @@ shaka.util.StreamUtils = class {
398
484
  }
399
485
 
400
486
 
401
- /**
402
- * Filter the variants in the |manifest| to only include those that are
403
- * supported by media source.
404
- * TODO: remove once MediaCap implementations are done.
405
- * @param {shaka.extern.Manifest} manifest
406
- */
407
- static filterManifestByMediaSource(manifest) {
408
- const StreamUtils = shaka.util.StreamUtils;
409
-
410
- manifest.variants = manifest.variants.filter((variant) => {
411
- const audio = variant.audio;
412
- const video = variant.video;
413
-
414
- if (audio && !shaka.media.MediaSourceEngine.isStreamSupported(audio)) {
415
- shaka.log.debug('Dropping variant - audio not compatible with platform',
416
- StreamUtils.getStreamSummaryString_(audio));
417
- return false;
418
- }
419
-
420
- if (video && !shaka.media.MediaSourceEngine.isStreamSupported(video)) {
421
- shaka.log.debug('Dropping variant - video not compatible with platform',
422
- StreamUtils.getStreamSummaryString_(video));
423
- return false;
424
- }
425
-
426
- // See: https://github.com/google/shaka-player/issues/3380
427
- if (shaka.util.Platform.isXboxOne() && video &&
428
- ((video.width && video.width > 1920) ||
429
- (video.height && video.height > 1080)) &&
430
- video.codecs.includes('avc1.')) {
431
- shaka.log.debug('Dropping variant - video not compatible with platform',
432
- StreamUtils.getStreamSummaryString_(video));
433
- return false;
434
- }
435
-
436
- return true;
437
- });
438
- }
439
-
440
-
441
487
  /**
442
488
  * Get the decodingInfo results of the variants via MediaCapabilities.
443
489
  * This should be called after the DrmEngine is created and configured, and
@@ -994,6 +1040,31 @@ shaka.util.StreamUtils = class {
994
1040
  static imageStreamToTrack(stream) {
995
1041
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
996
1042
 
1043
+ let width = stream.width || null;
1044
+ let height = stream.height || null;
1045
+
1046
+ // The stream width and height represent the size of the entire thumbnail
1047
+ // sheet, so divide by the layout.
1048
+ let reference = null;
1049
+ // Note: segmentIndex is built by default for HLS, but not for DASH, but
1050
+ // in DASH this information comes at the stream level and not at the
1051
+ // segment level.
1052
+ if (stream.segmentIndex) {
1053
+ reference = stream.segmentIndex.get(0);
1054
+ }
1055
+ let layout = stream.tilesLayout;
1056
+ if (reference) {
1057
+ layout = reference.getTilesLayout() || layout;
1058
+ }
1059
+ if (layout && width != null) {
1060
+ width /= Number(layout.split('x')[0]);
1061
+ }
1062
+ if (layout && height != null) {
1063
+ height /= Number(layout.split('x')[1]);
1064
+ }
1065
+ // TODO: What happens if there are multiple grids, with different
1066
+ // layout sizes, inside this image stream?
1067
+
997
1068
  /** @type {shaka.extern.Track} */
998
1069
  const track = {
999
1070
  id: stream.id,
@@ -1003,8 +1074,8 @@ shaka.util.StreamUtils = class {
1003
1074
  language: '',
1004
1075
  label: null,
1005
1076
  kind: null,
1006
- width: stream.width || null,
1007
- height: stream.height || null,
1077
+ width,
1078
+ height,
1008
1079
  frameRate: null,
1009
1080
  pixelAspectRatio: null,
1010
1081
  hdr: null,
@@ -1021,7 +1092,7 @@ shaka.util.StreamUtils = class {
1021
1092
  channelsCount: null,
1022
1093
  audioSamplingRate: null,
1023
1094
  spatialAudio: false,
1024
- tilesLayout: stream.tilesLayout || null,
1095
+ tilesLayout: layout || null,
1025
1096
  audioBandwidth: null,
1026
1097
  videoBandwidth: null,
1027
1098
  originalVideoId: null,
@@ -1422,3 +1493,12 @@ shaka.util.StreamUtils = class {
1422
1493
 
1423
1494
  /** @private {number} */
1424
1495
  shaka.util.StreamUtils.nextTrackId_ = 0;
1496
+
1497
+ /**
1498
+ * @enum {string}
1499
+ */
1500
+ shaka.util.StreamUtils.DecodingAttributes = {
1501
+ SMOOTH: 'smooth',
1502
+ POWER: 'powerEfficient',
1503
+ BANDWIDTH: 'bandwidth',
1504
+ };
@@ -6,6 +6,7 @@
6
6
 
7
7
  goog.provide('shaka.util.XmlUtils');
8
8
 
9
+ goog.require('goog.asserts');
9
10
  goog.require('shaka.log');
10
11
  goog.require('shaka.util.StringUtils');
11
12
 
@@ -331,29 +332,46 @@ shaka.util.XmlUtils = class {
331
332
 
332
333
 
333
334
  /**
334
- * Parse a string and return the resulting root element if
335
- * it was valid XML.
335
+ * Parse a string and return the resulting root element if it was valid XML.
336
+ *
336
337
  * @param {string} xmlString
337
338
  * @param {string} expectedRootElemName
338
339
  * @return {Element}
339
340
  */
340
341
  static parseXmlString(xmlString, expectedRootElemName) {
341
342
  const parser = new DOMParser();
342
- let rootElem = null;
343
343
  let xml = null;
344
344
  try {
345
345
  xml = parser.parseFromString(xmlString, 'text/xml');
346
- } catch (exception) {}
347
- if (xml) {
348
- // The top-level element in the loaded xml should have the
349
- // same type as the element linking.
350
- if (xml.documentElement.tagName == expectedRootElemName) {
351
- rootElem = xml.documentElement;
352
- }
346
+ } catch (exception) {
347
+ shaka.log.error('XML parsing exception:', exception);
348
+ return null;
353
349
  }
354
- if (rootElem && rootElem.getElementsByTagName('parsererror').length > 0) {
350
+
351
+ // According to MDN, parseFromString never returns null.
352
+ goog.asserts.assert(xml, 'Parsed XML document cannot be null!');
353
+
354
+ // Check for empty documents.
355
+ const rootElem = xml.documentElement;
356
+ if (!rootElem) {
357
+ shaka.log.error('XML document was empty!');
355
358
  return null;
356
- } // It had a parser error in it.
359
+ }
360
+
361
+ // Check for parser errors.
362
+ const parserErrorElements = rootElem.getElementsByTagName('parsererror');
363
+ if (parserErrorElements.length) {
364
+ shaka.log.error('XML parser error found:', parserErrorElements[0]);
365
+ return null;
366
+ }
367
+
368
+ // The top-level element in the loaded XML should have the name we expect.
369
+ if (xml.documentElement.tagName != expectedRootElemName) {
370
+ shaka.log.error(
371
+ `XML tag name does not match expected "${expectedRootElemName}":`,
372
+ xml.documentElement.tagName);
373
+ return null;
374
+ }
357
375
 
358
376
  return rootElem;
359
377
  }
@@ -371,6 +389,7 @@ shaka.util.XmlUtils = class {
371
389
  const string = shaka.util.StringUtils.fromUTF8(data);
372
390
  return shaka.util.XmlUtils.parseXmlString(string, expectedRootElemName);
373
391
  } catch (exception) {
392
+ shaka.log.error('parseXmlString threw!', exception);
374
393
  return null;
375
394
  }
376
395
  }
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": "3.1.5",
4
+ "version": "3.2.3",
5
5
  "homepage": "https://github.com/google/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
package/roadmap.md CHANGED
@@ -8,49 +8,51 @@ CHANGELOG.md.
8
8
  The goals of future milestones are fluid until we begin that development cycle,
9
9
  so the exact milestone for future features is not pre-determined.
10
10
 
11
- Candidate features for future release cycles
12
- - HLS performance improvements
13
- https://github.com/google/shaka-player/issues/3363
14
- - HLS interstitial support
15
- https://github.com/google/shaka-player/issues/3364
16
- - Integration with Google Video ML/Cloud AI
11
+ Priority features up next:
17
12
  - Support containerless formats
18
13
  https://github.com/google/shaka-player/issues/2337
14
+ - Preload API
15
+ https://github.com/google/shaka-player/issues/880
16
+ - Codec-switching and order preference
17
+ https://github.com/google/shaka-player/issues/1528
18
+ https://github.com/google/shaka-player/issues/2179
19
+
20
+ Candidate features for future release cycles:
21
+ - HLS interstitial support
22
+ https://github.com/google/shaka-player/issues/3364
19
23
  - Support ID3 tags in mp4
20
24
  https://github.com/google/shaka-player/issues/3351
21
25
  - MSE support for FairPlay
22
26
  https://github.com/google/shaka-player/issues/3346
23
- - Codec-switching and order preference
24
- https://github.com/google/shaka-player/issues/1528
25
- https://github.com/google/shaka-player/issues/2179
26
- - Configurable key-system priority
27
- https://github.com/google/shaka-player/issues/3002
28
- - Preload API
29
- https://github.com/google/shaka-player/issues/880
30
- - Thumbnail tracks
31
- DASH: https://github.com/google/shaka-player/issues/559
32
- HLS: https://github.com/google/shaka-player/issues/2429
33
27
  - Smaller, more modular binary
34
28
  - Official TypeScript defs, generated from source
35
29
  https://github.com/google/shaka-player/issues/1030
30
+ - Shaka Analytics Component and an integration with BigQuery Analytics
31
+ https://github.com/google/shaka-player/issues/3359
32
+ - Integration with Google Video ML/Cloud AI
36
33
 
37
- v3.3 - 2021 Q3
34
+ v3.3 - 2021 Q3 or Q4
38
35
  - Background fetch for offline storage
39
36
  https://github.com/google/shaka-player/issues/879
40
- - Shaka Analytics Component and an integration with BigQuery Analytics
41
- https://github.com/google/shaka-player/issues/3359
37
+ - HLS performance improvements
38
+ https://github.com/google/shaka-player/issues/3363
42
39
 
43
- v3.2 - 2021 Q2
40
+ =====
41
+
42
+ v3.2 - 2021 Q3
44
43
  - MediaCapabilities to make performance-based decisions
45
44
  https://github.com/google/shaka-player/issues/1391
45
+ - Configurable key-system priority
46
+ https://github.com/google/shaka-player/issues/3002
46
47
 
47
48
  v3.1 - 2021 Q2
48
49
  - Low-latency live (LL-HLS, LL-DASH)
49
50
  https://github.com/google/shaka-player/issues/1525
50
51
  - Own CEA parser, use mux.js only for TS
51
52
  https://github.com/google/shaka-player/issues/2648
52
-
53
- =====
53
+ - Thumbnail tracks
54
+ DASH: https://github.com/google/shaka-player/issues/559
55
+ HLS: https://github.com/google/shaka-player/issues/2429
54
56
 
55
57
  v3.0 - 2020 Q2
56
58
  - Code health improvements
@@ -32,6 +32,7 @@ goog.require('shaka.offline.OfflineManifestParser');
32
32
  goog.require('shaka.offline.OfflineScheme');
33
33
  goog.require('shaka.offline.Storage');
34
34
  goog.require('shaka.offline.indexeddb.StorageMechanism');
35
+ goog.require('shaka.polyfill.Aria');
35
36
  goog.require('shaka.polyfill.EncryptionScheme');
36
37
  goog.require('shaka.polyfill.Fullscreen');
37
38
  goog.require('shaka.polyfill.MathRound');
@@ -27,6 +27,7 @@ describe('CastUtils', () => {
27
27
  'getAdManager', // Handled specially
28
28
  'getSharedConfiguration', // Handled specially
29
29
  'getNetworkingEngine', // Handled specially
30
+ 'getDrmEngine', // Handled specially
30
31
  'getMediaElement', // Handled specially
31
32
  'setMaxHardwareResolution',
32
33
  'destroy', // Should use CastProxy.destroy instead
@@ -17,7 +17,7 @@ describe('Cea608Memory', () => {
17
17
  /** @type {!shaka.cea.Cea608Memory} */
18
18
  let memory;
19
19
 
20
- /** @type {!string} */
20
+ /** @type {string} */
21
21
  const stream = 'CC1';
22
22
 
23
23
  beforeEach(() => {
@@ -19,39 +19,39 @@ describe('Cea708Service', () => {
19
19
 
20
20
  /**
21
21
  * Hide window (2 bytes), with a bitmap provided to indicate all windows.
22
- * @type {!Array<!number>}
22
+ * @type {!Array<number>}
23
23
  */
24
24
  const hideWindow = [0x8a, 0xff];
25
25
 
26
26
  /**
27
27
  * Define window (7 bytes), defines window #0 to be a visible window
28
28
  * with 32 rows and 32 columns. (We specify 31 for each since decoder adds 1).
29
- * @type {!Array<!number>}
29
+ * @type {!Array<number>}
30
30
  */
31
31
  const defineWindow = [
32
32
  0x98, 0x38, 0x00, 0x00, 0x1f, 0x1f, 0x00,
33
33
  ];
34
34
 
35
- /** @type {!number} */
35
+ /** @type {number} */
36
36
  const startTime = 1;
37
37
 
38
- /** @type {!number} */
38
+ /** @type {number} */
39
39
  const endTime = 2;
40
40
 
41
41
  /**
42
42
  * We arbitrarily pick service 1 for all of these tests.
43
- * @type {!number}
43
+ * @type {number}
44
44
  */
45
45
  const serviceNumber = 1;
46
46
 
47
- /** @type {!string} */
47
+ /** @type {string} */
48
48
  const stream = `svc${serviceNumber}`;
49
49
 
50
50
  /**
51
51
  * Takes in a array of bytes and a presentation timestamp (in seconds),
52
52
  * and converts it into a CEA-708 DTVCC Packet.
53
- * @param {!Array<!number>} bytes
54
- * @param {!number} pts
53
+ * @param {!Array<number>} bytes
54
+ * @param {number} pts
55
55
  */
56
56
  const createCea708PacketFromBytes = (bytes, pts) => {
57
57
  const cea708Bytes = bytes.map((code, i) => {
@@ -15,22 +15,22 @@ describe('Cea708Window', () => {
15
15
  /** @type {!shaka.cea.Cea708Window} */
16
16
  let window;
17
17
 
18
- /** @type {!number} */
18
+ /** @type {number} */
19
19
  const serviceNumber = 1; // We will arbitrarily pick service 1 for all tests.
20
20
 
21
- /** @type {!string} */
21
+ /** @type {string} */
22
22
  const stream = `svc${serviceNumber}`;
23
23
 
24
- /** @type {!number} */
24
+ /** @type {number} */
25
25
  const rowCount = 10;
26
26
 
27
- /** @type {!number} */
27
+ /** @type {number} */
28
28
  const colCount = 32;
29
29
 
30
- /** @type {!number} */
30
+ /** @type {number} */
31
31
  const startTime = 1;
32
32
 
33
- /** @type {!number} */
33
+ /** @type {number} */
34
34
  const endTime = 2;
35
35
 
36
36
  beforeEach(() => {
@@ -13,7 +13,7 @@ goog.require('shaka.text.Cue');
13
13
  describe('CeaDecoder', () => {
14
14
  const CeaUtils = shaka.test.CeaUtils;
15
15
 
16
- /** @type {!string} */
16
+ /** @type {string} */
17
17
  const DEFAULT_BG_COLOR = shaka.cea.CeaUtils.DEFAULT_BG_COLOR;
18
18
 
19
19
  /**
@@ -11,10 +11,10 @@ describe('DtvccPacketBuilder', () => {
11
11
  /** @type {!shaka.cea.DtvccPacketBuilder} */
12
12
  let dtvccPacketBuilder;
13
13
 
14
- /** @type {!number} */
14
+ /** @type {number} */
15
15
  const DTVCC_PACKET_START = shaka.cea.DtvccPacketBuilder.DTVCC_PACKET_START;
16
16
 
17
- /** @type {!number} */
17
+ /** @type {number} */
18
18
  const DTVCC_PACKET_DATA = shaka.cea.DtvccPacketBuilder.DTVCC_PACKET_DATA;
19
19
 
20
20
  beforeEach(() => {