shaka-player 4.7.12 → 4.7.13

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 (35) hide show
  1. package/dist/deps.js +3 -3
  2. package/dist/locales.js +32 -32
  3. package/dist/shaka-player.compiled.d.ts +2 -2
  4. package/dist/shaka-player.compiled.debug.d.ts +2 -2
  5. package/dist/shaka-player.compiled.debug.js +224 -220
  6. package/dist/shaka-player.compiled.debug.map +3 -3
  7. package/dist/shaka-player.compiled.js +1148 -1140
  8. package/dist/shaka-player.compiled.map +4 -4
  9. package/dist/shaka-player.ui.d.ts +2 -2
  10. package/dist/shaka-player.ui.debug.d.ts +2 -2
  11. package/dist/shaka-player.ui.debug.js +355 -350
  12. package/dist/shaka-player.ui.debug.map +3 -3
  13. package/dist/shaka-player.ui.js +1304 -1296
  14. package/dist/shaka-player.ui.map +4 -4
  15. package/externs/shaka/manifest.js +11 -1
  16. package/externs/shaka/offline.js +7 -1
  17. package/lib/dash/dash_parser.js +10 -3
  18. package/lib/dash/segment_base.js +8 -1
  19. package/lib/dash/segment_list.js +24 -18
  20. package/lib/dash/segment_template.js +21 -2
  21. package/lib/hls/hls_parser.js +18 -1
  22. package/lib/media/media_source_engine.js +74 -24
  23. package/lib/media/playhead.js +3 -3
  24. package/lib/media/segment_index.js +21 -20
  25. package/lib/media/streaming_engine.js +2 -14
  26. package/lib/mss/mss_parser.js +4 -0
  27. package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
  28. package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
  29. package/lib/offline/manifest_converter.js +10 -3
  30. package/lib/offline/storage.js +2 -0
  31. package/lib/player.js +16 -3
  32. package/lib/util/mime_utils.js +10 -5
  33. package/lib/util/periods.js +5 -37
  34. package/lib/util/stream_utils.js +334 -271
  35. package/package.json +1 -1
@@ -400,7 +400,8 @@ shaka.extern.FetchCryptoKeysFunction;
400
400
  * undefined),
401
401
  * mssPrivateData: (shaka.extern.MssPrivateData|undefined),
402
402
  * external: boolean,
403
- * fastSwitching: boolean
403
+ * fastSwitching: boolean,
404
+ * fullMimeTypes: !Set.<string>
404
405
  * }}
405
406
  *
406
407
  * @description
@@ -430,10 +431,14 @@ shaka.extern.FetchCryptoKeysFunction;
430
431
  * @property {string} mimeType
431
432
  * <i>Required.</i> <br>
432
433
  * The Stream's MIME type, e.g., 'audio/mp4', 'video/webm', or 'text/vtt'.
434
+ * In the case of a stream that adapts between different periods with
435
+ * different MIME types, this represents only the first period.
433
436
  * @property {string} codecs
434
437
  * <i>Defaults to '' (i.e., unknown / not needed).</i> <br>
435
438
  * The Stream's codecs, e.g., 'avc1.4d4015' or 'vp9', which must be
436
439
  * compatible with the Stream's MIME type. <br>
440
+ * In the case of a stream that adapts between different periods with
441
+ * different codecs, this represents only the first period.
437
442
  * See {@link https://tools.ietf.org/html/rfc6381}
438
443
  * @property {(number|undefined)} frameRate
439
444
  * <i>Video streams only.</i> <br>
@@ -535,6 +540,11 @@ shaka.extern.FetchCryptoKeysFunction;
535
540
  * Eg: external text tracks.
536
541
  * @property {boolean} fastSwitching
537
542
  * Indicate if the stream should be used for fast switching.
543
+ * @property {!Set.<string>} fullMimeTypes
544
+ * A set of full MIME types (e.g. MIME types plus codecs information), that
545
+ * represents the types used in each period of the original manifest.
546
+ * Meant for being used by compatibility checking, such as with
547
+ * MediaSource.isTypeSupported.
538
548
  *
539
549
  * @exportDoc
540
550
  */
@@ -230,7 +230,9 @@ shaka.extern.StreamDB;
230
230
  * tilesLayout: ?string,
231
231
  * pendingSegmentRefId: (string|undefined),
232
232
  * pendingInitSegmentRefId: (string|undefined),
233
- * dataKey: number
233
+ * dataKey: number,
234
+ * mimeType: ?string,
235
+ * codecs: ?string
234
236
  * }}
235
237
  *
236
238
  * @property {?number} initSegmentKey
@@ -263,6 +265,10 @@ shaka.extern.StreamDB;
263
265
  * downloaded.
264
266
  * @property {number} dataKey
265
267
  * The key to the data in storage.
268
+ * @property {?string} mimeType
269
+ * The mimeType of the segment.
270
+ * @property {?string} codecs
271
+ * The codecs of the segment.
266
272
  */
267
273
  shaka.extern.SegmentDB;
268
274
 
@@ -1485,8 +1485,13 @@ shaka.dash.DashParser = class {
1485
1485
  const getBaseUris = context.representation.getBaseUris;
1486
1486
  streamInfo = {
1487
1487
  generateSegmentIndex: () => {
1488
- return Promise.resolve(shaka.media.SegmentIndex.forSingleSegment(
1489
- periodStart, duration, getBaseUris()));
1488
+ const segmentIndex = shaka.media.SegmentIndex.forSingleSegment(
1489
+ periodStart, duration, getBaseUris());
1490
+ segmentIndex.forEachTopLevelReference((ref) => {
1491
+ ref.mimeType = context.representation.mimeType;
1492
+ ref.codecs = context.representation.codecs;
1493
+ });
1494
+ return Promise.resolve(segmentIndex);
1490
1495
  },
1491
1496
  };
1492
1497
  }
@@ -1585,7 +1590,7 @@ shaka.dash.DashParser = class {
1585
1590
  },
1586
1591
  segmentIndex: null,
1587
1592
  mimeType: context.representation.mimeType,
1588
- codecs: context.representation.codecs,
1593
+ codecs,
1589
1594
  frameRate: context.representation.frameRate,
1590
1595
  pixelAspectRatio: context.representation.pixelAspectRatio,
1591
1596
  bandwidth: context.bandwidth,
@@ -1615,6 +1620,8 @@ shaka.dash.DashParser = class {
1615
1620
  accessibilityPurpose,
1616
1621
  external: false,
1617
1622
  fastSwitching: false,
1623
+ fullMimeTypes: new Set([shaka.util.MimeUtils.getFullType(
1624
+ context.representation.mimeType, context.representation.codecs)]),
1618
1625
  };
1619
1626
  }
1620
1627
 
@@ -62,7 +62,7 @@ shaka.dash.SegmentBase = class {
62
62
 
63
63
  const getUris = () => resolvedUris;
64
64
  const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
65
- return new shaka.media.InitSegmentReference(
65
+ const ref = new shaka.media.InitSegmentReference(
66
66
  getUris,
67
67
  startByte,
68
68
  endByte,
@@ -70,6 +70,9 @@ shaka.dash.SegmentBase = class {
70
70
  /* timescale= */ null,
71
71
  /* segmentData= */ null,
72
72
  aes128Key);
73
+ ref.codecs = context.representation.codecs;
74
+ ref.mimeType = context.representation.mimeType;
75
+ return ref;
73
76
  }
74
77
 
75
78
  /**
@@ -184,6 +187,10 @@ shaka.dash.SegmentBase = class {
184
187
  indexData, initData, uris, initSegmentReference, timestampOffset,
185
188
  appendWindowStart, appendWindowEnd);
186
189
  }
190
+ for (const ref of references) {
191
+ ref.codecs = context.representation.codecs;
192
+ ref.mimeType = context.representation.mimeType;
193
+ }
187
194
 
188
195
  presentationTimeline.notifySegments(references);
189
196
 
@@ -60,7 +60,8 @@ shaka.dash.SegmentList = class {
60
60
  const references = SegmentList.createSegmentReferences_(
61
61
  context.periodInfo.start, context.periodInfo.duration,
62
62
  info.startNumber, context.representation.getBaseUris, info,
63
- initSegmentReference, aes128Key);
63
+ initSegmentReference, aes128Key, context.representation.mimeType,
64
+ context.representation.codecs);
64
65
 
65
66
  const isNew = !segmentIndex;
66
67
  if (segmentIndex) {
@@ -199,12 +200,14 @@ shaka.dash.SegmentList = class {
199
200
  * @param {shaka.dash.SegmentList.SegmentListInfo} info
200
201
  * @param {shaka.media.InitSegmentReference} initSegmentReference
201
202
  * @param {shaka.extern.aes128Key|undefined} aes128Key
203
+ * @param {string} mimeType
204
+ * @param {string} codecs
202
205
  * @return {!Array.<!shaka.media.SegmentReference>}
203
206
  * @private
204
207
  */
205
208
  static createSegmentReferences_(
206
209
  periodStart, periodDuration, startNumber, getBaseUris, info,
207
- initSegmentReference, aes128Key) {
210
+ initSegmentReference, aes128Key, mimeType, codecs) {
208
211
  const ManifestParserUtils = shaka.util.ManifestParserUtils;
209
212
 
210
213
  let max = info.mediaSegments.length;
@@ -251,22 +254,25 @@ shaka.dash.SegmentList = class {
251
254
  }
252
255
  return uris;
253
256
  };
254
- references.push(
255
- new shaka.media.SegmentReference(
256
- periodStart + startTime,
257
- periodStart + endTime,
258
- getUris,
259
- segment.start,
260
- segment.end,
261
- initSegmentReference,
262
- timestampOffset,
263
- appendWindowStart, appendWindowEnd,
264
- /* partialReferences= */ [],
265
- /* tilesLayout= */ '',
266
- /* tileDuration= */ null,
267
- /* syncTime= */ null,
268
- shaka.media.SegmentReference.Status.AVAILABLE,
269
- aes128Key));
257
+
258
+ const ref = new shaka.media.SegmentReference(
259
+ periodStart + startTime,
260
+ periodStart + endTime,
261
+ getUris,
262
+ segment.start,
263
+ segment.end,
264
+ initSegmentReference,
265
+ timestampOffset,
266
+ appendWindowStart, appendWindowEnd,
267
+ /* partialReferences= */ [],
268
+ /* tilesLayout= */ '',
269
+ /* tileDuration= */ null,
270
+ /* syncTime= */ null,
271
+ shaka.media.SegmentReference.Status.AVAILABLE,
272
+ aes128Key);
273
+ ref.codecs = codecs;
274
+ ref.mimeType = mimeType;
275
+ references.push(ref);
270
276
  prevEndTime = endTime;
271
277
  }
272
278
 
@@ -213,6 +213,8 @@ shaka.dash.SegmentTemplate = class {
213
213
  timeline: segmentInfo.timeline,
214
214
  mediaTemplate: media,
215
215
  indexTemplate: index,
216
+ mimeType: context.representation.mimeType,
217
+ codecs: context.representation.codecs,
216
218
  };
217
219
  }
218
220
 
@@ -463,6 +465,8 @@ shaka.dash.SegmentTemplate = class {
463
465
  /* syncTime= */ null,
464
466
  shaka.media.SegmentReference.Status.AVAILABLE,
465
467
  aes128Key);
468
+ ref.codecs = context.representation.codecs;
469
+ ref.mimeType = context.representation.mimeType;
466
470
  // This is necessary information for thumbnail streams:
467
471
  ref.trueEndTime = trueSegmentEnd;
468
472
  return ref;
@@ -552,7 +556,7 @@ shaka.dash.SegmentTemplate = class {
552
556
  return resolvedUris;
553
557
  };
554
558
  const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
555
- return new shaka.media.InitSegmentReference(
559
+ const ref = new shaka.media.InitSegmentReference(
556
560
  getUris,
557
561
  /* startByte= */ 0,
558
562
  /* endByte= */ null,
@@ -560,6 +564,9 @@ shaka.dash.SegmentTemplate = class {
560
564
  /* timescale= */ null,
561
565
  /* segmentData= */ null,
562
566
  aes128Key);
567
+ ref.codecs = context.representation.codecs;
568
+ ref.mimeType = context.representation.mimeType;
569
+ return ref;
563
570
  }
564
571
  };
565
572
 
@@ -835,6 +842,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
835
842
  this.periodEnd_ !== Infinity) {
836
843
  segmentEnd = this.periodEnd_;
837
844
  }
845
+ const codecs = this.templateInfo_.codecs;
846
+ const mimeType = this.templateInfo_.mimeType;
838
847
 
839
848
  const partialSegmentRefs = [];
840
849
 
@@ -877,6 +886,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
877
886
  /* syncTime= */ null,
878
887
  shaka.media.SegmentReference.Status.AVAILABLE,
879
888
  this.aes128Key_);
889
+ partial.codecs = codecs;
890
+ partial.mimeType = mimeType;
880
891
  if (this.segmentSequenceCadence_ == 0) {
881
892
  if (i > 0) {
882
893
  partial.markAsNonIndependent();
@@ -920,6 +931,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
920
931
  shaka.media.SegmentReference.Status.AVAILABLE,
921
932
  this.aes128Key_,
922
933
  /* allPartialSegments= */ range.partialSegments > 0);
934
+ ref.codecs = codecs;
935
+ ref.mimeType = mimeType;
923
936
  ref.trueEndTime = trueSegmentEnd;
924
937
  this.references[correctedPosition] = ref;
925
938
  }
@@ -955,7 +968,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
955
968
  * unscaledPresentationTimeOffset: number,
956
969
  * timeline: Array.<shaka.media.PresentationTimeline.TimeRange>,
957
970
  * mediaTemplate: ?string,
958
- * indexTemplate: ?string
971
+ * indexTemplate: ?string,
972
+ * mimeType: string,
973
+ * codecs: string
959
974
  * }}
960
975
  *
961
976
  * @description
@@ -977,5 +992,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
977
992
  * The media URI template, if given.
978
993
  * @property {?string} indexTemplate
979
994
  * The index URI template, if given.
995
+ * @property {string} mimeType
996
+ * The mimeType.
997
+ * @property {string} codecs
998
+ * The codecs.
980
999
  */
981
1000
  shaka.dash.SegmentTemplate.SegmentTemplateInfo;
@@ -1224,6 +1224,7 @@ shaka.hls.HlsParser = class {
1224
1224
  textStreamInfo.stream.mimeType =
1225
1225
  this.guessMimeTypeBeforeLoading_(type, codecs) ||
1226
1226
  this.guessMimeTypeFallback_(type);
1227
+ this.setFullTypeForStream_(textStreamInfo.stream);
1227
1228
  }
1228
1229
  }
1229
1230
  }
@@ -1233,6 +1234,15 @@ shaka.hls.HlsParser = class {
1233
1234
  return textStreams.filter((s) => s);
1234
1235
  }
1235
1236
 
1237
+ /**
1238
+ * @param {!shaka.extern.Stream} stream
1239
+ * @private
1240
+ */
1241
+ setFullTypeForStream_(stream) {
1242
+ stream.fullMimeTypes = new Set([shaka.util.MimeUtils.getFullType(
1243
+ stream.mimeType, stream.codecs)]);
1244
+ }
1245
+
1236
1246
  /**
1237
1247
  * @param {!Array.<!shaka.hls.Tag>} imageTags from the playlist.
1238
1248
  * @param {!Array.<!shaka.hls.Tag>} iFrameTags from the playlist.
@@ -2266,6 +2276,7 @@ shaka.hls.HlsParser = class {
2266
2276
  stream.mimeType = realStream.mimeType;
2267
2277
  stream.bandwidth = stream.bandwidth || realStream.bandwidth;
2268
2278
  stream.codecs = stream.codecs || realStream.codecs;
2279
+ this.setFullTypeForStream_(stream);
2269
2280
 
2270
2281
  // Since we lazy-loaded this content, the player may need to create new
2271
2282
  // sessions for the DRM info in this stream.
@@ -2280,6 +2291,7 @@ shaka.hls.HlsParser = class {
2280
2291
  // To aid manifest filtering, assume before loading that all video
2281
2292
  // renditions have the same MIME type. (And likewise for audio.)
2282
2293
  otherStreamInfo.stream.mimeType = realStream.mimeType;
2294
+ this.setFullTypeForStream_(otherStreamInfo.stream);
2283
2295
  }
2284
2296
  }
2285
2297
  }
@@ -2288,6 +2300,7 @@ shaka.hls.HlsParser = class {
2288
2300
  const firstSegment = realStream.segmentIndex.get(0);
2289
2301
  if (firstSegment && firstSegment.initSegmentReference) {
2290
2302
  stream.mimeType = 'application/mp4';
2303
+ this.setFullTypeForStream_(stream);
2291
2304
  }
2292
2305
  }
2293
2306
 
@@ -2537,6 +2550,7 @@ shaka.hls.HlsParser = class {
2537
2550
  stream.drmInfos = drmInfos;
2538
2551
  stream.keyIds = keyIds;
2539
2552
  stream.mimeType = mimeType;
2553
+ this.setFullTypeForStream_(stream);
2540
2554
 
2541
2555
  const mediaSequenceToStartTime = this.isLive_() ?
2542
2556
  this.mediaSequenceToStartTimeByType_.get(type) : new Map();
@@ -2692,7 +2706,7 @@ shaka.hls.HlsParser = class {
2692
2706
  roles.push(shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE);
2693
2707
  }
2694
2708
 
2695
- return {
2709
+ const stream = {
2696
2710
  id: this.globalId_++,
2697
2711
  originalId: name,
2698
2712
  groupId: null,
@@ -2730,7 +2744,10 @@ shaka.hls.HlsParser = class {
2730
2744
  accessibilityPurpose: accessibilityPurpose,
2731
2745
  external: false,
2732
2746
  fastSwitching: false,
2747
+ fullMimeTypes: new Set(),
2733
2748
  };
2749
+ this.setFullTypeForStream_(stream);
2750
+ return stream;
2734
2751
  }
2735
2752
 
2736
2753
  /**
@@ -31,6 +31,7 @@ goog.require('shaka.util.Mp4BoxParsers');
31
31
  goog.require('shaka.util.Mp4Parser');
32
32
  goog.require('shaka.util.Platform');
33
33
  goog.require('shaka.util.PublicPromise');
34
+ goog.require('shaka.util.StreamUtils');
34
35
  goog.require('shaka.util.TsParser');
35
36
  goog.require('shaka.lcevc.Dec');
36
37
 
@@ -237,18 +238,61 @@ shaka.media.MediaSourceEngine = class {
237
238
  * Checks if a certain type is supported.
238
239
  *
239
240
  * @param {shaka.extern.Stream} stream
240
- * @return {boolean}
241
+ * @param {shaka.util.ManifestParserUtils.ContentType} contentType
242
+ * @return {!Promise.<boolean>}
241
243
  */
242
- static isStreamSupported(stream) {
244
+ static async isStreamSupported(stream, contentType) {
245
+ if (stream.createSegmentIndex) {
246
+ await stream.createSegmentIndex();
247
+ }
248
+ if (!stream.segmentIndex) {
249
+ return false;
250
+ }
251
+ if (stream.segmentIndex.isEmpty()) {
252
+ return true;
253
+ }
243
254
  const MimeUtils = shaka.util.MimeUtils;
244
- const fullMimeType = MimeUtils.getFullType(stream.mimeType, stream.codecs);
245
- const extendedMimeType = MimeUtils.getExtendedType(stream);
246
- const fullMimeTypeWithAllCodecs = MimeUtils.getFullTypeWithAllCodecs(
247
- stream.mimeType, stream.codecs);
248
255
  const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
249
- return shaka.text.TextEngine.isTypeSupported(fullMimeType) ||
250
- shaka.media.Capabilities.isTypeSupported(extendedMimeType) ||
251
- TransmuxerEngine.isSupported(fullMimeTypeWithAllCodecs, stream.type);
256
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
257
+ const StreamUtils = shaka.util.StreamUtils;
258
+ const seenCombos = new Set();
259
+ // Check each combination of mimeType and codecs within the segment index.
260
+ // Unfortunately we cannot use fullMimeTypes, as we ALSO need to check the
261
+ // getFullTypeWithAllCodecs (for the sake of the transmuxer) and we have no
262
+ // way of going from a full mimeType to a full mimeType with all codecs.
263
+ // As this function is only called in debug mode, a little inefficiency is
264
+ // acceptable.
265
+ for (const ref of stream.segmentIndex) {
266
+ const mimeType = ref.mimeType || stream.mimeType || '';
267
+ let codecs = ref.codecs || stream.codecs || '';
268
+ // Don't check the same combination of mimetype + codecs twice.
269
+ const combo = mimeType + ':' + codecs;
270
+ if (seenCombos.has(combo)) {
271
+ continue;
272
+ }
273
+ seenCombos.add(combo);
274
+ if (contentType == ContentType.TEXT) {
275
+ const fullMimeType = MimeUtils.getFullType(mimeType, codecs);
276
+ if (!shaka.text.TextEngine.isTypeSupported(fullMimeType)) {
277
+ return false;
278
+ }
279
+ } else {
280
+ if (contentType == ContentType.VIDEO) {
281
+ codecs = StreamUtils.getCorrectVideoCodecs(codecs);
282
+ } else if (contentType == ContentType.AUDIO) {
283
+ codecs = StreamUtils.getCorrectAudioCodecs(codecs);
284
+ }
285
+ const extendedMimeType = MimeUtils.getExtendedType(
286
+ stream, mimeType, codecs);
287
+ const fullMimeType = MimeUtils.getFullTypeWithAllCodecs(
288
+ mimeType, codecs);
289
+ if (!shaka.media.Capabilities.isTypeSupported(extendedMimeType) &&
290
+ !TransmuxerEngine.isSupported(fullMimeType, stream.type)) {
291
+ return false;
292
+ }
293
+ }
294
+ }
295
+ return true;
252
296
  }
253
297
 
254
298
  /**
@@ -451,7 +495,8 @@ shaka.media.MediaSourceEngine = class {
451
495
 
452
496
  for (const contentType of streamsByType.keys()) {
453
497
  const stream = streamsByType.get(contentType);
454
- this.initSourceBuffer_(contentType, stream, stream.codecs);
498
+ // eslint-disable-next-line no-await-in-loop
499
+ await this.initSourceBuffer_(contentType, stream, stream.codecs);
455
500
  if (this.needSplitMuxedContent_) {
456
501
  this.queues_[ContentType.AUDIO] = [];
457
502
  this.queues_[ContentType.VIDEO] = [];
@@ -467,13 +512,15 @@ shaka.media.MediaSourceEngine = class {
467
512
  * @param {shaka.util.ManifestParserUtils.ContentType} contentType
468
513
  * @param {shaka.extern.Stream} stream
469
514
  * @param {string} codecs
515
+ * @return {!Promise}
470
516
  * @private
471
517
  */
472
- initSourceBuffer_(contentType, stream, codecs) {
518
+ async initSourceBuffer_(contentType, stream, codecs) {
473
519
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
474
520
 
475
521
  goog.asserts.assert(
476
- shaka.media.MediaSourceEngine.isStreamSupported(stream),
522
+ await shaka.media.MediaSourceEngine.isStreamSupported(
523
+ stream, contentType),
477
524
  'Type negotiation should happen before MediaSourceEngine.init!');
478
525
 
479
526
  let mimeType = shaka.util.MimeUtils.getFullType(
@@ -490,7 +537,6 @@ shaka.media.MediaSourceEngine = class {
490
537
  const mimeTypeWithAllCodecs =
491
538
  shaka.util.MimeUtils.getFullTypeWithAllCodecs(
492
539
  stream.mimeType, codecs);
493
- const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
494
540
  if (needTransmux) {
495
541
  const audioCodec = shaka.util.ManifestParserUtils.guessCodecsSafe(
496
542
  ContentType.AUDIO, (codecs || '').split(','));
@@ -498,12 +544,12 @@ shaka.media.MediaSourceEngine = class {
498
544
  ContentType.VIDEO, (codecs || '').split(','));
499
545
  if (audioCodec && videoCodec) {
500
546
  this.needSplitMuxedContent_ = true;
501
- this.initSourceBuffer_(ContentType.AUDIO, stream, audioCodec);
502
- this.initSourceBuffer_(ContentType.VIDEO, stream, videoCodec);
547
+ await this.initSourceBuffer_(ContentType.AUDIO, stream, audioCodec);
548
+ await this.initSourceBuffer_(ContentType.VIDEO, stream, videoCodec);
503
549
  return;
504
550
  }
505
- const transmuxerPlugin =
506
- TransmuxerEngine.findTransmuxer(mimeTypeWithAllCodecs);
551
+ const transmuxerPlugin = shaka.transmuxer.TransmuxerEngine
552
+ .findTransmuxer(mimeTypeWithAllCodecs);
507
553
  if (transmuxerPlugin) {
508
554
  const transmuxer = transmuxerPlugin();
509
555
  this.transmuxers_[contentType] = transmuxer;
@@ -1802,7 +1848,8 @@ shaka.media.MediaSourceEngine = class {
1802
1848
 
1803
1849
  for (const contentType of streamsByType.keys()) {
1804
1850
  const stream = streamsByType.get(contentType);
1805
- this.initSourceBuffer_(contentType, stream, stream.codecs);
1851
+ // eslint-disable-next-line no-await-in-loop
1852
+ await this.initSourceBuffer_(contentType, stream, stream.codecs);
1806
1853
  if (this.needSplitMuxedContent_) {
1807
1854
  this.queues_[ContentType.AUDIO] = [];
1808
1855
  this.queues_[ContentType.VIDEO] = [];
@@ -1935,10 +1982,12 @@ shaka.media.MediaSourceEngine = class {
1935
1982
  *
1936
1983
  * @param {shaka.util.ManifestParserUtils.ContentType} contentType
1937
1984
  * @param {shaka.extern.Stream} stream
1985
+ * @param {string} refMimeType
1986
+ * @param {string} refCodecs
1938
1987
  * @return {boolean}
1939
1988
  * @private
1940
1989
  */
1941
- isCodecSwitchNecessary_(contentType, stream) {
1990
+ isCodecSwitchNecessary_(contentType, stream, refMimeType, refCodecs) {
1942
1991
  if (contentType == shaka.util.ManifestParserUtils.ContentType.TEXT) {
1943
1992
  return false;
1944
1993
  }
@@ -1948,8 +1997,7 @@ shaka.media.MediaSourceEngine = class {
1948
1997
  const currentBasicType = MimeUtils.getBasicType(
1949
1998
  this.sourceBufferTypes_[contentType]);
1950
1999
 
1951
- let newMimeType = shaka.util.MimeUtils.getFullType(
1952
- stream.mimeType, stream.codecs);
2000
+ let newMimeType = shaka.util.MimeUtils.getFullType(refMimeType, refCodecs);
1953
2001
  let needTransmux = this.config_.forceTransmux;
1954
2002
  if (!shaka.media.Capabilities.isTypeSupported(newMimeType) ||
1955
2003
  (!this.sequenceMode_ &&
@@ -1958,7 +2006,7 @@ shaka.media.MediaSourceEngine = class {
1958
2006
  }
1959
2007
  const newMimeTypeWithAllCodecs =
1960
2008
  shaka.util.MimeUtils.getFullTypeWithAllCodecs(
1961
- stream.mimeType, stream.codecs);
2009
+ refMimeType, refCodecs);
1962
2010
  const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
1963
2011
  if (needTransmux) {
1964
2012
  const transmuxerPlugin =
@@ -1984,10 +2032,12 @@ shaka.media.MediaSourceEngine = class {
1984
2032
  *
1985
2033
  * @param {shaka.util.ManifestParserUtils.ContentType} contentType
1986
2034
  * @param {shaka.extern.Stream} stream
2035
+ * @param {string} mimeType
2036
+ * @param {string} codecs
1987
2037
  * @return {boolean}
1988
2038
  */
1989
- isResetMediaSourceNecessary(contentType, stream) {
1990
- if (!this.isCodecSwitchNecessary_(contentType, stream)) {
2039
+ isResetMediaSourceNecessary(contentType, stream, mimeType, codecs) {
2040
+ if (!this.isCodecSwitchNecessary_(contentType, stream, mimeType, codecs)) {
1991
2041
  return false;
1992
2042
  }
1993
2043
 
@@ -382,10 +382,10 @@ shaka.media.MediaSourcePlayhead = class {
382
382
  seekStart = seekEnd - this.minSeekRange_;
383
383
  }
384
384
 
385
- if (currentTime < seekStart) {
386
- // The seek range has moved past the playhead. Move ahead to catch up.
385
+ if (currentTime < seekStart || currentTime > seekEnd) {
386
+ // playhead is outside of the seekrange. Move playhead to catch up.
387
387
  const targetTime = this.reposition_(currentTime);
388
- shaka.log.info('Jumping forward ' + (targetTime - currentTime) +
388
+ shaka.log.info('Jumping by ' + (targetTime - currentTime) +
389
389
  ' seconds to catch up with the seek range.');
390
390
  this.mediaElement_.currentTime = targetTime;
391
391
  }
@@ -363,26 +363,27 @@ shaka.media.SegmentIndex = class {
363
363
 
364
364
  // Adjust the last SegmentReference.
365
365
  const lastReference = this.references[this.references.length - 1];
366
- this.references[this.references.length - 1] =
367
- new shaka.media.SegmentReference(
368
- lastReference.startTime,
369
- /* endTime= */ windowEnd,
370
- lastReference.getUrisInner,
371
- lastReference.startByte,
372
- lastReference.endByte,
373
- lastReference.initSegmentReference,
374
- lastReference.timestampOffset,
375
- lastReference.appendWindowStart,
376
- lastReference.appendWindowEnd,
377
- lastReference.partialReferences,
378
- lastReference.tilesLayout,
379
- lastReference.tileDuration,
380
- lastReference.syncTime,
381
- lastReference.status,
382
- lastReference.aes128Key,
383
- );
384
- this.references[this.references.length - 1].discontinuitySequence =
385
- lastReference.discontinuitySequence;
366
+ const newReference = new shaka.media.SegmentReference(
367
+ lastReference.startTime,
368
+ /* endTime= */ windowEnd,
369
+ lastReference.getUrisInner,
370
+ lastReference.startByte,
371
+ lastReference.endByte,
372
+ lastReference.initSegmentReference,
373
+ lastReference.timestampOffset,
374
+ lastReference.appendWindowStart,
375
+ lastReference.appendWindowEnd,
376
+ lastReference.partialReferences,
377
+ lastReference.tilesLayout,
378
+ lastReference.tileDuration,
379
+ lastReference.syncTime,
380
+ lastReference.status,
381
+ lastReference.aes128Key,
382
+ );
383
+ newReference.mimeType = lastReference.mimeType;
384
+ newReference.codecs = lastReference.codecs;
385
+ newReference.discontinuitySequence = lastReference.discontinuitySequence;
386
+ this.references[this.references.length - 1] = newReference;
386
387
  }
387
388
 
388
389
 
@@ -881,7 +881,6 @@ shaka.media.StreamingEngine = class {
881
881
  // The playhead might be seeking on startup, if a start time is set, so
882
882
  // start "seeked" as true.
883
883
  seeked: true,
884
- needsResync: false,
885
884
  recovering: false,
886
885
  hasError: false,
887
886
  operation: null,
@@ -1248,11 +1247,6 @@ shaka.media.StreamingEngine = class {
1248
1247
  shaka.log.v1(
1249
1248
  logPrefix, 'looking up segment from new stream endTime:', time);
1250
1249
 
1251
- // Using a new iterator means we need to resync the stream in sequence
1252
- // mode. The buffered range might not align perfectly with the last
1253
- // segment end time, so we may end up repeating a segment. Resyncing
1254
- // makes this safe to do.
1255
- mediaState.needsResync = true;
1256
1250
  mediaState.segmentIterator =
1257
1251
  mediaState.stream.segmentIndex.getIteratorForTime(time);
1258
1252
  const ref = mediaState.segmentIterator &&
@@ -1730,7 +1724,7 @@ shaka.media.StreamingEngine = class {
1730
1724
  const isResetMediaSourceNecessary =
1731
1725
  mediaState.lastCodecs && mediaState.lastMimeType &&
1732
1726
  this.playerInterface_.mediaSourceEngine.isResetMediaSourceNecessary(
1733
- mediaState.type, mediaState.stream);
1727
+ mediaState.type, mediaState.stream, mimeType, codecs);
1734
1728
  if (isResetMediaSourceNecessary) {
1735
1729
  let otherState = null;
1736
1730
  if (mediaState.type === ContentType.VIDEO) {
@@ -1879,9 +1873,7 @@ shaka.media.StreamingEngine = class {
1879
1873
  // Across discontinuity bounds, we should resync timestamps for
1880
1874
  // sequence mode playbacks. The next segment appended should
1881
1875
  // land at its theoretical timestamp from the segment index.
1882
- if (reference.discontinuitySequence != lastDiscontinuitySequence ||
1883
- mediaState.needsResync) {
1884
- mediaState.needsResync = false;
1876
+ if (reference.discontinuitySequence != lastDiscontinuitySequence) {
1885
1877
  operations.push(this.playerInterface_.mediaSourceEngine.resync(
1886
1878
  mediaState.type, reference.startTime));
1887
1879
  }
@@ -2591,7 +2583,6 @@ shaka.media.StreamingEngine.PlayerInterface;
2591
2583
  * clearBufferSafeMargin: number,
2592
2584
  * clearingBuffer: boolean,
2593
2585
  * seeked: boolean,
2594
- * needsResync: boolean,
2595
2586
  * adaptation: boolean,
2596
2587
  * recovering: boolean,
2597
2588
  * hasError: boolean,
@@ -2646,9 +2637,6 @@ shaka.media.StreamingEngine.PlayerInterface;
2646
2637
  * True indicates that the presentation just seeked.
2647
2638
  * @property {boolean} adaptation
2648
2639
  * True indicates that the presentation just automatically switched variants.
2649
- * @property {boolean} needsResync
2650
- * True indicates that the stream needs to be resynced in sequence mode,
2651
- * regardless of discontinuity sequence.
2652
2640
  * @property {boolean} recovering
2653
2641
  * True indicates that the last segment was not appended because it could not
2654
2642
  * fit in the buffer.