shaka-player 3.2.1 → 3.2.2

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 (96) hide show
  1. package/AUTHORS +3 -0
  2. package/CHANGELOG.md +57 -0
  3. package/CONTRIBUTORS +3 -0
  4. package/build/generateExterns.js +1 -1
  5. package/demo/common/assets.js +1 -1
  6. package/demo/index.html +1 -1
  7. package/dist/controls.css +2 -2
  8. package/dist/controls.css.map +1 -1
  9. package/dist/demo.compiled.debug.js +1 -1
  10. package/dist/demo.compiled.js +1 -1
  11. package/dist/deps.js +1 -1
  12. package/dist/locales.js +37 -37
  13. package/dist/receiver.compiled.debug.js +1 -1
  14. package/dist/receiver.compiled.js +1 -1
  15. package/dist/shaka-player.compiled.d.ts +1 -1
  16. package/dist/shaka-player.compiled.debug.d.ts +1 -1
  17. package/dist/shaka-player.compiled.debug.externs.js +1 -1
  18. package/dist/shaka-player.compiled.debug.js +188 -181
  19. package/dist/shaka-player.compiled.debug.map +3 -3
  20. package/dist/shaka-player.compiled.externs.js +1 -1
  21. package/dist/shaka-player.compiled.js +795 -790
  22. package/dist/shaka-player.compiled.map +3 -3
  23. package/dist/shaka-player.ui.d.ts +1 -1
  24. package/dist/shaka-player.ui.debug.d.ts +1 -1
  25. package/dist/shaka-player.ui.debug.externs.js +3 -3
  26. package/dist/shaka-player.ui.debug.js +217 -210
  27. package/dist/shaka-player.ui.debug.map +4 -4
  28. package/dist/shaka-player.ui.externs.js +3 -3
  29. package/dist/shaka-player.ui.js +945 -940
  30. package/dist/shaka-player.ui.map +4 -4
  31. package/docs/tutorials/fairplay.md +1 -1
  32. package/docs/tutorials/ui.md +5 -5
  33. package/karma.conf.js +1 -0
  34. package/lib/ads/client_side_ad_manager.js +46 -86
  35. package/lib/ads/server_side_ad_manager.js +7 -10
  36. package/lib/cast/cast_proxy.js +3 -2
  37. package/lib/cast/cast_receiver.js +2 -1
  38. package/lib/cast/cast_sender.js +2 -2
  39. package/lib/dash/dash_parser.js +93 -2
  40. package/lib/dash/segment_list.js +1 -1
  41. package/lib/dash/segment_template.js +1 -1
  42. package/lib/hls/hls_parser.js +30 -17
  43. package/lib/media/drm_engine.js +7 -0
  44. package/lib/media/gap_jumping_controller.js +4 -2
  45. package/lib/media/media_source_engine.js +1 -2
  46. package/lib/media/streaming_engine.js +2 -1
  47. package/lib/net/networking_engine.js +2 -1
  48. package/lib/player.js +26 -25
  49. package/lib/polyfill/media_capabilities.js +7 -1
  50. package/lib/polyfill/mediasource.js +6 -0
  51. package/lib/polyfill/orientation.js +1 -1
  52. package/lib/polyfill/patchedmediakeys_apple.js +4 -4
  53. package/lib/polyfill/patchedmediakeys_ms.js +4 -4
  54. package/lib/polyfill/patchedmediakeys_webkit.js +4 -4
  55. package/lib/text/mp4_ttml_parser.js +3 -0
  56. package/lib/text/text_engine.js +14 -2
  57. package/lib/text/ttml_text_parser.js +5 -0
  58. package/lib/text/ui_text_displayer.js +85 -37
  59. package/lib/util/fake_event.js +53 -7
  60. package/lib/util/periods.js +4 -1
  61. package/lib/util/platform.js +13 -1
  62. package/lib/util/stream_utils.js +13 -0
  63. package/package.json +1 -1
  64. package/test/cast/cast_proxy_unit.js +12 -6
  65. package/test/cast/cast_utils_unit.js +1 -1
  66. package/test/dash/dash_parser_manifest_unit.js +187 -1
  67. package/test/hls/hls_parser_unit.js +5 -1
  68. package/test/media/closed_caption_parser_unit.js +6 -1
  69. package/test/media/drm_engine_unit.js +44 -0
  70. package/test/player_integration.js +38 -0
  71. package/test/test/assets/3675/chunk-stream0-00001.m4s +0 -0
  72. package/test/test/assets/3675/chunk-stream0-00002.m4s +0 -0
  73. package/test/test/assets/3675/chunk-stream0-00003.m4s +0 -0
  74. package/test/test/assets/3675/chunk-stream0-00004.m4s +0 -0
  75. package/test/test/assets/3675/chunk-stream0-00005.m4s +0 -0
  76. package/test/test/assets/3675/chunk-stream0-00006.m4s +0 -0
  77. package/test/test/assets/3675/chunk-stream0-00007.m4s +0 -0
  78. package/test/test/assets/3675/dash_0.mpd +30 -0
  79. package/test/test/assets/3675/dash_1.mpd +30 -0
  80. package/test/test/assets/3675/dash_2.mpd +30 -0
  81. package/test/test/assets/3675/dash_3.mpd +30 -0
  82. package/test/test/assets/3675/dash_4.mpd +30 -0
  83. package/test/test/assets/3675/dash_5.mpd +26 -0
  84. package/test/test/assets/3675/init-stream0.m4s +0 -0
  85. package/test/test/util/fake_ad_manager.js +1 -1
  86. package/test/text/ttml_text_parser_unit.js +9 -0
  87. package/test/text/ui_text_displayer_unit.js +29 -17
  88. package/test/ui/localization_unit.js +15 -14
  89. package/test/ui/text_displayer_layout_unit.js +13 -1
  90. package/test/util/stream_utils_unit.js +35 -0
  91. package/ui/cast_button.js +2 -3
  92. package/ui/controls.js +4 -6
  93. package/ui/less/containers.less +3 -7
  94. package/ui/locales/ru.json +6 -6
  95. package/ui/localization.js +28 -51
  96. package/ui/pip_button.js +2 -3
@@ -38,6 +38,14 @@ describe('DashParser Manifest', () => {
38
38
 
39
39
  /** @type {string} */
40
40
  const thumbnailScheme = 'http://dashif.org/guidelines/thumbnail_tile';
41
+ /**
42
+ * CICP scheme. parameter must be one of the following: "ColourPrimaries",
43
+ * "TransferCharacteristics", or "MatrixCoefficients".
44
+ *
45
+ * @param {string} parameter
46
+ * @return {string}
47
+ */
48
+ const cicpScheme = (parameter) => `urn:mpeg:mpegB:cicp:${parameter}`;
41
49
 
42
50
  beforeAll(async () => {
43
51
  mp4Index = await shaka.test.Util.fetch(mp4IndexSegmentUri);
@@ -1896,7 +1904,8 @@ describe('DashParser Manifest', () => {
1896
1904
  expect(textStream.forced).toBe(true);
1897
1905
  });
1898
1906
 
1899
- it('supports HDR signaling', async () => {
1907
+ it('supports HDR signaling via profiles', async () => {
1908
+ // (DASH-IF IOP v4.3 10.3.3.)
1900
1909
  const hdrProfile =
1901
1910
  'http://dashif.org/guidelines/dash-if-uhd#hevc-hdr-pq10';
1902
1911
  const manifestText = [
@@ -1927,6 +1936,110 @@ describe('DashParser Manifest', () => {
1927
1936
  expect(stream.hdr).toBe('PQ');
1928
1937
  });
1929
1938
 
1939
+ it('supports HDR signaling via SupplementalProperty', async () => {
1940
+ // (DASH-IF IOP v4.3 6.2.5.1.)
1941
+ const hdrScheme = cicpScheme('TransferCharacteristics');
1942
+ const pq = 16;
1943
+ const manifestText = [
1944
+ '<MPD minBufferTime="PT75S">',
1945
+ ' <Period id="1" duration="PT30S">',
1946
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
1947
+ ` <SupplementalProperty schemeIdUri="${hdrScheme}" value="${pq}" />`,
1948
+ ' <Representation codecs="hvc1.2.4.L150.90">',
1949
+ ' <BaseURL>v-sd.mp4</BaseURL>',
1950
+ ' <SegmentBase indexRange="100-200" />',
1951
+ ' </Representation>',
1952
+ ' </AdaptationSet>',
1953
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
1954
+ ' <Representation id="audio-en">',
1955
+ ' <BaseURL>a-en.mp4</BaseURL>',
1956
+ ' <SegmentBase indexRange="100-200" />',
1957
+ ' </Representation>',
1958
+ ' </AdaptationSet>',
1959
+ ' </Period>',
1960
+ '</MPD>',
1961
+ ].join('\n');
1962
+
1963
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
1964
+
1965
+ /** @type {shaka.extern.Manifest} */
1966
+ const manifest = await parser.start('dummy://foo', playerInterface);
1967
+ expect(manifest.variants.length).toBe(1);
1968
+ const stream = manifest.variants[0].video;
1969
+ expect(stream.hdr).toBe('PQ');
1970
+ });
1971
+
1972
+ it('supports HDR signaling via EssentialProperty', async () => {
1973
+ // (DASH-IF IOP v4.3 6.2.5.1.)
1974
+ const hdrScheme = cicpScheme('TransferCharacteristics');
1975
+ const hlg = 18;
1976
+ const manifestText = [
1977
+ '<MPD minBufferTime="PT75S">',
1978
+ ' <Period id="1" duration="PT30S">',
1979
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
1980
+ ` <EssentialProperty schemeIdUri="${hdrScheme}" value="${hlg}" />`,
1981
+ ' <Representation codecs="hvc1.2.4.L153.B0">',
1982
+ ' <BaseURL>v-sd.mp4</BaseURL>',
1983
+ ' <SegmentBase indexRange="100-200" />',
1984
+ ' </Representation>',
1985
+ ' </AdaptationSet>',
1986
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
1987
+ ' <Representation id="audio-en">',
1988
+ ' <BaseURL>a-en.mp4</BaseURL>',
1989
+ ' <SegmentBase indexRange="100-200" />',
1990
+ ' </Representation>',
1991
+ ' </AdaptationSet>',
1992
+ ' </Period>',
1993
+ '</MPD>',
1994
+ ].join('\n');
1995
+
1996
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
1997
+
1998
+ /** @type {shaka.extern.Manifest} */
1999
+ const manifest = await parser.start('dummy://foo', playerInterface);
2000
+ expect(manifest.variants.length).toBe(1);
2001
+ const stream = manifest.variants[0].video;
2002
+ expect(stream.hdr).toBe('HLG');
2003
+ });
2004
+
2005
+ it('supports SDR signalling via EssentialProperty', async () => {
2006
+ // (DASH-IF IOP v4.3 6.2.5.1.)
2007
+ const scheme = cicpScheme('TransferCharacteristics');
2008
+ const sdrValues = [1, 6, 13, 14, 15];
2009
+ const manifestPromises = [];
2010
+ for (const value of sdrValues) {
2011
+ const manifestText = [
2012
+ '<MPD minBufferTime="PT75S">',
2013
+ ' <Period id="1" duration="PT30S">',
2014
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2015
+ ` <EssentialProperty schemeIdUri="${scheme}" value="${value}" />`,
2016
+ ' <Representation codecs="avc1.640028">',
2017
+ ' <BaseURL>v-sd.mp4</BaseURL>',
2018
+ ' <SegmentBase indexRange="100-200" />',
2019
+ ' </Representation>',
2020
+ ' </AdaptationSet>',
2021
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
2022
+ ' <Representation id="audio-en">',
2023
+ ' <BaseURL>a-en.mp4</BaseURL>',
2024
+ ' <SegmentBase indexRange="100-200" />',
2025
+ ' </Representation>',
2026
+ ' </AdaptationSet>',
2027
+ ' </Period>',
2028
+ '</MPD>',
2029
+ ].join('\n');
2030
+
2031
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2032
+
2033
+ manifestPromises.push(parser.start('dummy://foo', playerInterface));
2034
+ }
2035
+ const manifests = await Promise.all(manifestPromises);
2036
+ for (const manifest of manifests) {
2037
+ expect(manifest.variants.length).toBe(1);
2038
+ const stream = manifest.variants[0].video;
2039
+ expect(stream.hdr).toBe('SDR');
2040
+ }
2041
+ });
2042
+
1930
2043
  it('Does not error when image adaptation sets are present', async () => {
1931
2044
  const manifestText = [
1932
2045
  '<MPD minBufferTime="PT75S">',
@@ -2150,4 +2263,77 @@ describe('DashParser Manifest', () => {
2150
2263
  expect(uri).not.toContain('/p2/');
2151
2264
  }
2152
2265
  });
2266
+
2267
+ /**
2268
+ * @param {!Array.<number>} periods Start time of multiple periods
2269
+ * @return {string}
2270
+ */
2271
+ function buildManifestWithPeriodStartTime(periods) {
2272
+ const mpdTemplate = [
2273
+ `<MPD type="dynamic"`,
2274
+ 'availabilityStartTime="1970-01-01T00:00:00Z"',
2275
+ 'timeShiftBufferDepth="PT10H">',
2276
+ ' %(periods)s',
2277
+ '</MPD>',
2278
+ ].join('\n');
2279
+ const periodTemplate = (id, period, duration) => {
2280
+ return [
2281
+ ` <Period id="${id}" start="PT${period}S">`,
2282
+ ' <AdaptationSet mimeType="video/mp4" lang="en" group="1">',
2283
+ ' <SegmentTemplate startNumber="1" media="l-$Number$.mp4">',
2284
+ ' <SegmentTimeline>',
2285
+ ` <S t="0" d="${duration}" />`,
2286
+ ' </SegmentTimeline>',
2287
+ ' </SegmentTemplate>',
2288
+ ' <Representation id="1"/>',
2289
+ ' </AdaptationSet>',
2290
+ ' </Period>',
2291
+ ].join('\n');
2292
+ };
2293
+ const periodXmls = periods.map((period, i) => {
2294
+ const duration = i+1 === periods.length ? 10 : periods[i+1] - period;
2295
+ // Period start time as ID here. If we use index then there will be
2296
+ // periods with same period ID and different start time which are invalid.
2297
+ return periodTemplate(period, period, duration);
2298
+ });
2299
+ return sprintf(mpdTemplate, {
2300
+ periods: periodXmls.join('\n'),
2301
+ });
2302
+ }
2303
+
2304
+ // Bug description: Inconsistent period start time in the manifests due
2305
+ // to failover triggered in backend servers
2306
+
2307
+ // When one of the servers is down, the manifest will be served by other
2308
+ // redundant servers. The period start time might become out of sync
2309
+ // during the switch-over/recovery.
2310
+
2311
+ it('skip periods that are earlier than max period start time', async () => {
2312
+ const sources = [
2313
+ buildManifestWithPeriodStartTime([5, 15]),
2314
+ buildManifestWithPeriodStartTime([6, 15]), // simulate out-of-sync of +1s
2315
+ buildManifestWithPeriodStartTime([4, 15]), // simulate out-of-sync of -1s
2316
+ ];
2317
+ const segments = [];
2318
+
2319
+ for (const source of sources) {
2320
+ fakeNetEngine.setResponseText('dummy://foo', source);
2321
+ /** @type {shaka.extern.Manifest} */
2322
+ // eslint-disable-next-line no-await-in-loop
2323
+ const manifest = await parser.start('dummy://foo', playerInterface);
2324
+ const video = manifest.variants[0].video;
2325
+ // eslint-disable-next-line no-await-in-loop
2326
+ await video.createSegmentIndex();
2327
+ goog.asserts.assert(video.segmentIndex, 'Null segmentIndex!');
2328
+ segments.push(Array.from(video.segmentIndex));
2329
+ }
2330
+
2331
+ // Expect identical segments
2332
+ expect(segments[0].length).toBe(2);
2333
+ expect(segments[1].length).toBe(2);
2334
+ expect(segments[0][0].startTime).toBe(5);
2335
+ expect(segments[1][0].startTime).toBe(5);
2336
+ expect(segments[0][1].startTime).toBe(15);
2337
+ expect(segments[1][1].startTime).toBe(15);
2338
+ });
2153
2339
  });
@@ -783,7 +783,7 @@ describe('HlsParser', () => {
783
783
  'RESOLUTION=960x540,FRAME-RATE=120,AUDIO="aud2"\n',
784
784
  'video2\n',
785
785
  '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
786
- 'URI="audio"\n',
786
+ 'DEFAULT=YES,URI="audio"\n',
787
787
  '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud2",LANGUAGE="fr",',
788
788
  'URI="audio2"\n',
789
789
  ].join('');
@@ -801,6 +801,7 @@ describe('HlsParser', () => {
801
801
  manifest.anyTimeline();
802
802
  manifest.addPartialVariant((variant) => {
803
803
  variant.bandwidth = 200;
804
+ variant.primary = true;
804
805
  variant.addPartialStream(ContentType.VIDEO, (stream) => {
805
806
  stream.size(960, 540);
806
807
  });
@@ -810,6 +811,7 @@ describe('HlsParser', () => {
810
811
  });
811
812
  manifest.addPartialVariant((variant) => {
812
813
  variant.bandwidth = 300;
814
+ variant.primary = false;
813
815
  variant.addPartialStream(ContentType.VIDEO, (stream) => {
814
816
  stream.size(960, 540);
815
817
  });
@@ -1307,6 +1309,8 @@ describe('HlsParser', () => {
1307
1309
  // stream.
1308
1310
  const timeline = actual.presentationTimeline;
1309
1311
  expect(timeline.getDuration()).toBe(10);
1312
+ expect(timeline.getSeekRangeStart()).toBe(0);
1313
+ expect(timeline.getSeekRangeEnd()).toBe(10);
1310
1314
 
1311
1315
  expect(actual.textStreams.length).toBe(1);
1312
1316
  expect(actual.variants.length).toBe(1);
@@ -1,3 +1,9 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
1
7
  goog.require('shaka.media.ClosedCaptionParser');
2
8
  goog.require('shaka.test.Util');
3
9
 
@@ -12,4 +18,3 @@ describe('ClosedCaptionParser', () => {
12
18
  parser.parseFrom(videoSegment);
13
19
  });
14
20
  });
15
-
@@ -2152,6 +2152,50 @@ describe('DrmEngine', () => {
2152
2152
  [drmInfoAudio]);
2153
2153
  expect(returned).toEqual([drmInfoDesired]);
2154
2154
  });
2155
+
2156
+ it('dedupes the merged init data based on keyId matching', () => {
2157
+ const serverCert = new Uint8Array(0);
2158
+ const drmInfoVideo = {
2159
+ keySystem: 'drm.abc',
2160
+ licenseServerUri: 'http://abc.drm/license',
2161
+ distinctiveIdentifierRequired: false,
2162
+ persistentStateRequired: true,
2163
+ videoRobustness: 'really_really_ridiculously_good',
2164
+ serverCertificate: serverCert,
2165
+ serverCertificateUri: '',
2166
+ initData: [{keyId: 'v-init'}],
2167
+ keyIds: new Set(['deadbeefdeadbeefdeadbeefdeadbeef']),
2168
+ };
2169
+ const drmInfoAudio = {
2170
+ keySystem: 'drm.abc',
2171
+ licenseServerUri: undefined,
2172
+ distinctiveIdentifierRequired: true,
2173
+ persistentStateRequired: false,
2174
+ audioRobustness: 'good',
2175
+ serverCertificate: undefined,
2176
+ serverCertificateUri: '',
2177
+ initData: [{keyId: 'v-init'}, {keyId: 'a-init'}],
2178
+ keyIds: new Set(['eadbeefdeadbeefdeadbeefdeadbeefd']),
2179
+ };
2180
+ const drmInfoDesired = {
2181
+ keySystem: 'drm.abc',
2182
+ licenseServerUri: 'http://abc.drm/license',
2183
+ distinctiveIdentifierRequired: true,
2184
+ persistentStateRequired: true,
2185
+ audioRobustness: 'good',
2186
+ videoRobustness: 'really_really_ridiculously_good',
2187
+ serverCertificate: serverCert,
2188
+ serverCertificateUri: '',
2189
+ initData: [{keyId: 'v-init'}, {keyId: 'a-init'}],
2190
+ keyIds: new Set([
2191
+ 'deadbeefdeadbeefdeadbeefdeadbeef',
2192
+ 'eadbeefdeadbeefdeadbeefdeadbeefd',
2193
+ ]),
2194
+ };
2195
+ const returned = shaka.media.DrmEngine.getCommonDrmInfos([drmInfoVideo],
2196
+ [drmInfoAudio]);
2197
+ expect(returned).toEqual([drmInfoDesired]);
2198
+ });
2155
2199
  }); // describe('getCommonDrmInfos')
2156
2200
 
2157
2201
  describe('configure', () => {
@@ -652,6 +652,44 @@ describe('Player', () => {
652
652
  });
653
653
  });
654
654
 
655
+ describe('seek range', () => {
656
+ // Regression test for Issue #3675.
657
+ it('has a reasonable seek range after going from live to VOD', async () => {
658
+ const netEngine = player.getNetworkingEngine();
659
+ const startTime = Date.now();
660
+ netEngine.registerRequestFilter((type, request) => {
661
+ if (type != shaka.net.NetworkingEngine.RequestType.MANIFEST) {
662
+ return;
663
+ }
664
+ // Simulate a live stream by providing different manifests over time.
665
+ const time = (Date.now() - startTime) / 1000;
666
+ const manifestNumber = Math.min(5, Math.floor(0.5 + time / 2));
667
+ request.uris = [
668
+ '/base/test/test/assets/3675/dash_' + manifestNumber + '.mpd',
669
+ ];
670
+ console.log('getting manifest', request.uris);
671
+ });
672
+
673
+ // Play the stream.
674
+ await player.load('/base/test/test/assets/3675/dash_0.mpd');
675
+ video.play();
676
+
677
+ // Wait for the stream to be over.
678
+ eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
679
+ /** @type {shaka.test.Waiter} */
680
+ const waiter = new shaka.test.Waiter(eventManager)
681
+ .timeoutAfter(20).failOnTimeout(true);
682
+ await waiter.waitForEnd(video);
683
+
684
+ // The stream should have transitioned to VOD by now.
685
+ expect(player.isLive()).toBe(false);
686
+
687
+ // Check that the final seek range is as expected.
688
+ const seekRange = player.seekRange();
689
+ expect(seekRange.end).toBe(14);
690
+ });
691
+ });
692
+
655
693
  describe('buffering', () => {
656
694
  const startBuffering = jasmine.objectContaining({buffering: true});
657
695
  const endBuffering = jasmine.objectContaining({buffering: false});
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns="urn:mpeg:dash:schema:mpd:2011"
4
+ xmlns:xlink="http://www.w3.org/1999/xlink"
5
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
6
+ profiles="urn:mpeg:dash:profile:isoff-live:2011"
7
+ type="dynamic"
8
+ minimumUpdatePeriod="PT2S"
9
+ suggestedPresentationDelay="PT2S"
10
+ availabilityStartTime="2021-10-28T07:36:27.755Z"
11
+ publishTime="2021-10-28T07:36:29.744Z"
12
+ timeShiftBufferDepth="PT10.0S"
13
+ maxSegmentDuration="PT2.0S"
14
+ minBufferTime="PT4.0S">
15
+ <ProgramInformation>
16
+ </ProgramInformation>
17
+ <ServiceDescription id="0">
18
+ </ServiceDescription>
19
+ <Period id="0" start="PT0.0S">
20
+ <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
21
+ <Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
22
+ <SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
23
+ <SegmentTimeline>
24
+ <S t="0" d="30720" />
25
+ </SegmentTimeline>
26
+ </SegmentTemplate>
27
+ </Representation>
28
+ </AdaptationSet>
29
+ </Period>
30
+ </MPD>
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns="urn:mpeg:dash:schema:mpd:2011"
4
+ xmlns:xlink="http://www.w3.org/1999/xlink"
5
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
6
+ profiles="urn:mpeg:dash:profile:isoff-live:2011"
7
+ type="dynamic"
8
+ minimumUpdatePeriod="PT2S"
9
+ suggestedPresentationDelay="PT2S"
10
+ availabilityStartTime="2021-10-28T07:36:27.755Z"
11
+ publishTime="2021-10-28T07:36:31.750Z"
12
+ timeShiftBufferDepth="PT10.0S"
13
+ maxSegmentDuration="PT2.0S"
14
+ minBufferTime="PT4.0S">
15
+ <ProgramInformation>
16
+ </ProgramInformation>
17
+ <ServiceDescription id="0">
18
+ </ServiceDescription>
19
+ <Period id="0" start="PT0.0S">
20
+ <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
21
+ <Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
22
+ <SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
23
+ <SegmentTimeline>
24
+ <S t="0" d="30720" r="1" />
25
+ </SegmentTimeline>
26
+ </SegmentTemplate>
27
+ </Representation>
28
+ </AdaptationSet>
29
+ </Period>
30
+ </MPD>
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns="urn:mpeg:dash:schema:mpd:2011"
4
+ xmlns:xlink="http://www.w3.org/1999/xlink"
5
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
6
+ profiles="urn:mpeg:dash:profile:isoff-live:2011"
7
+ type="dynamic"
8
+ minimumUpdatePeriod="PT2S"
9
+ suggestedPresentationDelay="PT2S"
10
+ availabilityStartTime="2021-10-28T07:36:27.755Z"
11
+ publishTime="2021-10-28T07:36:35.752Z"
12
+ timeShiftBufferDepth="PT10.0S"
13
+ maxSegmentDuration="PT2.0S"
14
+ minBufferTime="PT4.0S">
15
+ <ProgramInformation>
16
+ </ProgramInformation>
17
+ <ServiceDescription id="0">
18
+ </ServiceDescription>
19
+ <Period id="0" start="PT0.0S">
20
+ <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
21
+ <Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
22
+ <SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
23
+ <SegmentTimeline>
24
+ <S t="0" d="30720" r="3" />
25
+ </SegmentTimeline>
26
+ </SegmentTemplate>
27
+ </Representation>
28
+ </AdaptationSet>
29
+ </Period>
30
+ </MPD>
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns="urn:mpeg:dash:schema:mpd:2011"
4
+ xmlns:xlink="http://www.w3.org/1999/xlink"
5
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
6
+ profiles="urn:mpeg:dash:profile:isoff-live:2011"
7
+ type="dynamic"
8
+ minimumUpdatePeriod="PT2S"
9
+ suggestedPresentationDelay="PT2S"
10
+ availabilityStartTime="2021-10-28T07:36:27.755Z"
11
+ publishTime="2021-10-28T07:36:37.752Z"
12
+ timeShiftBufferDepth="PT10.0S"
13
+ maxSegmentDuration="PT2.0S"
14
+ minBufferTime="PT4.0S">
15
+ <ProgramInformation>
16
+ </ProgramInformation>
17
+ <ServiceDescription id="0">
18
+ </ServiceDescription>
19
+ <Period id="0" start="PT0.0S">
20
+ <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
21
+ <Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
22
+ <SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
23
+ <SegmentTimeline>
24
+ <S t="0" d="30720" r="4" />
25
+ </SegmentTimeline>
26
+ </SegmentTemplate>
27
+ </Representation>
28
+ </AdaptationSet>
29
+ </Period>
30
+ </MPD>
@@ -0,0 +1,30 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns="urn:mpeg:dash:schema:mpd:2011"
4
+ xmlns:xlink="http://www.w3.org/1999/xlink"
5
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
6
+ profiles="urn:mpeg:dash:profile:isoff-live:2011"
7
+ type="dynamic"
8
+ minimumUpdatePeriod="PT2S"
9
+ suggestedPresentationDelay="PT2S"
10
+ availabilityStartTime="2021-10-28T07:36:27.755Z"
11
+ publishTime="2021-10-28T07:36:41.751Z"
12
+ timeShiftBufferDepth="PT10.0S"
13
+ maxSegmentDuration="PT2.0S"
14
+ minBufferTime="PT4.0S">
15
+ <ProgramInformation>
16
+ </ProgramInformation>
17
+ <ServiceDescription id="0">
18
+ </ServiceDescription>
19
+ <Period id="0" start="PT0.0S">
20
+ <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
21
+ <Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
22
+ <SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="3">
23
+ <SegmentTimeline>
24
+ <S t="61440" d="30720" r="4" />
25
+ </SegmentTimeline>
26
+ </SegmentTemplate>
27
+ </Representation>
28
+ </AdaptationSet>
29
+ </Period>
30
+ </MPD>
@@ -0,0 +1,26 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns="urn:mpeg:dash:schema:mpd:2011"
4
+ xmlns:xlink="http://www.w3.org/1999/xlink"
5
+ xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
6
+ profiles="urn:mpeg:dash:profile:isoff-live:2011"
7
+ type="static"
8
+ mediaPresentationDuration="PT14.0S"
9
+ maxSegmentDuration="PT2.0S"
10
+ minBufferTime="PT4.0S">
11
+ <ProgramInformation>
12
+ </ProgramInformation>
13
+ <ServiceDescription id="0">
14
+ </ServiceDescription>
15
+ <Period id="0" start="PT0.0S">
16
+ <AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
17
+ <Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
18
+ <SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="3">
19
+ <SegmentTimeline>
20
+ <S t="61440" d="30720" r="4" />
21
+ </SegmentTimeline>
22
+ </SegmentTemplate>
23
+ </Representation>
24
+ </AdaptationSet>
25
+ </Period>
26
+ </MPD>
@@ -85,7 +85,7 @@ shaka.test.FakeAdManager = class extends shaka.util.FakeEventTarget {
85
85
  */
86
86
  startAd(ad) {
87
87
  const event = new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STARTED,
88
- {'ad': ad});
88
+ (new Map()).set('ad', ad));
89
89
 
90
90
  this.dispatchEvent(event);
91
91
  }
@@ -476,6 +476,15 @@ describe('TtmlTextParser', () => {
476
476
  {periodStart: 0, segmentStart: 0, segmentEnd: 0});
477
477
  });
478
478
 
479
+ it('supports comments in the body', () => {
480
+ verifyHelper(
481
+ [],
482
+ '<tt><body><div>' +
483
+ '<!-- text-based TTML -->' +
484
+ '</div></body></tt>',
485
+ {periodStart: 0, segmentStart: 0, segmentEnd: 0});
486
+ });
487
+
479
488
  it('parses alignment from textAlign attribute of a region', () => {
480
489
  verifyHelper(
481
490
  [