shaka-player 4.4.2 → 4.4.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 (57) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/demo/common/asset.js +5 -0
  3. package/demo/common/assets.js +20 -5
  4. package/demo/common/message_ids.js +1 -1
  5. package/demo/locales/en.json +2 -1
  6. package/demo/locales/source.json +5 -1
  7. package/demo/main.js +1 -1
  8. package/demo/search.js +3 -3
  9. package/dist/demo.compiled.debug.js +72 -70
  10. package/dist/demo.compiled.debug.map +3 -3
  11. package/dist/demo.compiled.js +72 -70
  12. package/dist/demo.compiled.map +3 -3
  13. package/dist/locales.js +30 -30
  14. package/dist/receiver.compiled.debug.js +38 -36
  15. package/dist/receiver.compiled.debug.map +3 -3
  16. package/dist/receiver.compiled.js +38 -36
  17. package/dist/receiver.compiled.map +3 -3
  18. package/dist/shaka-player.compiled.d.ts +222 -1
  19. package/dist/shaka-player.compiled.debug.d.ts +222 -1
  20. package/dist/shaka-player.compiled.debug.externs.js +271 -1
  21. package/dist/shaka-player.compiled.debug.js +233 -228
  22. package/dist/shaka-player.compiled.debug.map +3 -3
  23. package/dist/shaka-player.compiled.externs.js +271 -1
  24. package/dist/shaka-player.compiled.js +1035 -1028
  25. package/dist/shaka-player.compiled.map +3 -3
  26. package/dist/shaka-player.ui.d.ts +222 -1
  27. package/dist/shaka-player.ui.debug.d.ts +222 -1
  28. package/dist/shaka-player.ui.debug.externs.js +271 -1
  29. package/dist/shaka-player.ui.debug.js +256 -251
  30. package/dist/shaka-player.ui.debug.map +3 -3
  31. package/dist/shaka-player.ui.externs.js +271 -1
  32. package/dist/shaka-player.ui.js +1162 -1155
  33. package/dist/shaka-player.ui.map +3 -3
  34. package/docs/tutorials/offline.md +1 -1
  35. package/lib/dash/dash_parser.js +4 -1
  36. package/lib/hls/hls_parser.js +60 -24
  37. package/lib/media/segment_index.js +4 -4
  38. package/lib/media/segment_reference.js +6 -1
  39. package/lib/media/streaming_engine.js +14 -24
  40. package/lib/player.js +1 -1
  41. package/lib/text/cue.js +47 -47
  42. package/lib/text/vtt_text_parser.js +2 -2
  43. package/lib/util/cmcd_manager.js +6 -1
  44. package/lib/util/manifest_parser_utils.js +10 -4
  45. package/lib/util/platform.js +14 -0
  46. package/lib/util/ts_parser.js +3 -3
  47. package/package.json +1 -1
  48. package/test/dash/dash_parser_manifest_unit.js +5 -0
  49. package/test/dash/dash_parser_segment_base_unit.js +5 -0
  50. package/test/dash/dash_parser_segment_list_unit.js +21 -17
  51. package/test/dash/dash_parser_segment_template_unit.js +47 -0
  52. package/test/hls/hls_live_unit.js +33 -0
  53. package/test/hls/hls_parser_unit.js +2 -57
  54. package/test/test/util/dash_parser_util.js +16 -7
  55. package/test/text/vtt_text_parser_unit.js +2 -17
  56. package/test/transmuxer/transmuxer_integration.js +4 -4
  57. package/test/util/ts_parser_unit.js +1 -1
package/lib/text/cue.js CHANGED
@@ -26,7 +26,7 @@ shaka.text.Cue = class {
26
26
  * The start time of the cue in seconds, relative to the start of the
27
27
  * presentation.
28
28
  * @type {number}
29
- * @exportDoc
29
+ * @export
30
30
  */
31
31
  this.startTime = startTime;
32
32
 
@@ -34,7 +34,7 @@ shaka.text.Cue = class {
34
34
  * The end time of the cue in seconds, relative to the start of the
35
35
  * presentation.
36
36
  * @type {number}
37
- * @exportDoc
37
+ * @export
38
38
  */
39
39
  this.endTime = endTime;
40
40
 
@@ -42,7 +42,7 @@ shaka.text.Cue = class {
42
42
  * The text payload of the cue. If nestedCues is non-empty, this should be
43
43
  * empty. Top-level block containers should have no payload of their own.
44
44
  * @type {string}
45
- * @exportDoc
45
+ * @export
46
46
  */
47
47
  this.payload = payload;
48
48
 
@@ -50,7 +50,7 @@ shaka.text.Cue = class {
50
50
  * The region to render the cue into. Only supported on top-level cues,
51
51
  * because nested cues are inline elements.
52
52
  * @type {shaka.text.CueRegion}
53
- * @exportDoc
53
+ * @export
54
54
  */
55
55
  this.region = new shaka.text.CueRegion();
56
56
 
@@ -58,42 +58,42 @@ shaka.text.Cue = class {
58
58
  * The indent (in percent) of the cue box in the direction defined by the
59
59
  * writing direction.
60
60
  * @type {?number}
61
- * @exportDoc
61
+ * @export
62
62
  */
63
63
  this.position = null;
64
64
 
65
65
  /**
66
66
  * Position alignment of the cue.
67
67
  * @type {shaka.text.Cue.positionAlign}
68
- * @exportDoc
68
+ * @export
69
69
  */
70
70
  this.positionAlign = Cue.positionAlign.AUTO;
71
71
 
72
72
  /**
73
73
  * Size of the cue box (in percents), where 0 means "auto".
74
74
  * @type {number}
75
- * @exportDoc
75
+ * @export
76
76
  */
77
77
  this.size = 0;
78
78
 
79
79
  /**
80
80
  * Alignment of the text inside the cue box.
81
81
  * @type {shaka.text.Cue.textAlign}
82
- * @exportDoc
82
+ * @export
83
83
  */
84
84
  this.textAlign = Cue.textAlign.CENTER;
85
85
 
86
86
  /**
87
87
  * Text direction of the cue.
88
88
  * @type {shaka.text.Cue.direction}
89
- * @exportDoc
89
+ * @export
90
90
  */
91
91
  this.direction = Cue.direction.HORIZONTAL_LEFT_TO_RIGHT;
92
92
 
93
93
  /**
94
94
  * Text writing mode of the cue.
95
95
  * @type {shaka.text.Cue.writingMode}
96
- * @exportDoc
96
+ * @export
97
97
  */
98
98
  this.writingMode = Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM;
99
99
 
@@ -101,7 +101,7 @@ shaka.text.Cue = class {
101
101
  * The way to interpret line field. (Either as an integer line number or
102
102
  * percentage from the display box).
103
103
  * @type {shaka.text.Cue.lineInterpretation}
104
- * @exportDoc
104
+ * @export
105
105
  */
106
106
  this.lineInterpretation = Cue.lineInterpretation.LINE_NUMBER;
107
107
 
@@ -109,7 +109,7 @@ shaka.text.Cue = class {
109
109
  * The offset from the display box in either number of lines or
110
110
  * percentage depending on the value of lineInterpretation.
111
111
  * @type {?number}
112
- * @exportDoc
112
+ * @export
113
113
  */
114
114
  this.line = null;
115
115
 
@@ -118,7 +118,7 @@ shaka.text.Cue = class {
118
118
  * (e.g. '100px'/'100em'). If not specified, this should be no less than
119
119
  * the largest font size applied to the text in the cue.
120
120
  * @type {string}.
121
- * @exportDoc
121
+ * @export
122
122
  */
123
123
  this.lineHeight = '';
124
124
 
@@ -132,7 +132,7 @@ shaka.text.Cue = class {
132
132
  * (for vertical growing right), or left side (for vertical growing left) is
133
133
  * aligned at the line.
134
134
  * @type {shaka.text.Cue.lineAlign}
135
- * @exportDoc
135
+ * @export
136
136
  */
137
137
  this.lineAlign = Cue.lineAlign.START;
138
138
 
@@ -141,84 +141,84 @@ shaka.text.Cue = class {
141
141
  * 'BEFORE' means displaying the captions at the top of the text display
142
142
  * container box, 'CENTER' means in the middle, 'AFTER' means at the bottom.
143
143
  * @type {shaka.text.Cue.displayAlign}
144
- * @exportDoc
144
+ * @export
145
145
  */
146
146
  this.displayAlign = Cue.displayAlign.AFTER;
147
147
 
148
148
  /**
149
149
  * Text color as a CSS color, e.g. "#FFFFFF" or "white".
150
150
  * @type {string}
151
- * @exportDoc
151
+ * @export
152
152
  */
153
153
  this.color = '';
154
154
 
155
155
  /**
156
156
  * Text background color as a CSS color, e.g. "#FFFFFF" or "white".
157
157
  * @type {string}
158
- * @exportDoc
158
+ * @export
159
159
  */
160
160
  this.backgroundColor = '';
161
161
 
162
162
  /**
163
163
  * The URL of the background image, e.g. "data:[mime type];base64,[data]".
164
164
  * @type {string}
165
- * @exportDoc
165
+ * @export
166
166
  */
167
167
  this.backgroundImage = '';
168
168
 
169
169
  /**
170
170
  * The border around this cue as a CSS border.
171
171
  * @type {string}
172
- * @exportDoc
172
+ * @export
173
173
  */
174
174
  this.border = '';
175
175
 
176
176
  /**
177
177
  * Text font size in px or em (e.g. '100px'/'100em').
178
178
  * @type {string}
179
- * @exportDoc
179
+ * @export
180
180
  */
181
181
  this.fontSize = '';
182
182
 
183
183
  /**
184
184
  * Text font weight. Either normal or bold.
185
185
  * @type {shaka.text.Cue.fontWeight}
186
- * @exportDoc
186
+ * @export
187
187
  */
188
188
  this.fontWeight = Cue.fontWeight.NORMAL;
189
189
 
190
190
  /**
191
191
  * Text font style. Normal, italic or oblique.
192
192
  * @type {shaka.text.Cue.fontStyle}
193
- * @exportDoc
193
+ * @export
194
194
  */
195
195
  this.fontStyle = Cue.fontStyle.NORMAL;
196
196
 
197
197
  /**
198
198
  * Text font family.
199
199
  * @type {string}
200
- * @exportDoc
200
+ * @export
201
201
  */
202
202
  this.fontFamily = '';
203
203
 
204
204
  /**
205
205
  * Text letter spacing as a CSS letter-spacing value.
206
206
  * @type {string}
207
- * @exportDoc
207
+ * @export
208
208
  */
209
209
  this.letterSpacing = '';
210
210
 
211
211
  /**
212
212
  * Text line padding as a CSS line-padding value.
213
213
  * @type {string}
214
- * @exportDoc
214
+ * @export
215
215
  */
216
216
  this.linePadding = '';
217
217
 
218
218
  /**
219
219
  * Opacity of the cue element, from 0-1.
220
220
  * @type {number}
221
- * @exportDoc
221
+ * @export
222
222
  */
223
223
  this.opacity = 1;
224
224
 
@@ -226,42 +226,42 @@ shaka.text.Cue = class {
226
226
  * Text decoration. A combination of underline, overline
227
227
  * and line through. Empty array means no decoration.
228
228
  * @type {!Array.<!shaka.text.Cue.textDecoration>}
229
- * @exportDoc
229
+ * @export
230
230
  */
231
231
  this.textDecoration = [];
232
232
 
233
233
  /**
234
234
  * Text shadow color as a CSS text-shadow value.
235
235
  * @type {string}
236
- * @exportDoc
236
+ * @export
237
237
  */
238
238
  this.textShadow = '';
239
239
 
240
240
  /**
241
241
  * Text stroke color as a CSS color, e.g. "#FFFFFF" or "white".
242
242
  * @type {string}
243
- * @exportDoc
243
+ * @export
244
244
  */
245
245
  this.textStrokeColor = '';
246
246
 
247
247
  /**
248
248
  * Text stroke width as a CSS stroke-width value.
249
249
  * @type {string}
250
- * @exportDoc
250
+ * @export
251
251
  */
252
252
  this.textStrokeWidth = '';
253
253
 
254
254
  /**
255
255
  * Whether or not line wrapping should be applied to the cue.
256
256
  * @type {boolean}
257
- * @exportDoc
257
+ * @export
258
258
  */
259
259
  this.wrapLine = true;
260
260
 
261
261
  /**
262
262
  * Id of the cue.
263
263
  * @type {string}
264
- * @exportDoc
264
+ * @export
265
265
  */
266
266
  this.id = '';
267
267
 
@@ -270,7 +270,7 @@ shaka.text.Cue = class {
270
270
  * Top-level cues are blocks, and nested cues are inline elements.
271
271
  * Cues can be nested arbitrarily deeply.
272
272
  * @type {!Array.<!shaka.text.Cue>}
273
- * @exportDoc
273
+ * @export
274
274
  */
275
275
  this.nestedCues = [];
276
276
 
@@ -280,7 +280,7 @@ shaka.text.Cue = class {
280
280
  * in a TTML file. This controls the flow of the final cues; any nested cues
281
281
  * within an "isContainer" cue will be laid out as separate lines.
282
282
  * @type {boolean}
283
- * @exportDoc
283
+ * @export
284
284
  */
285
285
  this.isContainer = false;
286
286
 
@@ -288,7 +288,7 @@ shaka.text.Cue = class {
288
288
  * Whether or not the cue only acts as a line break between two nested cues.
289
289
  * Should only appear in nested cues.
290
290
  * @type {boolean}
291
- * @exportDoc
291
+ * @export
292
292
  */
293
293
  this.lineBreak = false;
294
294
 
@@ -297,7 +297,7 @@ shaka.text.Cue = class {
297
297
  * Region area is divided.
298
298
  *
299
299
  * @type {{ columns: number, rows: number }}
300
- * @exportDoc
300
+ * @export
301
301
  */
302
302
  this.cellResolution = {
303
303
  columns: 32,
@@ -551,7 +551,7 @@ shaka.text.CueRegion = class {
551
551
  /**
552
552
  * Region identifier.
553
553
  * @type {string}
554
- * @exportDoc
554
+ * @export
555
555
  */
556
556
  this.id = '';
557
557
 
@@ -559,7 +559,7 @@ shaka.text.CueRegion = class {
559
559
  * The X offset to start the rendering area in viewportAnchorUnits of the
560
560
  * video width.
561
561
  * @type {number}
562
- * @exportDoc
562
+ * @export
563
563
  */
564
564
  this.viewportAnchorX = 0;
565
565
 
@@ -567,7 +567,7 @@ shaka.text.CueRegion = class {
567
567
  * The X offset to start the rendering area in viewportAnchorUnits of the
568
568
  * video height.
569
569
  * @type {number}
570
- * @exportDoc
570
+ * @export
571
571
  */
572
572
  this.viewportAnchorY = 0;
573
573
 
@@ -575,7 +575,7 @@ shaka.text.CueRegion = class {
575
575
  * The X offset to start the rendering area in percentage (0-100) of this
576
576
  * region width.
577
577
  * @type {number}
578
- * @exportDoc
578
+ * @export
579
579
  */
580
580
  this.regionAnchorX = 0;
581
581
 
@@ -583,42 +583,42 @@ shaka.text.CueRegion = class {
583
583
  * The Y offset to start the rendering area in percentage (0-100) of the
584
584
  * region height.
585
585
  * @type {number}
586
- * @exportDoc
586
+ * @export
587
587
  */
588
588
  this.regionAnchorY = 0;
589
589
 
590
590
  /**
591
591
  * The width of the rendering area in widthUnits.
592
592
  * @type {number}
593
- * @exportDoc
593
+ * @export
594
594
  */
595
595
  this.width = 100;
596
596
 
597
597
  /**
598
598
  * The width of the rendering area in heightUnits.
599
599
  * @type {number}
600
- * @exportDoc
600
+ * @export
601
601
  */
602
602
  this.height = 100;
603
603
 
604
604
  /**
605
605
  * The units (percentage, pixels or lines) the region height is in.
606
606
  * @type {shaka.text.CueRegion.units}
607
- * @exportDoc
607
+ * @export
608
608
  */
609
609
  this.heightUnits = CueRegion.units.PERCENTAGE;
610
610
 
611
611
  /**
612
612
  * The units (percentage or pixels) the region width is in.
613
613
  * @type {shaka.text.CueRegion.units}
614
- * @exportDoc
614
+ * @export
615
615
  */
616
616
  this.widthUnits = CueRegion.units.PERCENTAGE;
617
617
 
618
618
  /**
619
619
  * The units (percentage or pixels) the region viewportAnchors are in.
620
620
  * @type {shaka.text.CueRegion.units}
621
- * @exportDoc
621
+ * @export
622
622
  */
623
623
  this.viewportAnchorUnits = CueRegion.units.PERCENTAGE;
624
624
 
@@ -628,7 +628,7 @@ shaka.text.CueRegion = class {
628
628
  * region up. Otherwise (scroll=NONE) cues will stay fixed at the location
629
629
  * they were first painted in.
630
630
  * @type {shaka.text.CueRegion.scrollMode}
631
- * @exportDoc
631
+ * @export
632
632
  */
633
633
  this.scroll = CueRegion.scrollMode.NONE;
634
634
  }
@@ -417,6 +417,8 @@ shaka.text.VttTextParser = class {
417
417
  cue = new shaka.text.Cue(start, end, '');
418
418
  }
419
419
 
420
+ VttTextParser.parseCueStyles(payload, cue, styles);
421
+
420
422
  // Parse optional settings.
421
423
  parser.skipWhitespace();
422
424
  let word = parser.readWord();
@@ -430,8 +432,6 @@ shaka.text.VttTextParser = class {
430
432
  word = parser.readWord();
431
433
  }
432
434
 
433
- VttTextParser.parseCueStyles(payload, cue, styles);
434
-
435
435
  if (id != null) {
436
436
  cue.id = id;
437
437
  }
@@ -406,12 +406,17 @@ shaka.util.CmcdManager = class {
406
406
  * @private
407
407
  */
408
408
  getObjectTypeFromMimeType_(mimeType) {
409
- switch (mimeType) {
409
+ switch (mimeType.toLowerCase()) {
410
410
  case 'video/webm':
411
411
  case 'video/mp4':
412
+ case 'video/mpeg':
413
+ case 'video/mp2t':
412
414
  return shaka.util.CmcdManager.ObjectType.MUXED;
413
415
 
414
416
  case 'application/x-mpegurl':
417
+ case 'application/vnd.apple.mpegurl':
418
+ case 'application/dash+xml':
419
+ case 'video/vnd.mpeg.dash.mpd':
415
420
  return shaka.util.CmcdManager.ObjectType.MANIFEST;
416
421
 
417
422
  default:
@@ -32,13 +32,19 @@ shaka.util.ManifestParserUtils = class {
32
32
  return baseUris;
33
33
  }
34
34
 
35
+ if (baseUris.length == 1 && relativeUris.length == 1) {
36
+ const baseUri = new goog.Uri(baseUris[0]);
37
+ const relativeUri = new goog.Uri(relativeUris[0]);
38
+ return [baseUri.resolve(relativeUri).toString()];
39
+ }
40
+
35
41
  const relativeAsGoog = relativeUris.map((uri) => new goog.Uri(uri));
36
42
  // Resolve each URI relative to each base URI, creating an Array of Arrays.
37
43
  // Then flatten the Arrays into a single Array.
38
- return baseUris.map((uri) => new goog.Uri(uri))
39
- .map((base) => relativeAsGoog.map((i) => base.resolve(i)))
40
- .reduce(Functional.collapseArrays, [])
41
- .map((uri) => uri.toString());
44
+ return baseUris.map((uri) => {
45
+ const base = new goog.Uri(uri);
46
+ return relativeAsGoog.map((i) => base.resolve(i).toString());
47
+ }).reduce(Functional.collapseArrays, []);
42
48
  }
43
49
 
44
50
 
@@ -368,6 +368,20 @@ shaka.util.Platform = class {
368
368
  return navigator.platform.toLowerCase().includes('mac');
369
369
  }
370
370
 
371
+ /**
372
+ * Return true if the platform is a Windows, regardless of the browser.
373
+ *
374
+ * @return {boolean}
375
+ */
376
+ static isWindows() {
377
+ // Try the newer standard first.
378
+ if (navigator.userAgentData && navigator.userAgentData.platform) {
379
+ return navigator.userAgentData.platform.toLowerCase() == 'windows';
380
+ }
381
+ // Fall back to the old API, with less strict matching.
382
+ return navigator.platform.toLowerCase().includes('windows');
383
+ }
384
+
371
385
  /**
372
386
  * Check if the user agent contains a key. This is the best way we know of
373
387
  * right now to detect platforms. If there is a better way, please send a
@@ -129,15 +129,15 @@ shaka.util.TsParser = class {
129
129
  // for example
130
130
  // NOTE this is only the PID of the track as found in TS,
131
131
  // but we are not using this for MP4 track IDs.
132
- if (this.videoPid_ == null) {
132
+ if (parsedPIDs.video != -1) {
133
133
  this.videoPid_ = parsedPIDs.video;
134
134
  this.videoCodec_ = parsedPIDs.videoCodec;
135
135
  }
136
- if (this.audioPid_ == null) {
136
+ if (parsedPIDs.audio != -1) {
137
137
  this.audioPid_ = parsedPIDs.audio;
138
138
  this.audioCodec_ = parsedPIDs.audioCodec;
139
139
  }
140
- if (this.id3Pid_ == null) {
140
+ if (parsedPIDs.id3 != -1) {
141
141
  this.id3Pid_ = parsedPIDs.id3;
142
142
  }
143
143
 
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.4.2",
4
+ "version": "4.4.3",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -57,6 +57,11 @@ describe('DashParser Manifest', () => {
57
57
  };
58
58
  });
59
59
 
60
+ afterEach(() => {
61
+ // Dash parser stop is synchronous.
62
+ parser.stop();
63
+ });
64
+
60
65
  /**
61
66
  * Makes a series of tests for the given manifest type.
62
67
  *
@@ -43,6 +43,11 @@ describe('DashParser SegmentBase', () => {
43
43
  };
44
44
  });
45
45
 
46
+ afterEach(() => {
47
+ // Dash parser stop is synchronous.
48
+ parser.stop();
49
+ });
50
+
46
51
  it('requests init data for WebM', async () => {
47
52
  const source = [
48
53
  '<MPD mediaPresentationDuration="PT75S">',
@@ -351,24 +351,28 @@ describe('DashParser SegmentList', () => {
351
351
  updateDuration: () => {},
352
352
  newDrmInfo: (stream) => {},
353
353
  };
354
- const manifest = await dashParser.start('dummy://foo', playerInterface);
355
- const stream = manifest.variants[0].video;
356
- await stream.createSegmentIndex();
357
- goog.asserts.assert(stream.segmentIndex, 'Expected index to be created');
354
+ try {
355
+ const manifest = await dashParser.start('dummy://foo', playerInterface);
356
+ const stream = manifest.variants[0].video;
357
+ await stream.createSegmentIndex();
358
+ goog.asserts.assert(stream.segmentIndex, 'Expected index to be created');
358
359
 
359
- // Don't use Dash.testSegmentIndex since it uses SegmentIndex.find, which
360
- // doesn't reproduce this issue. We want to use Array.from which uses the
361
- // iterator.
362
- const expected = [
363
- ManifestParser.makeReference('s1.mp4', 0, 10, baseUri),
364
- ManifestParser.makeReference('s2.mp4', 10, 20, baseUri),
365
- ManifestParser.makeReference('s3.mp4', 20, 30, baseUri),
360
+ // Don't use Dash.testSegmentIndex since it uses SegmentIndex.find, which
361
+ // doesn't reproduce this issue. We want to use Array.from which uses
362
+ // the iterator.
363
+ const expected = [
364
+ ManifestParser.makeReference('s1.mp4', 0, 10, baseUri),
365
+ ManifestParser.makeReference('s2.mp4', 10, 20, baseUri),
366
+ ManifestParser.makeReference('s3.mp4', 20, 30, baseUri),
366
367
 
367
- ManifestParser.makeReference('s3.mp4', 30, 40, baseUri),
368
- ManifestParser.makeReference('s4.mp4', 40, 50, baseUri),
369
- ManifestParser.makeReference('s5.mp4', 50, 60, baseUri),
370
- ];
371
- const actual = Array.from(stream.segmentIndex);
372
- expect(actual).toEqual(expected);
368
+ ManifestParser.makeReference('s3.mp4', 30, 40, baseUri),
369
+ ManifestParser.makeReference('s4.mp4', 40, 50, baseUri),
370
+ ManifestParser.makeReference('s5.mp4', 50, 60, baseUri),
371
+ ];
372
+ const actual = Array.from(stream.segmentIndex);
373
+ expect(actual).toEqual(expected);
374
+ } finally {
375
+ dashParser.stop();
376
+ }
373
377
  });
374
378
  });
@@ -52,6 +52,11 @@ describe('DashParser SegmentTemplate', () => {
52
52
  };
53
53
  });
54
54
 
55
+ afterEach(() => {
56
+ // Dash parser stop is synchronous.
57
+ parser.stop();
58
+ });
59
+
55
60
  shaka.test.Dash.makeTimelineTests(
56
61
  'SegmentTemplate', 'media="s$Number$.mp4"', []);
57
62
 
@@ -670,6 +675,48 @@ describe('DashParser SegmentTemplate', () => {
670
675
  expect(pos).toBe(1);
671
676
  });
672
677
 
678
+ it('finds correct position in multiperiod content', async () => {
679
+ const source = [
680
+ '<MPD type="static" availabilityStartTime="1970-01-01T00:00:00Z">',
681
+ ' <Period duration="PT30S">',
682
+ ' <AdaptationSet mimeType="video/mp4">',
683
+ ' <Representation bandwidth="500">',
684
+ ' <BaseURL>http://example.com</BaseURL>',
685
+ ' <SegmentTemplate startNumber="0"',
686
+ ' media="$Number$-$Time$-$Bandwidth$.mp4">',
687
+ ' <SegmentTimeline>',
688
+ ' <S t="0" d="5" r="6" />',
689
+ ' </SegmentTimeline>',
690
+ ' </SegmentTemplate>',
691
+ ' </Representation>',
692
+ ' </AdaptationSet>',
693
+ ' </Period>',
694
+ ' <Period duration="PT30S">',
695
+ ' <AdaptationSet mimeType="video/mp4">',
696
+ ' <Representation bandwidth="500">',
697
+ ' <BaseURL>http://example.com</BaseURL>',
698
+ ' <SegmentTemplate startNumber="6"',
699
+ ' media="$Number$-$Time$-$Bandwidth$.mp4">',
700
+ ' <SegmentTimeline>',
701
+ ' <S t="0" d="5" r="6" />',
702
+ ' </SegmentTimeline>',
703
+ ' </SegmentTemplate>',
704
+ ' </Representation>',
705
+ ' </AdaptationSet>',
706
+ ' </Period>',
707
+ '</MPD>',
708
+ ].join('\n');
709
+
710
+ fakeNetEngine.setResponseText('dummy://foo', source);
711
+ const manifest = await parser.start('dummy://foo', playerInterface);
712
+ const stream = manifest.variants[0].video;
713
+ await stream.createSegmentIndex();
714
+
715
+ // simulate a seek into the second period
716
+ const segmentIterator = stream.segmentIndex.getIteratorForTime(42);
717
+ const ref = segmentIterator.next().value;
718
+ expect(ref.startTime).toBe(40);
719
+ });
673
720
 
674
721
  it('returns null if time === last end time', async () => {
675
722
  const info = makeTemplateInfo(makeRanges(0, 2.0, 2));
@@ -540,10 +540,43 @@ describe('HlsParser live', () => {
540
540
 
541
541
  it('sets 3 times target duration as presentation delay if not configured',
542
542
  async () => {
543
+ const media = [
544
+ '#EXTM3U\n',
545
+ '#EXT-X-TARGETDURATION:5\n',
546
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
547
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
548
+ '#EXTINF:2,\n',
549
+ 'main.mp4\n',
550
+ '#EXTINF:2,\n',
551
+ 'main.mp4\n',
552
+ '#EXTINF:2,\n',
553
+ 'main.mp4\n',
554
+ '#EXTINF:2,\n',
555
+ 'main.mp4\n',
556
+ '#EXTINF:2,\n',
557
+ 'main.mp4\n',
558
+ '#EXTINF:2,\n',
559
+ 'main.mp4\n',
560
+ ].join('');
543
561
  const manifest = await testInitialManifest(master, media);
544
562
  expect(manifest.presentationTimeline.getDelay()).toBe(15);
545
563
  });
546
564
 
565
+ it('sets 1 times target duration as presentation delay if there are not enough segments', async () => { // eslint-disable-line max-len
566
+ const media = [
567
+ '#EXTM3U\n',
568
+ '#EXT-X-TARGETDURATION:5\n',
569
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
570
+ '#EXT-X-MEDIA-SEQUENCE:0\n',
571
+ '#EXTINF:2,\n',
572
+ 'main.mp4\n',
573
+ '#EXTINF:2,\n',
574
+ 'main.mp4\n',
575
+ ].join('');
576
+ const manifest = await testInitialManifest(master, media);
577
+ expect(manifest.presentationTimeline.getDelay()).toBe(5);
578
+ });
579
+
547
580
  it('sets presentation delay if defined', async () => {
548
581
  const media = [
549
582
  '#EXTM3U\n',