shaka-player 4.8.8 → 4.9.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 (60) hide show
  1. package/README.md +5 -0
  2. package/dist/controls.css +1 -1
  3. package/dist/controls.css.map +1 -1
  4. package/dist/deps.js +5 -5
  5. package/dist/locales.js +33 -33
  6. package/dist/shaka-player.compiled.d.ts +39 -17
  7. package/dist/shaka-player.compiled.debug.d.ts +39 -17
  8. package/dist/shaka-player.compiled.debug.externs.js +32 -11
  9. package/dist/shaka-player.compiled.debug.js +574 -516
  10. package/dist/shaka-player.compiled.debug.map +4 -4
  11. package/dist/shaka-player.compiled.externs.js +32 -11
  12. package/dist/shaka-player.compiled.js +1270 -1236
  13. package/dist/shaka-player.compiled.map +4 -4
  14. package/dist/shaka-player.ui.d.ts +39 -17
  15. package/dist/shaka-player.ui.debug.d.ts +39 -17
  16. package/dist/shaka-player.ui.debug.externs.js +43 -22
  17. package/dist/shaka-player.ui.debug.js +601 -543
  18. package/dist/shaka-player.ui.debug.map +4 -4
  19. package/dist/shaka-player.ui.externs.js +43 -22
  20. package/dist/shaka-player.ui.js +1483 -1448
  21. package/dist/shaka-player.ui.map +4 -4
  22. package/externs/shaka/manifest.js +11 -1
  23. package/externs/shaka/offline.js +3 -0
  24. package/externs/shaka/player.js +105 -12
  25. package/externs/tizen.js +1 -1
  26. package/lib/abr/simple_abr_manager.js +5 -0
  27. package/lib/ads/media_tailor_ad.js +11 -0
  28. package/lib/ads/media_tailor_ad_manager.js +37 -3
  29. package/lib/cea/cea608_data_channel.js +9 -0
  30. package/lib/cea/cea_decoder.js +6 -2
  31. package/lib/dash/dash_parser.js +655 -46
  32. package/lib/dash/mpd_utils.js +7 -8
  33. package/lib/dash/segment_template.js +65 -10
  34. package/lib/hls/hls_parser.js +92 -34
  35. package/lib/media/drm_engine.js +274 -40
  36. package/lib/media/manifest_filterer.js +10 -14
  37. package/lib/media/preload_manager.js +3 -10
  38. package/lib/media/segment_utils.js +14 -3
  39. package/lib/mss/mss_parser.js +2 -0
  40. package/lib/net/http_plugin_utils.js +2 -1
  41. package/lib/net/networking_engine.js +27 -0
  42. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  43. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  44. package/lib/offline/manifest_converter.js +2 -0
  45. package/lib/offline/storage.js +1 -0
  46. package/lib/player.js +221 -14
  47. package/lib/polyfill/media_capabilities.js +10 -35
  48. package/lib/util/config_utils.js +74 -6
  49. package/lib/util/error.js +7 -0
  50. package/lib/util/mp4_box_parsers.js +23 -2
  51. package/lib/util/periods.js +51 -28
  52. package/lib/util/platform.js +3 -1
  53. package/lib/util/player_configuration.js +20 -8
  54. package/lib/util/stream_utils.js +62 -30
  55. package/lib/util/tXml.js +74 -6
  56. package/package.json +2 -2
  57. package/support.html +1 -0
  58. package/ui/controls.js +4 -0
  59. package/ui/less/ad_controls.less +2 -1
  60. package/ui/resolution_selection.js +12 -3
@@ -166,11 +166,12 @@ shaka.util.PeriodCombiner = class {
166
166
  /**
167
167
  * @param {!Array.<shaka.extern.Period>} periods
168
168
  * @param {boolean} isDynamic
169
+ * @param {boolean=} isPatchUpdate
169
170
  * @return {!Promise}
170
171
  *
171
172
  * @export
172
173
  */
173
- async combinePeriods(periods, isDynamic) {
174
+ async combinePeriods(periods, isDynamic, isPatchUpdate = false) {
174
175
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
175
176
 
176
177
  // Optimization: for single-period VOD, do nothing. This makes sure
@@ -190,6 +191,8 @@ shaka.util.PeriodCombiner = class {
190
191
  this.textStreams_ = Array.from(textStreamsPerPeriod[0].values());
191
192
  this.imageStreams_ = Array.from(imageStreamsPerPeriod[0].values());
192
193
  } else {
194
+ // How many periods we've seen before which are not included in this call.
195
+ const periodsMissing = isPatchUpdate ? this.usedPeriodIds_.size : 0;
193
196
  // Find the first period we haven't seen before. Tag all the periods we
194
197
  // see now as "used".
195
198
  let firstNewPeriodIndex = -1;
@@ -226,25 +229,29 @@ shaka.util.PeriodCombiner = class {
226
229
  audioStreamsPerPeriod,
227
230
  firstNewPeriodIndex,
228
231
  shaka.util.PeriodCombiner.cloneStream_,
229
- shaka.util.PeriodCombiner.concatenateStreams_),
232
+ shaka.util.PeriodCombiner.concatenateStreams_,
233
+ periodsMissing),
230
234
  this.combine_(
231
235
  this.videoStreams_,
232
236
  videoStreamsPerPeriod,
233
237
  firstNewPeriodIndex,
234
238
  shaka.util.PeriodCombiner.cloneStream_,
235
- shaka.util.PeriodCombiner.concatenateStreams_),
239
+ shaka.util.PeriodCombiner.concatenateStreams_,
240
+ periodsMissing),
236
241
  this.combine_(
237
242
  this.textStreams_,
238
243
  textStreamsPerPeriod,
239
244
  firstNewPeriodIndex,
240
245
  shaka.util.PeriodCombiner.cloneStream_,
241
- shaka.util.PeriodCombiner.concatenateStreams_),
246
+ shaka.util.PeriodCombiner.concatenateStreams_,
247
+ periodsMissing),
242
248
  this.combine_(
243
249
  this.imageStreams_,
244
250
  imageStreamsPerPeriod,
245
251
  firstNewPeriodIndex,
246
252
  shaka.util.PeriodCombiner.cloneStream_,
247
- shaka.util.PeriodCombiner.concatenateStreams_),
253
+ shaka.util.PeriodCombiner.concatenateStreams_,
254
+ periodsMissing),
248
255
  ]);
249
256
  }
250
257
 
@@ -367,28 +374,32 @@ shaka.util.PeriodCombiner = class {
367
374
  audioStreamDbsPerPeriod,
368
375
  /* firstNewPeriodIndex= */ 0,
369
376
  shaka.util.PeriodCombiner.cloneStreamDB_,
370
- shaka.util.PeriodCombiner.concatenateStreamDBs_);
377
+ shaka.util.PeriodCombiner.concatenateStreamDBs_,
378
+ /* periodsMissing= */ 0);
371
379
 
372
380
  const combinedVideoStreamDbs = await periodCombiner.combine_(
373
381
  /* outputStreams= */ [],
374
382
  videoStreamDbsPerPeriod,
375
383
  /* firstNewPeriodIndex= */ 0,
376
384
  shaka.util.PeriodCombiner.cloneStreamDB_,
377
- shaka.util.PeriodCombiner.concatenateStreamDBs_);
385
+ shaka.util.PeriodCombiner.concatenateStreamDBs_,
386
+ /* periodsMissing= */ 0);
378
387
 
379
388
  const combinedTextStreamDbs = await periodCombiner.combine_(
380
389
  /* outputStreams= */ [],
381
390
  textStreamDbsPerPeriod,
382
391
  /* firstNewPeriodIndex= */ 0,
383
392
  shaka.util.PeriodCombiner.cloneStreamDB_,
384
- shaka.util.PeriodCombiner.concatenateStreamDBs_);
393
+ shaka.util.PeriodCombiner.concatenateStreamDBs_,
394
+ /* periodsMissing= */ 0);
385
395
 
386
396
  const combinedImageStreamDbs = await periodCombiner.combine_(
387
397
  /* outputStreams= */ [],
388
398
  imageStreamDbsPerPeriod,
389
399
  /* firstNewPeriodIndex= */ 0,
390
400
  shaka.util.PeriodCombiner.cloneStreamDB_,
391
- shaka.util.PeriodCombiner.concatenateStreamDBs_);
401
+ shaka.util.PeriodCombiner.concatenateStreamDBs_,
402
+ /* periodsMissing= */ 0);
392
403
 
393
404
  // Recreate variantIds from scratch in the output.
394
405
  // HLS content is always single-period, so the early return at the top of
@@ -435,6 +446,7 @@ shaka.util.PeriodCombiner = class {
435
446
  * @param {function(T):T} clone Make a clone of an input stream.
436
447
  * @param {function(T, T)} concat Concatenate the second stream onto the end
437
448
  * of the first.
449
+ * @param {number} periodsMissing The number of periods missing
438
450
  *
439
451
  * @return {!Promise.<!Array.<T>>} The same array passed to outputStreams,
440
452
  * modified to include any newly-created streams.
@@ -445,15 +457,18 @@ shaka.util.PeriodCombiner = class {
445
457
  * @private
446
458
  */
447
459
  async combine_(
448
- outputStreams, streamsPerPeriod, firstNewPeriodIndex, clone, concat) {
460
+ outputStreams, streamsPerPeriod, firstNewPeriodIndex, clone, concat,
461
+ periodsMissing) {
449
462
  const unusedStreamsPerPeriod = [];
450
- for (let i = 0; i < firstNewPeriodIndex; i++) {
451
- // This period's streams have all been used already.
452
- unusedStreamsPerPeriod.push(new Set());
453
- }
454
- for (let i = firstNewPeriodIndex; i < streamsPerPeriod.length; i++) {
455
- // This periods streams are all new.
456
- unusedStreamsPerPeriod.push(new Set(streamsPerPeriod[i].values()));
463
+
464
+ for (let i = 0; i < streamsPerPeriod.length; i++) {
465
+ if (i >= firstNewPeriodIndex) {
466
+ // This periods streams are all new.
467
+ unusedStreamsPerPeriod.push(new Set(streamsPerPeriod[i].values()));
468
+ } else {
469
+ // This period's streams have all been used already.
470
+ unusedStreamsPerPeriod.push(new Set());
471
+ }
457
472
  }
458
473
 
459
474
  // First, extend all existing output Streams into the new periods.
@@ -461,7 +476,7 @@ shaka.util.PeriodCombiner = class {
461
476
  // eslint-disable-next-line no-await-in-loop
462
477
  const ok = await this.extendExistingOutputStream_(
463
478
  outputStream, streamsPerPeriod, firstNewPeriodIndex, concat,
464
- unusedStreamsPerPeriod);
479
+ unusedStreamsPerPeriod, periodsMissing);
465
480
  if (!ok) {
466
481
  // This output Stream was not properly extended to include streams from
467
482
  // the new period. This is likely a bug in our algorithm, so throw an
@@ -532,6 +547,7 @@ shaka.util.PeriodCombiner = class {
532
547
  * of the first.
533
548
  * @param {!Array.<!Set.<T>>} unusedStreamsPerPeriod An array of sets of
534
549
  * unused streams from each period.
550
+ * @param {number} periodsMissing How many periods are missing in this update.
535
551
  *
536
552
  * @return {!Promise.<boolean>}
537
553
  *
@@ -543,8 +559,9 @@ shaka.util.PeriodCombiner = class {
543
559
  */
544
560
  async extendExistingOutputStream_(
545
561
  outputStream, streamsPerPeriod, firstNewPeriodIndex, concat,
546
- unusedStreamsPerPeriod) {
547
- this.findMatchesInAllPeriods_(streamsPerPeriod, outputStream);
562
+ unusedStreamsPerPeriod, periodsMissing) {
563
+ this.findMatchesInAllPeriods_(streamsPerPeriod,
564
+ outputStream, periodsMissing > 0);
548
565
 
549
566
  // This only exists where T == Stream, and this should only ever be called
550
567
  // on Stream types. StreamDB should not have pre-existing output streams.
@@ -561,11 +578,11 @@ shaka.util.PeriodCombiner = class {
561
578
  // the output's MetaSegmentIndex.
562
579
  if (outputStream.segmentIndex) {
563
580
  await shaka.util.PeriodCombiner.extendOutputSegmentIndex_(outputStream,
564
- firstNewPeriodIndex);
581
+ firstNewPeriodIndex + periodsMissing);
565
582
  }
566
583
 
567
584
  shaka.util.PeriodCombiner.extendOutputStream_(outputStream,
568
- firstNewPeriodIndex, concat, unusedStreamsPerPeriod);
585
+ firstNewPeriodIndex, concat, unusedStreamsPerPeriod, periodsMissing);
569
586
  return true;
570
587
  }
571
588
 
@@ -664,7 +681,8 @@ shaka.util.PeriodCombiner = class {
664
681
  return null;
665
682
  }
666
683
  shaka.util.PeriodCombiner.extendOutputStream_(outputStream,
667
- /* firstNewPeriodIndex= */ 0, concat, unusedStreamsPerPeriod);
684
+ /* firstNewPeriodIndex= */ 0, concat, unusedStreamsPerPeriod,
685
+ /* periodsMissing= */ 0);
668
686
 
669
687
  return outputStream;
670
688
  }
@@ -678,6 +696,7 @@ shaka.util.PeriodCombiner = class {
678
696
  * of the first.
679
697
  * @param {!Array.<!Set.<T>>} unusedStreamsPerPeriod An array of sets of
680
698
  * unused streams from each period.
699
+ * @param {number} periodsMissing How many periods are missing in this update
681
700
  *
682
701
  * @template T
683
702
  * Accepts either a StreamDB or Stream type.
@@ -685,7 +704,8 @@ shaka.util.PeriodCombiner = class {
685
704
  * @private
686
705
  */
687
706
  static extendOutputStream_(
688
- outputStream, firstNewPeriodIndex, concat, unusedStreamsPerPeriod) {
707
+ outputStream, firstNewPeriodIndex, concat, unusedStreamsPerPeriod,
708
+ periodsMissing) {
689
709
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
690
710
  const LanguageUtils = shaka.util.LanguageUtils;
691
711
  const matches = outputStream.matchedStreams;
@@ -697,7 +717,8 @@ shaka.util.PeriodCombiner = class {
697
717
 
698
718
  // Concatenate the new matches onto the stream, starting at the first new
699
719
  // period.
700
- for (let i = firstNewPeriodIndex; i < matches.length; i++) {
720
+ const start = firstNewPeriodIndex + periodsMissing;
721
+ for (let i = start; i < matches.length; i++) {
701
722
  const match = matches[i];
702
723
  concat(outputStream, match);
703
724
 
@@ -715,7 +736,7 @@ shaka.util.PeriodCombiner = class {
715
736
  }
716
737
 
717
738
  if (used) {
718
- unusedStreamsPerPeriod[i].delete(match);
739
+ unusedStreamsPerPeriod[i - periodsMissing].delete(match);
719
740
  // Add the full mimetypes to the stream.
720
741
  if (match.fullMimeTypes) {
721
742
  for (const fullMimeType of match.fullMimeTypes.values()) {
@@ -937,14 +958,16 @@ shaka.util.PeriodCombiner = class {
937
958
  *
938
959
  * @param {!Array<!Map<string, T>>} streamsPerPeriod
939
960
  * @param {T} outputStream
961
+ * @param {boolean=} shouldAppend
940
962
  *
941
963
  * @template T
942
964
  * Accepts either a StreamDB or Stream type.
943
965
  *
944
966
  * @private
945
967
  */
946
- findMatchesInAllPeriods_(streamsPerPeriod, outputStream) {
947
- const matches = [];
968
+ findMatchesInAllPeriods_(streamsPerPeriod, outputStream,
969
+ shouldAppend = false) {
970
+ const matches = shouldAppend ? outputStream.matchedStreams : [];
948
971
  for (const streams of streamsPerPeriod) {
949
972
  const match = this.findBestMatchInPeriod_(streams, outputStream);
950
973
  if (!match) {
@@ -648,10 +648,12 @@ shaka.util.Platform = class {
648
648
  /**
649
649
  * Detect the maximum resolution that the platform's hardware can handle.
650
650
  *
651
- * @return {!Promise.<{width: number, height: number}>}
651
+ * @return {!Promise.<shaka.extern.Resolution>}
652
652
  */
653
653
  static async detectMaxHardwareResolution() {
654
654
  const Platform = shaka.util.Platform;
655
+
656
+ /** @type {shaka.extern.Resolution} */
655
657
  const maxResolution = {
656
658
  width: Infinity,
657
659
  height: Infinity,
@@ -150,6 +150,7 @@ shaka.util.PlayerConfiguration = class {
150
150
  multiTypeVariantsAllowed,
151
151
  useStreamOnceInPeriodFlattening: false,
152
152
  updatePeriod: -1,
153
+ enableFastSwitching: true,
153
154
  },
154
155
  hls: {
155
156
  ignoreTextStreamFailures: false,
@@ -165,6 +166,7 @@ shaka.util.PlayerConfiguration = class {
165
166
  sequenceMode: shaka.util.Platform.supportsSequenceMode(),
166
167
  ignoreManifestTimestampsInSegmentsMode: false,
167
168
  disableCodecGuessing: false,
169
+ disableClosedCaptionsDetection: false,
168
170
  allowLowLatencyByteRangeOptimization: true,
169
171
  },
170
172
  mss: {
@@ -221,6 +223,7 @@ shaka.util.PlayerConfiguration = class {
221
223
  inaccurateManifestTolerance: 2,
222
224
  lowLatencyMode: false,
223
225
  autoLowLatencyMode: false,
226
+ forceHTTP: false,
224
227
  forceHTTPS: false,
225
228
  preferNativeHls: false,
226
229
  updateIntervalSeconds: 1,
@@ -236,6 +239,7 @@ shaka.util.PlayerConfiguration = class {
236
239
  disableTextPrefetch: false,
237
240
  disableVideoPrefetch: false,
238
241
  liveSync: false,
242
+ liveSyncTargetLatencyTolerance: 0.5,
239
243
  liveSyncMaxLatency: 1,
240
244
  liveSyncPlaybackRate: 1.1,
241
245
  liveSyncMinLatency: 0,
@@ -248,7 +252,10 @@ shaka.util.PlayerConfiguration = class {
248
252
  vodDynamicPlaybackRateLowBufferRate: 0.95,
249
253
  vodDynamicPlaybackRateBufferRatio: 0.5,
250
254
  infiniteLiveStreamDuration: false,
255
+ preloadNextUrlWindow: 30,
251
256
  loadTimeout: 30,
257
+ clearDecodingCache: shaka.util.Platform.isPS4() ||
258
+ shaka.util.Platform.isPS5(),
252
259
  };
253
260
 
254
261
  // WebOS, Tizen, Chromecast and Hisense have long hardware pipelines
@@ -317,6 +324,8 @@ shaka.util.PlayerConfiguration = class {
317
324
  maxFrameRate: Infinity,
318
325
  minBandwidth: 0,
319
326
  maxBandwidth: Infinity,
327
+ minChannelsCount: 0,
328
+ maxChannelsCount: Infinity,
320
329
  },
321
330
  advanced: {
322
331
  minTotalBytes: 128e3,
@@ -329,6 +338,7 @@ shaka.util.PlayerConfiguration = class {
329
338
  ignoreDevicePixelRatio: false,
330
339
  clearBufferSwitch: false,
331
340
  safeMarginSwitch: 0,
341
+ cacheLoadThreshold: 20,
332
342
  };
333
343
 
334
344
  const cmcd = {
@@ -369,20 +379,19 @@ shaka.util.PlayerConfiguration = class {
369
379
  },
370
380
  };
371
381
 
382
+ let customPlayheadTracker = false;
372
383
  let skipPlayDetection = false;
373
- if (shaka.util.Platform.isWebOS() ||
374
- shaka.util.Platform.isTizen() ||
375
- shaka.util.Platform.isChromecast() ||
376
- shaka.util.Platform.isHisense() ||
377
- shaka.util.Platform.isPS5() ||
378
- shaka.util.Platform.isPS4() ||
379
- shaka.util.Platform.isXboxOne()) {
384
+ let supportsMultipleMediaElements = true;
385
+ if (shaka.util.Platform.isSmartTV()) {
386
+ customPlayheadTracker = true;
380
387
  skipPlayDetection = true;
388
+ supportsMultipleMediaElements = false;
381
389
  }
382
390
 
383
391
  const ads = {
384
- customPlayheadTracker: false,
392
+ customPlayheadTracker,
385
393
  skipPlayDetection,
394
+ supportsMultipleMediaElements,
386
395
  };
387
396
 
388
397
  const textDisplayer = {
@@ -426,6 +435,8 @@ shaka.util.PlayerConfiguration = class {
426
435
  maxFrameRate: Infinity,
427
436
  minBandwidth: 0,
428
437
  maxBandwidth: Infinity,
438
+ minChannelsCount: 0,
439
+ maxChannelsCount: Infinity,
429
440
  },
430
441
  playRangeStart: 0,
431
442
  playRangeEnd: Infinity,
@@ -474,6 +485,7 @@ shaka.util.PlayerConfiguration = class {
474
485
  serverCertificate: new Uint8Array(0),
475
486
  serverCertificateUri: '',
476
487
  individualizationServer: '',
488
+ headers: {},
477
489
  },
478
490
  };
479
491
  return shaka.util.ConfigUtils.mergeConfigObjects(
@@ -232,7 +232,7 @@ shaka.util.StreamUtils = class {
232
232
  *
233
233
  * @param {!shaka.extern.Manifest} manifest
234
234
  * @param {shaka.extern.Restrictions} restrictions
235
- * @param {{width: number, height:number}} maxHwResolution
235
+ * @param {shaka.extern.Resolution} maxHwResolution
236
236
  */
237
237
  static filterByRestrictions(manifest, restrictions, maxHwResolution) {
238
238
  manifest.variants = manifest.variants.filter((variant) => {
@@ -245,7 +245,7 @@ shaka.util.StreamUtils = class {
245
245
  * @param {shaka.extern.Variant} variant
246
246
  * @param {shaka.extern.Restrictions} restrictions
247
247
  * Configured restrictions from the user.
248
- * @param {{width: number, height: number}} maxHwRes
248
+ * @param {shaka.extern.Resolution} maxHwRes
249
249
  * The maximum resolution the hardware can handle.
250
250
  * This is applied separately from user restrictions because the setting
251
251
  * should not be easily replaced by the user's configuration.
@@ -289,7 +289,7 @@ shaka.util.StreamUtils = class {
289
289
  }
290
290
  }
291
291
 
292
- // |variant.frameRate| can be undefined, which breaks
292
+ // |variant.video.frameRate| can be undefined, which breaks
293
293
  // the math, so make sure they are there first.
294
294
  if (variant && variant.video && variant.video.frameRate) {
295
295
  if (!inRange(variant.video.frameRate,
@@ -299,6 +299,16 @@ shaka.util.StreamUtils = class {
299
299
  }
300
300
  }
301
301
 
302
+ // |variant.audio.channelsCount| can be undefined, which breaks
303
+ // the math, so make sure they are there first.
304
+ if (variant && variant.audio && variant.audio.channelsCount) {
305
+ if (!inRange(variant.audio.channelsCount,
306
+ restrictions.minChannelsCount,
307
+ restrictions.maxChannelsCount)) {
308
+ return false;
309
+ }
310
+ }
311
+
302
312
  if (!inRange(variant.bandwidth,
303
313
  restrictions.minBandwidth,
304
314
  restrictions.maxBandwidth)) {
@@ -312,7 +322,7 @@ shaka.util.StreamUtils = class {
312
322
  /**
313
323
  * @param {!Array.<shaka.extern.Variant>} variants
314
324
  * @param {shaka.extern.Restrictions} restrictions
315
- * @param {{width: number, height: number}} maxHwRes
325
+ * @param {shaka.extern.Resolution} maxHwRes
316
326
  * @return {boolean} Whether the tracks changed.
317
327
  */
318
328
  static applyRestrictions(variants, restrictions, maxHwRes) {
@@ -813,6 +823,9 @@ shaka.util.StreamUtils = class {
813
823
  break;
814
824
  }
815
825
  }
826
+ if (video.colorGamut) {
827
+ videoConfig.colorGamut = video.colorGamut;
828
+ }
816
829
  videoConfigs.push(videoConfig);
817
830
  }
818
831
  }
@@ -931,38 +944,44 @@ shaka.util.StreamUtils = class {
931
944
  }
932
945
 
933
946
  if (audio) {
934
- // See: https://github.com/shaka-project/shaka-player/issues/4659
935
- if (info.audioRobustness != '') {
936
- if (!keySystemConfig.audio) {
937
- // KeySystemTrackConfiguration
938
- keySystemConfig.audio = {
939
- robustness: info.audioRobustness,
940
- };
941
- } else {
942
- keySystemConfig.audio.robustness =
943
- keySystemConfig.audio.robustness || info.audioRobustness;
944
- }
945
- } else if (!keySystemConfig.audio) {
947
+ if (!keySystemConfig.audio) {
946
948
  // KeySystemTrackConfiguration
947
- keySystemConfig.audio = {};
949
+ keySystemConfig.audio = {
950
+ encryptionScheme: info.encryptionScheme,
951
+ robustness: info.audioRobustness,
952
+ };
953
+ } else {
954
+ keySystemConfig.audio.encryptionScheme =
955
+ keySystemConfig.audio.encryptionScheme ||
956
+ info.encryptionScheme;
957
+ keySystemConfig.audio.robustness =
958
+ keySystemConfig.audio.robustness ||
959
+ info.audioRobustness;
960
+ }
961
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
962
+ if (keySystemConfig.audio.robustness == '') {
963
+ delete keySystemConfig.audio.robustness;
948
964
  }
949
965
  }
950
966
 
951
967
  if (video) {
952
- // See: https://github.com/shaka-project/shaka-player/issues/4659
953
- if (info.videoRobustness != '') {
954
- if (!keySystemConfig.video) {
955
- // KeySystemTrackConfiguration
956
- keySystemConfig.video = {
957
- robustness: info.videoRobustness,
958
- };
959
- } else {
960
- keySystemConfig.video.robustness =
961
- keySystemConfig.video.robustness || info.videoRobustness;
962
- }
963
- } else if (!keySystemConfig.video) {
968
+ if (!keySystemConfig.video) {
964
969
  // KeySystemTrackConfiguration
965
- keySystemConfig.video = {};
970
+ keySystemConfig.video = {
971
+ encryptionScheme: info.encryptionScheme,
972
+ robustness: info.videoRobustness,
973
+ };
974
+ } else {
975
+ keySystemConfig.video.encryptionScheme =
976
+ keySystemConfig.video.encryptionScheme ||
977
+ info.encryptionScheme;
978
+ keySystemConfig.video.robustness =
979
+ keySystemConfig.video.robustness ||
980
+ info.videoRobustness;
981
+ }
982
+ // See: https://github.com/shaka-project/shaka-player/issues/4659
983
+ if (keySystemConfig.video.robustness == '') {
984
+ delete keySystemConfig.video.robustness;
966
985
  }
967
986
  }
968
987
  }
@@ -1277,6 +1296,7 @@ shaka.util.StreamUtils = class {
1277
1296
  frameRate: null,
1278
1297
  pixelAspectRatio: null,
1279
1298
  hdr: null,
1299
+ colorGamut: null,
1280
1300
  videoLayout: null,
1281
1301
  mimeType: mimeType,
1282
1302
  audioMimeType: audioMimeType,
@@ -1313,6 +1333,7 @@ shaka.util.StreamUtils = class {
1313
1333
  track.pixelAspectRatio = video.pixelAspectRatio || null;
1314
1334
  track.videoBandwidth = video.bandwidth || null;
1315
1335
  track.hdr = video.hdr || null;
1336
+ track.colorGamut = video.colorGamut || null;
1316
1337
  track.videoLayout = video.videoLayout || null;
1317
1338
  }
1318
1339
 
@@ -1354,6 +1375,7 @@ shaka.util.StreamUtils = class {
1354
1375
  frameRate: null,
1355
1376
  pixelAspectRatio: null,
1356
1377
  hdr: null,
1378
+ colorGamut: null,
1357
1379
  videoLayout: null,
1358
1380
  mimeType: stream.mimeType,
1359
1381
  audioMimeType: null,
@@ -1431,6 +1453,7 @@ shaka.util.StreamUtils = class {
1431
1453
  frameRate: null,
1432
1454
  pixelAspectRatio: null,
1433
1455
  hdr: null,
1456
+ colorGamut: null,
1434
1457
  videoLayout: null,
1435
1458
  mimeType: stream.mimeType,
1436
1459
  audioMimeType: null,
@@ -1558,6 +1581,7 @@ shaka.util.StreamUtils = class {
1558
1581
  frameRate: null,
1559
1582
  pixelAspectRatio: null,
1560
1583
  hdr: null,
1584
+ colorGamut: null,
1561
1585
  videoLayout: null,
1562
1586
  mimeType: null,
1563
1587
  audioMimeType: null,
@@ -1829,6 +1853,14 @@ shaka.util.StreamUtils = class {
1829
1853
 
1830
1854
  return 'unexpected stream type';
1831
1855
  }
1856
+
1857
+
1858
+ /**
1859
+ * Clears underlying decoding config cache.
1860
+ */
1861
+ static clearDecodingConfigCache() {
1862
+ shaka.util.StreamUtils.decodingConfigCache_ = {};
1863
+ }
1832
1864
  };
1833
1865
 
1834
1866
 
package/lib/util/tXml.js CHANGED
@@ -741,28 +741,94 @@ shaka.util.TXml = class {
741
741
  * @return {!Array<!shaka.util.TXml.PathNode>}
742
742
  */
743
743
  static parseXpath(exprString) {
744
+ const StringUtils = shaka.util.StringUtils;
744
745
  const returnPaths = [];
745
746
  // Split string by paths but ignore '/' in quotes
746
- const paths = exprString
747
+ const paths = StringUtils.htmlUnescape(exprString)
747
748
  .split(/\/+(?=(?:[^'"]*['"][^'"]*['"])*[^'"]*$)/);
748
749
  for (const path of paths) {
749
- const nodeName = path.match(/\b([A-Z])\w+/);
750
+ const nodeName = path.match(/^([\w]+)/);
750
751
 
751
- // We only want the id attribute in which case
752
- // /'(.*?)'/ will suffice to get it.
753
- const idAttr = path.match(/(@id='(.*?)')/);
754
752
  if (nodeName) {
753
+ // We only want the id attribute in which case
754
+ // /'(.*?)'/ will suffice to get it.
755
+ const idAttr = path.match(/(@id='(.*?)')/);
756
+ const position = path.match(/\[(\d+)\]/);
755
757
  returnPaths.push({
756
758
  name: nodeName[0],
757
759
  id: idAttr ?
758
760
  idAttr[0].match(/'(.*?)'/)[0].replace(/'/gm, '') : null,
761
+ // position is counted from 1, so make it readable for devs
762
+ position: position ? Number(position[1]) - 1 : null,
763
+ attribute: path.split('/@')[1] || null,
759
764
  });
765
+ } else if (path.startsWith('@') && returnPaths.length) {
766
+ returnPaths[returnPaths.length - 1].attribute = path.slice(1);
760
767
  }
761
768
  }
762
769
  return returnPaths;
763
770
  }
764
771
 
765
772
 
773
+ /**
774
+ * Modifies nodes in specified array by adding or removing nodes
775
+ * and updating attributes.
776
+ * @param {!Array<shaka.extern.xml.Node>} nodes
777
+ * @param {!shaka.extern.xml.Node} patchNode
778
+ */
779
+ static modifyNodes(nodes, patchNode) {
780
+ const TXml = shaka.util.TXml;
781
+
782
+ const paths = TXml.parseXpath(patchNode.attributes['sel'] || '');
783
+ if (!paths.length) {
784
+ return;
785
+ }
786
+ const lastNode = paths[paths.length - 1];
787
+ const position = patchNode.attributes['pos'] || null;
788
+
789
+ let index = lastNode.position;
790
+ if (index === null) {
791
+ index = position === 'prepend' ? 0 : nodes.length;
792
+ } else if (position === 'prepend') {
793
+ --index;
794
+ } else if (position === 'after') {
795
+ ++index;
796
+ }
797
+ const action = patchNode.tagName;
798
+ const attribute = lastNode.attribute;
799
+
800
+ // Modify attribute
801
+ if (attribute) {
802
+ TXml.modifyNodeAttribute(nodes[index], action, attribute,
803
+ TXml.getContents(patchNode) || '');
804
+ // Rearrange nodes
805
+ } else {
806
+ if (action === 'remove' || action === 'replace') {
807
+ nodes.splice(index, 1);
808
+ }
809
+ if (action === 'add' || action === 'replace') {
810
+ const newNodes = patchNode.children;
811
+ nodes.splice(index, 0, ...newNodes);
812
+ }
813
+ }
814
+ }
815
+
816
+
817
+ /**
818
+ * @param {!shaka.extern.xml.Node} node
819
+ * @param {string} action
820
+ * @param {string} attribute
821
+ * @param {string} value
822
+ */
823
+ static modifyNodeAttribute(node, action, attribute, value) {
824
+ if (action === 'remove') {
825
+ delete node.attributes[attribute];
826
+ } else if (action === 'add' || action === 'replace') {
827
+ node.attributes[attribute] = value;
828
+ }
829
+ }
830
+
831
+
766
832
  /**
767
833
  * Converts a tXml node to DOM element.
768
834
  * @param {shaka.extern.xml.Node} node
@@ -808,7 +874,9 @@ shaka.util.TXml.knownNameSpaces_ = new Map([]);
808
874
  /**
809
875
  * @typedef {{
810
876
  * name: string,
811
- * id: ?string
877
+ * id: ?string,
878
+ * position: ?number,
879
+ * attribute: ?string
812
880
  * }}
813
881
  */
814
882
  shaka.util.TXml.PathNode;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "4.8.8",
4
+ "version": "4.9.0",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -105,7 +105,7 @@
105
105
  "prepublishOnly": "python build/checkversion.py && python build/all.py --force"
106
106
  },
107
107
  "dependencies": {
108
- "eme-encryption-scheme-polyfill": "^2.1.1"
108
+ "eme-encryption-scheme-polyfill": "^2.1.5"
109
109
  },
110
110
  "clean-package": {
111
111
  "remove": [
package/support.html CHANGED
@@ -76,6 +76,7 @@
76
76
 
77
77
  function doTest() {
78
78
  shaka.polyfill.installAll();
79
+
79
80
  if (shaka.Player.isBrowserSupported()) {
80
81
  shaka.Player.probeSupport().then(function(support) {
81
82
  printSupport(JSON.stringify(support, null, ' '));