shaka-player 4.4.0 → 4.4.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 (46) hide show
  1. package/.github/workflows/release-please.yaml +21 -13
  2. package/.github/workflows/report-incremental-coverage.yaml +2 -2
  3. package/.github/workflows/shaka-bot-commands/command-help.sh +27 -0
  4. package/.github/workflows/shaka-bot-commands/command-test.sh +56 -0
  5. package/.github/workflows/shaka-bot-commands/lib.sh +83 -0
  6. package/.github/workflows/shaka-bot-commands/main.sh +51 -0
  7. package/.github/workflows/talk-to-shaka-bot.yaml +29 -0
  8. package/.github/workflows/update-issues.yaml +2 -1
  9. package/.github/workflows/validate-pr-title.yaml +3 -11
  10. package/CHANGELOG.md +13 -0
  11. package/dist/deps.js +1 -1
  12. package/dist/locales.js +32 -32
  13. package/dist/shaka-player.compiled.d.ts +297 -297
  14. package/dist/shaka-player.compiled.debug.d.ts +297 -297
  15. package/dist/shaka-player.compiled.debug.externs.js +1 -1
  16. package/dist/shaka-player.compiled.debug.js +221 -222
  17. package/dist/shaka-player.compiled.debug.map +3 -3
  18. package/dist/shaka-player.compiled.externs.js +1 -1
  19. package/dist/shaka-player.compiled.js +947 -946
  20. package/dist/shaka-player.compiled.map +3 -3
  21. package/dist/shaka-player.ui.d.ts +341 -341
  22. package/dist/shaka-player.ui.debug.d.ts +341 -341
  23. package/dist/shaka-player.ui.debug.externs.js +1 -1
  24. package/dist/shaka-player.ui.debug.js +282 -283
  25. package/dist/shaka-player.ui.debug.map +3 -3
  26. package/dist/shaka-player.ui.externs.js +1 -1
  27. package/dist/shaka-player.ui.js +566 -564
  28. package/dist/shaka-player.ui.map +3 -3
  29. package/externs/shaka/namespace.js +2 -2
  30. package/externs/shaka/transmuxer.js +2 -1
  31. package/lib/hls/hls_parser.js +1 -0
  32. package/lib/media/media_source_engine.js +22 -2
  33. package/lib/mss/mss_parser.js +1 -0
  34. package/lib/player.js +1 -1
  35. package/lib/text/simple_text_displayer.js +0 -1
  36. package/lib/transmuxer/aac_transmuxer.js +1 -1
  37. package/lib/transmuxer/ac3_transmuxer.js +1 -0
  38. package/lib/transmuxer/ec3_transmuxer.js +1 -0
  39. package/lib/transmuxer/mp3_transmuxer.js +1 -0
  40. package/lib/transmuxer/ts_transmuxer.js +54 -71
  41. package/lib/util/mp4_generator.js +27 -20
  42. package/lib/util/ts_parser.js +73 -110
  43. package/package.json +1 -1
  44. package/test/hls/hls_parser_unit.js +12 -13
  45. package/test/media/media_source_engine_integration.js +2 -2
  46. package/test/mss/mss_player_integration.js +1 -1
@@ -6,8 +6,8 @@
6
6
 
7
7
  /**
8
8
  * @externs
9
- * @suppress {duplicate} To prevent compiler errors with the namespace
10
- * being declared both here and by goog.provide in the library.
9
+ * @suppress {constantProperty, duplicate} To prevent compiler errors with the
10
+ * namespace being declared both here and by goog.provide in the library.
11
11
  */
12
12
 
13
13
  /** @namespace */
@@ -46,9 +46,10 @@ shaka.extern.Transmuxer = class {
46
46
  * @param {?shaka.media.SegmentReference} reference The segment reference, or
47
47
  * null for init segments
48
48
  * @param {number} duration
49
+ * @param {string} contentType
49
50
  * @return {!Promise.<!Uint8Array>}
50
51
  */
51
- transmux(data, stream, reference, duration) {}
52
+ transmux(data, stream, reference, duration, contentType) {}
52
53
  };
53
54
 
54
55
 
@@ -1466,6 +1466,7 @@ shaka.hls.HlsParser = class {
1466
1466
  // and no video codec, so it should be audio.
1467
1467
  type = ContentType.AUDIO;
1468
1468
  shaka.log.debug('Guessing audio-only.');
1469
+ ignoreStream = res.audio.length > 0;
1469
1470
  } else if (!streamInfos.length && audioCodecs && videoCodecs) {
1470
1471
  // There are both audio and video codecs, so assume multiplexed content.
1471
1472
  // Note that the default used when CODECS is missing assumes multiple
@@ -821,7 +821,7 @@ shaka.media.MediaSourceEngine = class {
821
821
 
822
822
  if (this.transmuxers_[contentType]) {
823
823
  data = await this.transmuxers_[contentType].transmux(
824
- data, stream, reference, this.mediaSource_.duration);
824
+ data, stream, reference, this.mediaSource_.duration, contentType);
825
825
  }
826
826
 
827
827
  data = this.workAroundBrokenPlatforms_(
@@ -1562,16 +1562,34 @@ shaka.media.MediaSourceEngine = class {
1562
1562
  * @private
1563
1563
  */
1564
1564
  async reset_(streamsByType) {
1565
+ const Functional = shaka.util.Functional;
1565
1566
  this.reloadingMediaSource_ = true;
1566
1567
  const currentTime = this.video_.currentTime;
1567
1568
  try {
1568
1569
  this.eventManager_.removeAll();
1569
- this.sourceBuffers_ = {};
1570
1570
 
1571
1571
  const cleanup = [];
1572
1572
  for (const contentType in this.transmuxers_) {
1573
1573
  cleanup.push(this.transmuxers_[contentType].destroy());
1574
1574
  }
1575
+ for (const contentType in this.queues_) {
1576
+ // Make a local copy of the queue and the first item.
1577
+ const q = this.queues_[contentType];
1578
+ const inProgress = q[0];
1579
+
1580
+ // Drop everything else out of the original queue.
1581
+ this.queues_[contentType] = q.slice(0, 1);
1582
+
1583
+ // We will wait for this item to complete/fail.
1584
+ if (inProgress) {
1585
+ cleanup.push(inProgress.p.catch(Functional.noop));
1586
+ }
1587
+
1588
+ // The rest will be rejected silently if possible.
1589
+ for (const item of q.slice(1)) {
1590
+ item.p.reject(shaka.util.Destroyer.destroyedError());
1591
+ }
1592
+ }
1575
1593
  for (const contentType in this.sourceBuffers_) {
1576
1594
  const sourceBuffer = this.sourceBuffers_[contentType];
1577
1595
  try {
@@ -1580,6 +1598,8 @@ shaka.media.MediaSourceEngine = class {
1580
1598
  }
1581
1599
  await Promise.all(cleanup);
1582
1600
  this.transmuxers_ = {};
1601
+ this.queues_ = {};
1602
+ this.sourceBuffers_ = {};
1583
1603
 
1584
1604
  const previousDuration = this.mediaSource_.duration;
1585
1605
  this.mediaSourceOpen_ = new shaka.util.PublicPromise();
@@ -635,6 +635,7 @@ shaka.mss.MssParser = class {
635
635
  const streamInfo = {
636
636
  id: stream.id,
637
637
  type: stream.type,
638
+ codecs: stream.codecs,
638
639
  encrypted: stream.encrypted,
639
640
  timescale: stream.mssPrivateData.timescale,
640
641
  duration: stream.mssPrivateData.duration,
package/lib/player.js CHANGED
@@ -7224,7 +7224,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
7224
7224
  * @define {string} A version number taken from git at compile time.
7225
7225
  * @export
7226
7226
  */
7227
- shaka.Player.version = 'v4.4.0-uncompiled';
7227
+ shaka.Player.version = 'v4.4.1-uncompiled';
7228
7228
 
7229
7229
  // Initialize the deprecation system using the version string we just set
7230
7230
  // on the player.
@@ -51,7 +51,6 @@ shaka.text.SimpleTextDisplayer = class {
51
51
  // kinds which can be displayed in the app's UI.
52
52
  this.textTrack_ = video.addTextTrack(
53
53
  'subtitles', shaka.Player.TextTrackLabel);
54
- console.log(this.textTrack_);
55
54
  }
56
55
  this.textTrack_.mode = 'hidden';
57
56
  }
@@ -145,7 +145,6 @@ shaka.transmuxer.AacTransmuxer = class {
145
145
  }
146
146
  stream.audioSamplingRate = info.sampleRate;
147
147
  stream.channelsCount = info.channelCount;
148
- stream.codecs = info.codec;
149
148
 
150
149
  /** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
151
150
  const samples = [];
@@ -189,6 +188,7 @@ shaka.transmuxer.AacTransmuxer = class {
189
188
  const streamInfo = {
190
189
  id: stream.id,
191
190
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
191
+ codecs: info.codec,
192
192
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
193
193
  timescale: sampleRate,
194
194
  duration: duration,
@@ -177,6 +177,7 @@ shaka.transmuxer.Ac3Transmuxer = class {
177
177
  const streamInfo = {
178
178
  id: stream.id,
179
179
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
180
+ codecs: 'ac-3',
180
181
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
181
182
  timescale: sampleRate,
182
183
  duration: duration,
@@ -177,6 +177,7 @@ shaka.transmuxer.Ec3Transmuxer = class {
177
177
  const streamInfo = {
178
178
  id: stream.id,
179
179
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
180
+ codecs: 'ec-3',
180
181
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
181
182
  timescale: sampleRate,
182
183
  duration: duration,
@@ -169,6 +169,7 @@ shaka.transmuxer.Mp3Transmuxer = class {
169
169
  const streamInfo = {
170
170
  id: stream.id,
171
171
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
172
+ codecs: 'mp3',
172
173
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
173
174
  timescale: sampleRate,
174
175
  duration: duration,
@@ -159,7 +159,8 @@ shaka.transmuxer.TsTransmuxer = class {
159
159
  * @override
160
160
  * @export
161
161
  */
162
- transmux(data, stream, reference, duration) {
162
+ transmux(data, stream, reference, duration, contentType) {
163
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
163
164
  if (!this.tsParser_) {
164
165
  this.tsParser_ = new shaka.util.TsParser();
165
166
  } else {
@@ -184,42 +185,46 @@ shaka.transmuxer.TsTransmuxer = class {
184
185
  const codecs = tsParser.getCodecs();
185
186
  try {
186
187
  let streamInfo = null;
187
- switch (codecs.video) {
188
- case 'avc':
189
- streamInfo =
190
- this.getAvcStreamInfo_(tsParser, timestamp, stream, duration);
191
- break;
192
- }
193
- if (streamInfo) {
194
- streamInfos.push(streamInfo);
195
- streamInfo = null;
196
- }
197
- const isMuxed = !!(codecs.video && codecs.audio);
198
- switch (codecs.audio) {
199
- case 'aac':
200
- streamInfo =
201
- this.getAacStreamInfo_(
202
- tsParser, timestamp, stream, duration, isMuxed);
203
- break;
204
- case 'ac3':
205
- streamInfo =
206
- this.getAc3StreamInfo_(
207
- tsParser, timestamp, stream, duration, isMuxed);
208
- break;
209
- case 'ec3':
210
- streamInfo =
211
- this.getEc3StreamInfo_(
212
- tsParser, timestamp, stream, duration, isMuxed);
213
- break;
214
- case 'mp3':
215
- streamInfo =
216
- this.getMp3StreamInfo_(
217
- tsParser, timestamp, stream, duration, isMuxed);
218
- break;
188
+ if (contentType == ContentType.VIDEO) {
189
+ switch (codecs.video) {
190
+ case 'avc':
191
+ streamInfo =
192
+ this.getAvcStreamInfo_(
193
+ tsParser, timestamp, stream, duration);
194
+ break;
195
+ }
196
+ if (streamInfo) {
197
+ streamInfos.push(streamInfo);
198
+ streamInfo = null;
199
+ }
219
200
  }
220
- if (streamInfo) {
221
- streamInfos.push(streamInfo);
222
- streamInfo = null;
201
+ if (contentType == ContentType.AUDIO) {
202
+ switch (codecs.audio) {
203
+ case 'aac':
204
+ streamInfo =
205
+ this.getAacStreamInfo_(
206
+ tsParser, timestamp, stream, duration);
207
+ break;
208
+ case 'ac3':
209
+ streamInfo =
210
+ this.getAc3StreamInfo_(
211
+ tsParser, timestamp, stream, duration);
212
+ break;
213
+ case 'ec3':
214
+ streamInfo =
215
+ this.getEc3StreamInfo_(
216
+ tsParser, timestamp, stream, duration);
217
+ break;
218
+ case 'mp3':
219
+ streamInfo =
220
+ this.getMp3StreamInfo_(
221
+ tsParser, timestamp, stream, duration);
222
+ break;
223
+ }
224
+ if (streamInfo) {
225
+ streamInfos.push(streamInfo);
226
+ streamInfo = null;
227
+ }
223
228
  }
224
229
  } catch (e) {
225
230
  return Promise.reject(e);
@@ -253,11 +258,10 @@ shaka.transmuxer.TsTransmuxer = class {
253
258
  * @param {number} timestamp
254
259
  * @param {shaka.extern.Stream} stream
255
260
  * @param {number} duration
256
- * @param {boolean} isMuxed
257
261
  * @return {shaka.util.Mp4Generator.StreamInfo}
258
262
  * @private
259
263
  */
260
- getAacStreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
264
+ getAacStreamInfo_(tsParser, timestamp, stream, duration) {
261
265
  const ADTS = shaka.transmuxer.ADTS;
262
266
 
263
267
  /** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
@@ -280,7 +284,6 @@ shaka.transmuxer.TsTransmuxer = class {
280
284
  }
281
285
  stream.audioSamplingRate = info.sampleRate;
282
286
  stream.channelsCount = info.channelCount;
283
- stream.codecs = info.codec;
284
287
 
285
288
  while (offset < data.length) {
286
289
  const header = ADTS.parseHeader(data, offset);
@@ -325,13 +328,10 @@ shaka.transmuxer.TsTransmuxer = class {
325
328
  /** @type {number} */
326
329
  const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);
327
330
 
328
- let id = stream.id;
329
- if (isMuxed) {
330
- id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
331
- }
332
331
  return {
333
- id: id,
332
+ id: stream.id,
334
333
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
334
+ codecs: info.codec,
335
335
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
336
336
  timescale: sampleRate,
337
337
  duration: duration,
@@ -353,11 +353,10 @@ shaka.transmuxer.TsTransmuxer = class {
353
353
  * @param {number} timestamp
354
354
  * @param {shaka.extern.Stream} stream
355
355
  * @param {number} duration
356
- * @param {boolean} isMuxed
357
356
  * @return {shaka.util.Mp4Generator.StreamInfo}
358
357
  * @private
359
358
  */
360
- getAc3StreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
359
+ getAc3StreamInfo_(tsParser, timestamp, stream, duration) {
361
360
  const Ac3 = shaka.transmuxer.Ac3;
362
361
 
363
362
  /** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
@@ -415,13 +414,10 @@ shaka.transmuxer.TsTransmuxer = class {
415
414
  /** @type {number} */
416
415
  const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);
417
416
 
418
- let id = stream.id;
419
- if (isMuxed) {
420
- id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
421
- }
422
417
  return {
423
- id: id,
418
+ id: stream.id,
424
419
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
420
+ codecs: 'ac-3',
425
421
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
426
422
  timescale: sampleRate,
427
423
  duration: duration,
@@ -443,11 +439,10 @@ shaka.transmuxer.TsTransmuxer = class {
443
439
  * @param {number} timestamp
444
440
  * @param {shaka.extern.Stream} stream
445
441
  * @param {number} duration
446
- * @param {boolean} isMuxed
447
442
  * @return {shaka.util.Mp4Generator.StreamInfo}
448
443
  * @private
449
444
  */
450
- getEc3StreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
445
+ getEc3StreamInfo_(tsParser, timestamp, stream, duration) {
451
446
  const Ec3 = shaka.transmuxer.Ec3;
452
447
 
453
448
  /** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
@@ -505,13 +500,10 @@ shaka.transmuxer.TsTransmuxer = class {
505
500
  /** @type {number} */
506
501
  const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);
507
502
 
508
- let id = stream.id;
509
- if (isMuxed) {
510
- id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
511
- }
512
503
  return {
513
- id: id,
504
+ id: stream.id,
514
505
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
506
+ codecs: 'ec-3',
515
507
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
516
508
  timescale: sampleRate,
517
509
  duration: duration,
@@ -533,11 +525,10 @@ shaka.transmuxer.TsTransmuxer = class {
533
525
  * @param {number} timestamp
534
526
  * @param {shaka.extern.Stream} stream
535
527
  * @param {number} duration
536
- * @param {boolean} isMuxed
537
528
  * @return {shaka.util.Mp4Generator.StreamInfo}
538
529
  * @private
539
530
  */
540
- getMp3StreamInfo_(tsParser, timestamp, stream, duration, isMuxed) {
531
+ getMp3StreamInfo_(tsParser, timestamp, stream, duration) {
541
532
  const MpegAudio = shaka.transmuxer.MpegAudio;
542
533
 
543
534
  /** @type {!Array.<shaka.util.Mp4Generator.Mp4Sample>} */
@@ -590,13 +581,10 @@ shaka.transmuxer.TsTransmuxer = class {
590
581
  /** @type {number} */
591
582
  const baseMediaDecodeTime = Math.floor(timestamp * sampleRate / 1000);
592
583
 
593
- let id = stream.id;
594
- if (isMuxed) {
595
- id += shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_;
596
- }
597
584
  return {
598
- id: id,
585
+ id: stream.id,
599
586
  type: shaka.util.ManifestParserUtils.ContentType.AUDIO,
587
+ codecs: 'mp3',
600
588
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
601
589
  timescale: sampleRate,
602
590
  duration: duration,
@@ -686,6 +674,7 @@ shaka.transmuxer.TsTransmuxer = class {
686
674
  return {
687
675
  id: stream.id,
688
676
  type: shaka.util.ManifestParserUtils.ContentType.VIDEO,
677
+ codecs: 'avc1',
689
678
  encrypted: stream.encrypted && stream.drmInfos.length > 0,
690
679
  timescale: timescale,
691
680
  duration: duration,
@@ -725,12 +714,6 @@ shaka.transmuxer.TsTransmuxer.SUPPORTED_VIDEO_CODECS_ = [
725
714
  'avc',
726
715
  ];
727
716
 
728
- /**
729
- * @private
730
- * @const {number}
731
- */
732
- shaka.transmuxer.TsTransmuxer.START_ID_FOR_MUXED_CONTENT_ = 128;
733
-
734
717
 
735
718
  shaka.transmuxer.TransmuxerEngine.registerTransmuxer(
736
719
  'video/mp2t',
@@ -55,7 +55,7 @@ shaka.util.Mp4Generator = class {
55
55
  return Mp4Generator.box('moov',
56
56
  this.mvhd_(firstStreamInfo),
57
57
  traks,
58
- this.mvex_(firstStreamInfo),
58
+ this.mvex_(),
59
59
  this.pssh_(firstStreamInfo));
60
60
  }
61
61
 
@@ -130,9 +130,14 @@ shaka.util.Mp4Generator = class {
130
130
  */
131
131
  tkhd_(streamInfo) {
132
132
  const Mp4Generator = shaka.util.Mp4Generator;
133
+ const ContentType = shaka.util.ManifestParserUtils.ContentType;
133
134
  const id = streamInfo.id + 1;
134
- const width = streamInfo.stream.width || 0;
135
- const height = streamInfo.stream.height || 0;
135
+ let width = streamInfo.stream.width || 0;
136
+ let height = streamInfo.stream.height || 0;
137
+ if (streamInfo.type == ContentType.AUDIO) {
138
+ width = 0;
139
+ height = 0;
140
+ }
136
141
  const duration = streamInfo.duration * streamInfo.timescale;
137
142
  const upperWordDuration =
138
143
  Math.floor(duration / (Mp4Generator.UINT32_MAX_ + 1));
@@ -295,24 +300,18 @@ shaka.util.Mp4Generator = class {
295
300
  let bytes = new Uint8Array([]);
296
301
  switch (streamInfo.type) {
297
302
  case ContentType.VIDEO:
298
- if (streamInfo.stream.codecs.includes('avc1.') ||
299
- streamInfo.stream.codecs.includes('avc3.')) {
303
+ if (streamInfo.codecs.includes('avc1')) {
300
304
  bytes = this.avc1_(streamInfo);
301
- } else if (streamInfo.stream.codecs.includes('hev1.') ||
302
- streamInfo.stream.codecs.includes('hvc1.')) {
305
+ } else if (streamInfo.codecs.includes('hvc1')) {
303
306
  bytes = this.hvc1_(streamInfo);
304
307
  }
305
308
  break;
306
309
  case ContentType.AUDIO:
307
- if (streamInfo.stream.mimeType === 'audio/mpeg' ||
308
- streamInfo.stream.codecs.includes('mp3') ||
309
- streamInfo.stream.codecs.includes('mp4a.40.34')) {
310
+ if (streamInfo.codecs.includes('mp3')) {
310
311
  bytes = this.mp3_(streamInfo);
311
- } else if (streamInfo.stream.mimeType === 'audio/ac3' ||
312
- streamInfo.stream.codecs.includes('ac-3')) {
312
+ } else if (streamInfo.codecs.includes('ac-3')) {
313
313
  bytes = this.ac3_(streamInfo);
314
- } else if (streamInfo.stream.mimeType === 'audio/ec3' ||
315
- streamInfo.stream.codecs.includes('ec-3')) {
314
+ } else if (streamInfo.codecs.includes('ec-3')) {
316
315
  bytes = this.ec3_(streamInfo);
317
316
  } else {
318
317
  bytes = this.mp4a_(streamInfo);
@@ -630,7 +629,7 @@ shaka.util.Mp4Generator = class {
630
629
  const audioSamplingRate = streamInfo.stream.audioSamplingRate || 44100;
631
630
 
632
631
  const audioCodec = shaka.util.ManifestParserUtils.guessCodecs(
633
- ContentType.AUDIO, streamInfo.stream.codecs.split(','));
632
+ ContentType.AUDIO, streamInfo.codecs.split(','));
634
633
 
635
634
  const samplingFrequencyIndex = {
636
635
  96000: 0x0,
@@ -689,13 +688,16 @@ shaka.util.Mp4Generator = class {
689
688
  /**
690
689
  * Generate a MVEX box
691
690
  *
692
- * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
693
691
  * @return {!Uint8Array}
694
692
  * @private
695
693
  */
696
- mvex_(streamInfo) {
694
+ mvex_() {
697
695
  const Mp4Generator = shaka.util.Mp4Generator;
698
- return Mp4Generator.box('mvex', this.trex_(streamInfo));
696
+ let trexs = new Uint8Array([]);
697
+ for (const streamInfo of this.streamInfos_) {
698
+ trexs = shaka.util.Uint8ArrayUtils.concat(trexs, this.trex_(streamInfo));
699
+ }
700
+ return Mp4Generator.box('mvex', trexs);
699
701
  }
700
702
 
701
703
  /**
@@ -765,8 +767,8 @@ shaka.util.Mp4Generator = class {
765
767
  * @private
766
768
  */
767
769
  frma_(streamInfo) {
768
- const codec = streamInfo.stream.codecs.substring(
769
- 0, streamInfo.stream.codecs.indexOf('.'));
770
+ const codec = streamInfo.codecs.substring(
771
+ 0, streamInfo.codecs.indexOf('.'));
770
772
  const Mp4Generator = shaka.util.Mp4Generator;
771
773
  const codecNumber = this.stringToCharCode_(codec);
772
774
  const bytes = new Uint8Array([
@@ -1290,6 +1292,7 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]);
1290
1292
  * @typedef {{
1291
1293
  * id: number,
1292
1294
  * type: string,
1295
+ * codecs: string,
1293
1296
  * encrypted: boolean,
1294
1297
  * timescale: number,
1295
1298
  * duration: number,
@@ -1304,6 +1307,10 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]);
1304
1307
  * A unique ID
1305
1308
  * @property {string} type
1306
1309
  * Indicate the content type: 'video' or 'audio'.
1310
+ * @property {string} codecs
1311
+ * <i>Defaults to '' (i.e., unknown / not needed).</i> <br>
1312
+ * The Stream's codecs, e.g., 'avc1.4d4015' or 'vp9'<br>
1313
+ * See {@link https://tools.ietf.org/html/rfc6381}
1307
1314
  * @property {boolean} encrypted
1308
1315
  * Indicate if the stream is encrypted.
1309
1316
  * @property {number} timescale