shaka-player 4.4.1 → 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 (84) hide show
  1. package/.github/workflows/deflake.yaml +8 -5
  2. package/.github/workflows/release-please.yaml +47 -7
  3. package/.github/workflows/shaka-bot-commands/command-test.sh +1 -1
  4. package/CHANGELOG.md +43 -0
  5. package/CONTRIBUTORS +1 -0
  6. package/demo/common/asset.js +5 -0
  7. package/demo/common/assets.js +20 -5
  8. package/demo/common/message_ids.js +1 -1
  9. package/demo/custom.js +5 -5
  10. package/demo/locales/en.json +2 -1
  11. package/demo/locales/source.json +5 -1
  12. package/demo/main.js +1 -1
  13. package/demo/search.js +3 -3
  14. package/dist/demo.compiled.debug.js +75 -73
  15. package/dist/demo.compiled.debug.map +3 -3
  16. package/dist/demo.compiled.js +75 -73
  17. package/dist/demo.compiled.map +3 -3
  18. package/dist/deps.js +2 -2
  19. package/dist/locales.js +31 -31
  20. package/dist/receiver.compiled.debug.js +38 -36
  21. package/dist/receiver.compiled.debug.map +3 -3
  22. package/dist/receiver.compiled.js +38 -36
  23. package/dist/receiver.compiled.map +3 -3
  24. package/dist/shaka-player.compiled.d.ts +533 -296
  25. package/dist/shaka-player.compiled.debug.d.ts +533 -296
  26. package/dist/shaka-player.compiled.debug.externs.js +308 -1
  27. package/dist/shaka-player.compiled.debug.js +280 -265
  28. package/dist/shaka-player.compiled.debug.map +3 -3
  29. package/dist/shaka-player.compiled.externs.js +308 -1
  30. package/dist/shaka-player.compiled.js +1037 -1027
  31. package/dist/shaka-player.compiled.map +4 -4
  32. package/dist/shaka-player.ui.d.ts +577 -340
  33. package/dist/shaka-player.ui.debug.d.ts +577 -340
  34. package/dist/shaka-player.ui.debug.externs.js +308 -1
  35. package/dist/shaka-player.ui.debug.js +341 -326
  36. package/dist/shaka-player.ui.debug.map +3 -3
  37. package/dist/shaka-player.ui.externs.js +308 -1
  38. package/dist/shaka-player.ui.js +1149 -1141
  39. package/dist/shaka-player.ui.map +4 -4
  40. package/docs/tutorials/fairplay.md +8 -0
  41. package/docs/tutorials/faq.md +1 -1
  42. package/docs/tutorials/offline.md +1 -1
  43. package/externs/shaka/text.js +7 -0
  44. package/lib/dash/dash_parser.js +4 -1
  45. package/lib/dash/segment_template.js +3 -0
  46. package/lib/hls/hls_parser.js +68 -28
  47. package/lib/media/media_source_engine.js +1 -1
  48. package/lib/media/segment_index.js +4 -4
  49. package/lib/media/segment_reference.js +6 -1
  50. package/lib/media/streaming_engine.js +14 -24
  51. package/lib/player.js +8 -57
  52. package/lib/text/cue.js +47 -47
  53. package/lib/text/lrc_text_parser.js +8 -0
  54. package/lib/text/mp4_ttml_parser.js +8 -0
  55. package/lib/text/mp4_vtt_parser.js +8 -0
  56. package/lib/text/sbv_text_parser.js +8 -0
  57. package/lib/text/srt_text_parser.js +8 -0
  58. package/lib/text/ssa_text_parser.js +8 -0
  59. package/lib/text/text_engine.js +8 -1
  60. package/lib/text/ttml_text_parser.js +10 -1
  61. package/lib/text/ui_text_displayer.js +49 -3
  62. package/lib/text/vtt_text_parser.js +19 -3
  63. package/lib/transmuxer/ts_transmuxer.js +44 -43
  64. package/lib/util/cmcd_manager.js +6 -1
  65. package/lib/util/error.js +16 -10
  66. package/lib/util/manifest_parser_utils.js +10 -4
  67. package/lib/util/platform.js +14 -0
  68. package/lib/util/player_configuration.js +2 -2
  69. package/lib/util/stream_utils.js +13 -11
  70. package/lib/util/ts_parser.js +73 -16
  71. package/package.json +2 -2
  72. package/test/dash/dash_parser_manifest_unit.js +5 -0
  73. package/test/dash/dash_parser_segment_base_unit.js +5 -0
  74. package/test/dash/dash_parser_segment_list_unit.js +21 -17
  75. package/test/dash/dash_parser_segment_template_unit.js +47 -0
  76. package/test/hls/hls_live_unit.js +33 -0
  77. package/test/hls/hls_parser_unit.js +2 -57
  78. package/test/test/util/dash_parser_util.js +16 -7
  79. package/test/text/text_engine_unit.js +4 -2
  80. package/test/text/ttml_text_parser_unit.js +3 -4
  81. package/test/text/web_vtt_layout_integration.js +0 -1
  82. package/test/transmuxer/transmuxer_integration.js +4 -4
  83. package/test/util/ts_parser_unit.js +1 -1
  84. package/ui/language_utils.js +0 -15
@@ -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',
@@ -1136,63 +1136,6 @@ describe('HlsParser', () => {
1136
1136
  expect(references[6].discontinuitySequence).toBe(3);
1137
1137
  });
1138
1138
 
1139
- it('sets reference timetampOffset based on discontinuity start time',
1140
- async () => {
1141
- const master = [
1142
- '#EXTM3U\n',
1143
- '#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
1144
- 'video\n',
1145
- ].join('');
1146
-
1147
- const media = [
1148
- '#EXTM3U\n',
1149
- '#EXT-X-VERSION:3\n',
1150
- '#EXT-X-TARGETDURATION:5\n',
1151
- '#EXT-X-MEDIA-SEQUENCE:0\n',
1152
- '#EXTINF:3,\n',
1153
- 'clip0-video-0.ts\n',
1154
- '#EXTINF:1,\n',
1155
- 'clip0-video-1.ts\n',
1156
- '#EXT-X-DISCONTINUITY\n',
1157
- '#EXTINF:2,\n',
1158
- 'clip1-video-1.ts\n',
1159
- '#EXTINF:3,\n',
1160
- 'clip1-video-2.ts\n',
1161
- '#EXT-X-DISCONTINUITY\n',
1162
- '#EXTINF:1,\n',
1163
- 'media-clip2-video-0.ts\n',
1164
- '#EXTINF:1,\n',
1165
- 'media-clip2-video-1.ts\n',
1166
- '#EXT-X-DISCONTINUITY\n',
1167
- '#EXTINF:4,\n',
1168
- 'media-clip3-video-1.ts\n',
1169
- '#EXT-X-ENDLIST\n',
1170
- ].join('');
1171
-
1172
- fakeNetEngine
1173
- .setResponseText('test:/master', master)
1174
- .setResponseText('test:/video', media);
1175
-
1176
- const manifest = await parser.start('test:/master', playerInterface);
1177
- await manifest.variants[0].video.createSegmentIndex();
1178
-
1179
- const segmentIndex = manifest.variants[0].video.segmentIndex;
1180
- const references = [];
1181
-
1182
- for (let i = 0; i < 7; i++) {
1183
- references.push(segmentIndex.get(i));
1184
- }
1185
-
1186
- expect(references[0].timestampOffset).toBe(0);
1187
- expect(references[1].timestampOffset).toBe(0);
1188
- expect(references[2].timestampOffset).toBe(4);
1189
- expect(references[3].timestampOffset).toBe(4);
1190
- expect(references[4].timestampOffset).toBe(9);
1191
- expect(references[5].timestampOffset).toBe(9);
1192
- expect(references[6].timestampOffset).toBe(11);
1193
- },
1194
- );
1195
-
1196
1139
  it('parses characteristics from audio tags', async () => {
1197
1140
  const master = [
1198
1141
  '#EXTM3U\n',
@@ -3182,8 +3125,10 @@ describe('HlsParser', () => {
3182
3125
 
3183
3126
  const firstMp4Segment = mp4AesEncryptionVideo.segmentIndex.get(0);
3184
3127
  expect(firstMp4Segment.hlsAes128Key).toBeDefined();
3128
+ expect(firstMp4Segment.initSegmentReference.hlsAes128Key).toBeDefined();
3185
3129
  const secondMp4Segment = mp4AesEncryptionVideo.segmentIndex.get(1);
3186
3130
  expect(secondMp4Segment.hlsAes128Key).toBeNull();
3131
+ expect(secondMp4Segment.initSegmentReference.hlsAes128Key).toBeDefined();
3187
3132
 
3188
3133
  const tsAesEncryptionVideo = actual.variants[2].video;
3189
3134
  await tsAesEncryptionVideo.createSegmentIndex();
@@ -46,11 +46,15 @@ shaka.test.Dash = class {
46
46
  updateDuration: () => {},
47
47
  newDrmInfo: (stream) => {},
48
48
  };
49
- const manifest = await dashParser.start('dummy://foo', playerInterface);
50
- const stream = manifest.variants[0].video;
51
- await stream.createSegmentIndex();
49
+ try {
50
+ const manifest = await dashParser.start('dummy://foo', playerInterface);
51
+ const stream = manifest.variants[0].video;
52
+ await stream.createSegmentIndex();
52
53
 
53
- shaka.test.ManifestParser.verifySegmentIndex(stream, references);
54
+ shaka.test.ManifestParser.verifySegmentIndex(stream, references);
55
+ } finally {
56
+ dashParser.stop();
57
+ }
54
58
  }
55
59
 
56
60
  /**
@@ -82,9 +86,14 @@ shaka.test.Dash = class {
82
86
  updateDuration: () => {},
83
87
  newDrmInfo: (stream) => {},
84
88
  };
85
- const p = dashParser.start('dummy://foo', playerInterface);
86
- await expectAsync(p).toBeRejectedWith(
87
- shaka.test.Util.jasmineError(expectedError));
89
+
90
+ try {
91
+ const p = dashParser.start('dummy://foo', playerInterface);
92
+ await expectAsync(p).toBeRejectedWith(
93
+ shaka.test.Util.jasmineError(expectedError));
94
+ } finally {
95
+ dashParser.stop();
96
+ }
88
97
  }
89
98
 
90
99
  /**
@@ -49,7 +49,8 @@ describe('TextEngine', () => {
49
49
  textEngine.initParser(
50
50
  dummyMimeType,
51
51
  /* sequenceMode= */ false,
52
- /* segmentRelativeVttTiming= */ false);
52
+ /* segmentRelativeVttTiming= */ false,
53
+ shaka.media.ManifestParser.UNKNOWN);
53
54
  });
54
55
 
55
56
  afterEach(() => {
@@ -298,7 +299,8 @@ describe('TextEngine', () => {
298
299
  textEngine.initParser(
299
300
  dummyMimeType,
300
301
  /* sequenceMode= */ false,
301
- /* segmentRelativeVttTiming= */ true);
302
+ /* segmentRelativeVttTiming= */ true,
303
+ shaka.media.ManifestParser.UNKNOWN);
302
304
 
303
305
  mockParseMedia.and.callFake((data, time) => {
304
306
  return [
@@ -1866,9 +1866,8 @@ describe('TtmlTextParser', () => {
1866
1866
  endTime: 60,
1867
1867
  payload: '',
1868
1868
  fontSize: '15px',
1869
- // Styles from regionStyle should apply only to the nested cue.
1870
- backgroundColor: '',
1871
- color: '',
1869
+ backgroundColor: 'transparent',
1870
+ color: 'blue',
1872
1871
  displayAlign: Cue.displayAlign.CENTER,
1873
1872
  textAlign: Cue.textAlign.CENTER,
1874
1873
 
@@ -1970,7 +1969,7 @@ describe('TtmlTextParser', () => {
1970
1969
  startTime: 0,
1971
1970
  endTime: 60,
1972
1971
  payload: '',
1973
- fontSize: '',
1972
+ fontSize: '16px',
1974
1973
  nestedCues: [
1975
1974
  {
1976
1975
  startTime: 0,
@@ -213,7 +213,6 @@ filterDescribe('WebVTT layout', shaka.test.TextLayoutTests.supported, () => {
213
213
  await helper.checkScreenshot('line-negative-2');
214
214
  });
215
215
 
216
- // FIXME: UI version is wrong: not positioned by line
217
216
  it('line 0', async () => {
218
217
  parseAndDisplay([
219
218
  'WEBVTT\n',
@@ -36,8 +36,8 @@ describe('Transmuxer Player', () => {
36
36
  // We must enable this, once it is resolved:
37
37
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1450313
38
38
  const chromeVersion = shaka.util.Platform.chromeVersion();
39
- if (shaka.util.Platform.isEdge() &&
40
- chromeVersion && chromeVersion <= 116) {
39
+ if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() &&
40
+ chromeVersion && chromeVersion <= 118) {
41
41
  return false;
42
42
  }
43
43
  return true;
@@ -57,8 +57,8 @@ describe('Transmuxer Player', () => {
57
57
  // We must enable this, once it is resolved:
58
58
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1450313
59
59
  const chromeVersion = shaka.util.Platform.chromeVersion();
60
- if (shaka.util.Platform.isEdge() &&
61
- chromeVersion && chromeVersion <= 116) {
60
+ if (shaka.util.Platform.isWindows() && shaka.util.Platform.isEdge() &&
61
+ chromeVersion && chromeVersion <= 118) {
62
62
  return false;
63
63
  }
64
64
  return true;
@@ -72,6 +72,6 @@ describe('TsParser', () => {
72
72
  const codecs = new shaka.util.TsParser().parse(tsSegment)
73
73
  .getCodecs();
74
74
  expect(codecs.audio).toBe('aac');
75
- expect(codecs.video).toBe('');
75
+ expect(codecs.video).toBe(null);
76
76
  });
77
77
  });
@@ -193,21 +193,6 @@ shaka.ui.LanguageUtils = class {
193
193
  // Extract the base language from the locale as a fallback step.
194
194
  const language = shaka.util.LanguageUtils.getBase(locale);
195
195
 
196
- // If Intl.DisplayNames is supported we prefer it, because the list of
197
- // languages is up to date.
198
- if (window.Intl && 'DisplayNames' in Intl) {
199
- try {
200
- if (Intl.DisplayNames.supportedLocalesOf([locale]).length) {
201
- const languageNames =
202
- new Intl.DisplayNames([locale], {type: 'language'});
203
- const language = languageNames.of(locale);
204
- return language.charAt(0).toUpperCase() + language.slice(1);
205
- }
206
- } catch (e) {
207
- // Ignore errors and try the fallback
208
- }
209
- }
210
-
211
196
  // First try to resolve the full language name.
212
197
  // If that fails, try the base.
213
198
  // Finally, report "unknown".