shaka-player 3.3.0 → 3.3.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 (53) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/build/conformance.textproto +183 -169
  3. package/dist/controls.css +1 -1
  4. package/dist/deps.js +1 -1
  5. package/dist/locales.js +30 -30
  6. package/dist/shaka-player.compiled.d.ts +25 -2
  7. package/dist/shaka-player.compiled.debug.d.ts +25 -2
  8. package/dist/shaka-player.compiled.debug.externs.js +22 -1
  9. package/dist/shaka-player.compiled.debug.js +226 -222
  10. package/dist/shaka-player.compiled.debug.map +3 -3
  11. package/dist/shaka-player.compiled.externs.js +22 -1
  12. package/dist/shaka-player.compiled.js +814 -812
  13. package/dist/shaka-player.compiled.map +4 -4
  14. package/dist/shaka-player.ui.d.ts +25 -2
  15. package/dist/shaka-player.ui.debug.d.ts +25 -2
  16. package/dist/shaka-player.ui.debug.externs.js +22 -1
  17. package/dist/shaka-player.ui.debug.js +244 -240
  18. package/dist/shaka-player.ui.debug.map +3 -3
  19. package/dist/shaka-player.ui.externs.js +22 -1
  20. package/dist/shaka-player.ui.js +995 -992
  21. package/dist/shaka-player.ui.map +4 -4
  22. package/externs/cmcd.js +186 -0
  23. package/externs/shaka/player.js +8 -0
  24. package/externs/shaka/text.js +10 -0
  25. package/lib/hls/hls_parser.js +30 -0
  26. package/lib/media/segment_index.js +2 -1
  27. package/lib/media/segment_reference.js +19 -1
  28. package/lib/media/streaming_engine.js +5 -2
  29. package/lib/player.js +23 -17
  30. package/lib/polyfill/media_capabilities.js +30 -15
  31. package/lib/text/cue.js +6 -0
  32. package/lib/text/ttml_text_parser.js +84 -58
  33. package/lib/text/ui_text_displayer.js +17 -11
  34. package/lib/util/cmcd_manager.js +47 -201
  35. package/lib/util/stream_utils.js +86 -10
  36. package/lib/util/xml_utils.js +19 -0
  37. package/package.json +2 -2
  38. package/test/media/drm_engine_unit.js +3 -3
  39. package/test/media/streaming_engine_integration.js +2 -1
  40. package/test/media/streaming_engine_unit.js +145 -0
  41. package/test/player_integration.js +41 -8
  42. package/test/player_src_equals_integration.js +41 -8
  43. package/test/player_unit.js +19 -9
  44. package/test/test/assets/chapters.vtt +2 -2
  45. package/test/test/assets/chapters2.vtt +10 -0
  46. package/test/test/util/ttml_utils.js +81 -0
  47. package/test/text/mp4_ttml_parser_unit.js +11 -18
  48. package/test/text/ttml_text_parser_unit.js +499 -230
  49. package/test/util/cmcd_manager_unit.js +29 -15
  50. package/test/util/stream_utils_unit.js +36 -30
  51. package/third_party/closure-uri/uri.js +21 -0
  52. package/ui/text_selection.js +1 -0
  53. package/externs/media_capabilities.js +0 -16
@@ -97,6 +97,9 @@ describe('StreamingEngine', () => {
97
97
  /** @type {!shaka.media.StreamingEngine} */
98
98
  let streamingEngine;
99
99
 
100
+ /** @type {function(function(), number)} */
101
+ let realSetTimeout;
102
+
100
103
  /**
101
104
  * Runs the fake event loop.
102
105
  * @param {function()=} callback An optional callback that is executed
@@ -116,6 +119,7 @@ describe('StreamingEngine', () => {
116
119
  }
117
120
 
118
121
  beforeAll(() => {
122
+ realSetTimeout = window.setTimeout;
119
123
  jasmine.clock().install();
120
124
  jasmine.clock().mockDate();
121
125
  });
@@ -824,6 +828,53 @@ describe('StreamingEngine', () => {
824
828
  .toHaveBeenCalledWith('video', 0, lt20, gt40);
825
829
  });
826
830
 
831
+ // Regression test for https://github.com/google/shaka-player/issues/3717
832
+ it('applies fudge factors for the duration', async () => {
833
+ setupVod();
834
+
835
+ // In #3717, the duration was just barely large enough to encompass an
836
+ // additional segment, but that segment didn't exist, so playback never
837
+ // completed. Here, we set the duration to just beyond the 3rd segment, and
838
+ // we make the 4th segment fail when requested.
839
+ const duration = 30.000000005;
840
+ timeline.getDuration.and.returnValue(duration);
841
+
842
+ const targetUri = '1_video_3'; // The URI of the 4th video segment.
843
+ failRequestsForTarget(netEngine, targetUri);
844
+
845
+ mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
846
+ createStreamingEngine();
847
+
848
+ // Here we go!
849
+ streamingEngine.switchVariant(variant);
850
+ streamingEngine.switchTextStream(textStream);
851
+ await streamingEngine.start();
852
+ playing = true;
853
+ await runTest();
854
+
855
+ // The end of the stream should have been reached, and the 4th segment from
856
+ // each type should never have been requested.
857
+ expect(mediaSourceEngine.endOfStream).toHaveBeenCalled();
858
+
859
+ const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
860
+
861
+ netEngine.expectRequest('0_audio_0', segmentType);
862
+ netEngine.expectRequest('0_video_0', segmentType);
863
+ netEngine.expectRequest('0_text_0', segmentType);
864
+
865
+ netEngine.expectRequest('0_audio_1', segmentType);
866
+ netEngine.expectRequest('0_video_1', segmentType);
867
+ netEngine.expectRequest('0_text_1', segmentType);
868
+
869
+ netEngine.expectRequest('1_audio_2', segmentType);
870
+ netEngine.expectRequest('1_video_2', segmentType);
871
+ netEngine.expectRequest('1_text_2', segmentType);
872
+
873
+ netEngine.expectNoRequest('1_audio_3', segmentType);
874
+ netEngine.expectNoRequest('1_video_3', segmentType);
875
+ netEngine.expectNoRequest('1_text_3', segmentType);
876
+ });
877
+
827
878
  it('does not buffer one media type ahead of another', async () => {
828
879
  setupVod();
829
880
  mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
@@ -1391,6 +1442,66 @@ describe('StreamingEngine', () => {
1391
1442
  });
1392
1443
  });
1393
1444
 
1445
+ it('into unbuffered regions when nothing is buffered ' +
1446
+ 'and mediaState is performing an update', async () => {
1447
+ // Here we go!
1448
+ streamingEngine.switchVariant(variant);
1449
+ streamingEngine.switchTextStream(textStream);
1450
+ // ensure init source buffer promise does not resolve before seeked()
1451
+ // so mediaState remains in "performingUpdate" state
1452
+ const initSourceBufferPromise = new shaka.util.PublicPromise();
1453
+ mediaSourceEngine.setStreamProperties.and
1454
+ .returnValue(initSourceBufferPromise);
1455
+ await streamingEngine.start();
1456
+ playing = true;
1457
+
1458
+ // tick to trigger mediaState updates
1459
+ jasmine.clock().tick(1);
1460
+ // give a chance for fetchAndAppend_ to be invoked
1461
+ // by async onUpdate_ callback
1462
+ await Util.shortDelay(realSetTimeout);
1463
+
1464
+ // Nothing is buffered yet.
1465
+ expect(mediaSourceEngine.segments).toEqual({
1466
+ audio: [false, false, false, false],
1467
+ video: [false, false, false, false],
1468
+ text: [false, false, false, false],
1469
+ });
1470
+
1471
+ // Seek forward to an unbuffered region in the first Period.
1472
+ presentationTimeInSeconds = 15;
1473
+ streamingEngine.seeked();
1474
+
1475
+ // resolve initSourceBufferPromise after seeked(), waitingToClearBuffer
1476
+ // should have been set, so this will now trigger the actual flush of
1477
+ // the buffer
1478
+ initSourceBufferPromise.resolve();
1479
+ mediaSourceEngine.setStreamProperties.and
1480
+ .returnValue(Promise.resolve());
1481
+
1482
+ // allow mediaState update to resolve
1483
+ await Util.shortDelay(realSetTimeout);
1484
+
1485
+ onTick.and.callFake(() => {
1486
+ expect(mediaSourceEngine.clear).toHaveBeenCalled();
1487
+ onTick.and.stub();
1488
+ });
1489
+
1490
+ await runTest(Util.spyFunc(onTick));
1491
+
1492
+ // Verify buffers.
1493
+ expect(mediaSourceEngine.initSegments).toEqual({
1494
+ audio: [false, true],
1495
+ video: [false, true],
1496
+ text: [],
1497
+ });
1498
+ expect(mediaSourceEngine.segments).toEqual({
1499
+ audio: [false, true, true, true],
1500
+ video: [false, true, true, true],
1501
+ text: [false, true, true, true],
1502
+ });
1503
+ });
1504
+
1394
1505
  it('into unbuffered regions near segment start', async () => {
1395
1506
  // Here we go!
1396
1507
  streamingEngine.switchVariant(variant);
@@ -3390,6 +3501,40 @@ describe('StreamingEngine', () => {
3390
3501
  segmentAvailability.end++;
3391
3502
  }
3392
3503
 
3504
+ /**
3505
+ * @param {!shaka.test.FakeNetworkingEngine} netEngine A NetworkingEngine
3506
+ * look-alike.
3507
+ * @param {string} targetUri
3508
+ * @param {shaka.util.Error.Code=} errorCode
3509
+ */
3510
+ function failRequestsForTarget(
3511
+ netEngine, targetUri, errorCode=shaka.util.Error.Code.BAD_HTTP_STATUS) {
3512
+ // eslint-disable-next-line no-restricted-syntax
3513
+ const originalNetEngineRequest = netEngine.request.bind(netEngine);
3514
+
3515
+ netEngine.request = jasmine.createSpy('request').and.callFake(
3516
+ (requestType, request) => {
3517
+ if (request.uris[0] == targetUri) {
3518
+ const data = [targetUri];
3519
+
3520
+ if (errorCode == shaka.util.Error.Code.BAD_HTTP_STATUS) {
3521
+ data.push(404);
3522
+ data.push('');
3523
+ }
3524
+
3525
+ // The compiler still sees the error code parameter as potentially
3526
+ // undefined, even though we gave it a default value.
3527
+ goog.asserts.assert(errorCode != undefined, 'Undefined error code');
3528
+
3529
+ return shaka.util.AbortableOperation.failed(new shaka.util.Error(
3530
+ shaka.util.Error.Severity.CRITICAL,
3531
+ shaka.util.Error.Category.NETWORK,
3532
+ errorCode, data));
3533
+ }
3534
+ return originalNetEngineRequest(requestType, request);
3535
+ });
3536
+ }
3537
+
3393
3538
  /**
3394
3539
  * @param {!shaka.test.FakeNetworkingEngine} netEngine A NetworkingEngine
3395
3540
  * look-alike.
@@ -1063,9 +1063,9 @@ describe('Player', () => {
1063
1063
  it('add external chapters in vtt format', async () => {
1064
1064
  await player.load('test:sintel_no_text_compiled');
1065
1065
  const locationUri = new goog.Uri(location.href);
1066
- const partialUri = new goog.Uri('/base/test/test/assets/chapters.vtt');
1067
- const absoluteUri = locationUri.resolve(partialUri);
1068
- await player.addChaptersTrack(absoluteUri.toString(), 'en');
1066
+ const partialUri1 = new goog.Uri('/base/test/test/assets/chapters.vtt');
1067
+ const absoluteUri1 = locationUri.resolve(partialUri1);
1068
+ await player.addChaptersTrack(absoluteUri1.toString(), 'en');
1069
1069
 
1070
1070
  await shaka.test.Util.delay(1.5);
1071
1071
 
@@ -1078,11 +1078,44 @@ describe('Player', () => {
1078
1078
  const chapter2 = chapters[1];
1079
1079
  expect(chapter2.title).toBe('Chapter 2');
1080
1080
  expect(chapter2.startTime).toBe(5);
1081
- expect(chapter2.endTime).toBe(30);
1081
+ expect(chapter2.endTime).toBe(10);
1082
1082
  const chapter3 = chapters[2];
1083
1083
  expect(chapter3.title).toBe('Chapter 3');
1084
- expect(chapter3.startTime).toBe(30);
1085
- expect(chapter3.endTime).toBe(61.349);
1084
+ expect(chapter3.startTime).toBe(10);
1085
+ expect(chapter3.endTime).toBe(20);
1086
+
1087
+ const partialUri2 = new goog.Uri('/base/test/test/assets/chapters2.vtt');
1088
+ const absoluteUri2 = locationUri.resolve(partialUri2);
1089
+ await player.addChaptersTrack(absoluteUri2.toString(), 'en');
1090
+
1091
+ await shaka.test.Util.delay(1.5);
1092
+
1093
+ const chaptersUpdated = player.getChapters('en');
1094
+ expect(chaptersUpdated.length).toBe(6);
1095
+ const chapterUpdated1 = chaptersUpdated[0];
1096
+ expect(chapterUpdated1.title).toBe('Chapter 1');
1097
+ expect(chapterUpdated1.startTime).toBe(0);
1098
+ expect(chapterUpdated1.endTime).toBe(5);
1099
+ const chapterUpdated2 = chaptersUpdated[1];
1100
+ expect(chapterUpdated2.title).toBe('Chapter 2');
1101
+ expect(chapterUpdated2.startTime).toBe(5);
1102
+ expect(chapterUpdated2.endTime).toBe(10);
1103
+ const chapterUpdated3 = chaptersUpdated[2];
1104
+ expect(chapterUpdated3.title).toBe('Chapter 3');
1105
+ expect(chapterUpdated3.startTime).toBe(10);
1106
+ expect(chapterUpdated3.endTime).toBe(20);
1107
+ const chapterUpdated4 = chaptersUpdated[3];
1108
+ expect(chapterUpdated4.title).toBe('Chapter 4');
1109
+ expect(chapterUpdated4.startTime).toBe(20);
1110
+ expect(chapterUpdated4.endTime).toBe(30);
1111
+ const chapterUpdated5 = chaptersUpdated[4];
1112
+ expect(chapterUpdated5.title).toBe('Chapter 5');
1113
+ expect(chapterUpdated5.startTime).toBe(30);
1114
+ expect(chapterUpdated5.endTime).toBe(40);
1115
+ const chapterUpdated6 = chaptersUpdated[5];
1116
+ expect(chapterUpdated6.title).toBe('Chapter 6');
1117
+ expect(chapterUpdated6.startTime).toBe(40);
1118
+ expect(chapterUpdated6.endTime).toBe(61.349);
1086
1119
  });
1087
1120
 
1088
1121
  it('add external chapters in srt format', async () => {
@@ -1090,11 +1123,11 @@ describe('Player', () => {
1090
1123
  const locationUri = new goog.Uri(location.href);
1091
1124
  const partialUri = new goog.Uri('/base/test/test/assets/chapters.srt');
1092
1125
  const absoluteUri = locationUri.resolve(partialUri);
1093
- await player.addChaptersTrack(absoluteUri.toString(), 'en');
1126
+ await player.addChaptersTrack(absoluteUri.toString(), 'es');
1094
1127
 
1095
1128
  await shaka.test.Util.delay(1.5);
1096
1129
 
1097
- const chapters = player.getChapters('en');
1130
+ const chapters = player.getChapters('es');
1098
1131
  expect(chapters.length).toBe(3);
1099
1132
  const chapter1 = chapters[0];
1100
1133
  expect(chapter1.title).toBe('Chapter 1');
@@ -330,9 +330,9 @@ describe('Player Src Equals', () => {
330
330
  await loadWithSrcEquals(SMALL_MP4_CONTENT_URI, /* startTime= */ null);
331
331
 
332
332
  const locationUri = new goog.Uri(location.href);
333
- const partialUri = new goog.Uri('/base/test/test/assets/chapters.vtt');
334
- const absoluteUri = locationUri.resolve(partialUri);
335
- await player.addChaptersTrack(absoluteUri.toString(), 'en');
333
+ const partialUri1 = new goog.Uri('/base/test/test/assets/chapters.vtt');
334
+ const absoluteUri1 = locationUri.resolve(partialUri1);
335
+ await player.addChaptersTrack(absoluteUri1.toString(), 'en');
336
336
 
337
337
  await shaka.test.Util.delay(1.5);
338
338
 
@@ -345,11 +345,44 @@ describe('Player Src Equals', () => {
345
345
  const chapter2 = chapters[1];
346
346
  expect(chapter2.title).toBe('Chapter 2');
347
347
  expect(chapter2.startTime).toBe(5);
348
- expect(chapter2.endTime).toBe(30);
348
+ expect(chapter2.endTime).toBe(10);
349
349
  const chapter3 = chapters[2];
350
350
  expect(chapter3.title).toBe('Chapter 3');
351
- expect(chapter3.startTime).toBe(30);
352
- expect(chapter3.endTime).toBe(61.349);
351
+ expect(chapter3.startTime).toBe(10);
352
+ expect(chapter3.endTime).toBe(20);
353
+
354
+ const partialUri2 = new goog.Uri('/base/test/test/assets/chapters2.vtt');
355
+ const absoluteUri2 = locationUri.resolve(partialUri2);
356
+ await player.addChaptersTrack(absoluteUri2.toString(), 'en');
357
+
358
+ await shaka.test.Util.delay(1.5);
359
+
360
+ const chaptersUpdated = player.getChapters('en');
361
+ expect(chaptersUpdated.length).toBe(6);
362
+ const chapterUpdated1 = chaptersUpdated[0];
363
+ expect(chapterUpdated1.title).toBe('Chapter 1');
364
+ expect(chapterUpdated1.startTime).toBe(0);
365
+ expect(chapterUpdated1.endTime).toBe(5);
366
+ const chapterUpdated2 = chaptersUpdated[1];
367
+ expect(chapterUpdated2.title).toBe('Chapter 2');
368
+ expect(chapterUpdated2.startTime).toBe(5);
369
+ expect(chapterUpdated2.endTime).toBe(10);
370
+ const chapterUpdated3 = chaptersUpdated[2];
371
+ expect(chapterUpdated3.title).toBe('Chapter 3');
372
+ expect(chapterUpdated3.startTime).toBe(10);
373
+ expect(chapterUpdated3.endTime).toBe(20);
374
+ const chapterUpdated4 = chaptersUpdated[3];
375
+ expect(chapterUpdated4.title).toBe('Chapter 4');
376
+ expect(chapterUpdated4.startTime).toBe(20);
377
+ expect(chapterUpdated4.endTime).toBe(30);
378
+ const chapterUpdated5 = chaptersUpdated[4];
379
+ expect(chapterUpdated5.title).toBe('Chapter 5');
380
+ expect(chapterUpdated5.startTime).toBe(30);
381
+ expect(chapterUpdated5.endTime).toBe(40);
382
+ const chapterUpdated6 = chaptersUpdated[5];
383
+ expect(chapterUpdated6.title).toBe('Chapter 6');
384
+ expect(chapterUpdated6.startTime).toBe(40);
385
+ expect(chapterUpdated6.endTime).toBe(61.349);
353
386
  });
354
387
 
355
388
  it('add external chapters in srt format', async () => {
@@ -358,11 +391,11 @@ describe('Player Src Equals', () => {
358
391
  const locationUri = new goog.Uri(location.href);
359
392
  const partialUri = new goog.Uri('/base/test/test/assets/chapters.srt');
360
393
  const absoluteUri = locationUri.resolve(partialUri);
361
- await player.addChaptersTrack(absoluteUri.toString(), 'en');
394
+ await player.addChaptersTrack(absoluteUri.toString(), 'es');
362
395
 
363
396
  await shaka.test.Util.delay(1.5);
364
397
 
365
- const chapters = player.getChapters('en');
398
+ const chapters = player.getChapters('es');
366
399
  expect(chapters.length).toBe(3);
367
400
  const chapter1 = chapters[0];
368
401
  expect(chapter1.title).toBe('Chapter 1');
@@ -36,7 +36,7 @@ describe('Player', () => {
36
36
  const originalLogWarn = shaka.log.warning;
37
37
  const originalLogAlwaysWarn = shaka.log.alwaysWarn;
38
38
  const originalIsTypeSupported = window.MediaSource.isTypeSupported;
39
- const originalDecodingInfo = window.shakaMediaCapabilities.decodingInfo;
39
+ const originalDecodingInfo = navigator.mediaCapabilities.decodingInfo;
40
40
 
41
41
  const fakeManifestUri = 'fake-manifest-uri';
42
42
  const fakeMimeType = 'application/test';
@@ -93,7 +93,7 @@ describe('Player', () => {
93
93
  // Since this is not an integration test, we don't want MediaCapabilities to
94
94
  // fail assertions based on browser support for types. Pretend that all
95
95
  // video and audio types are supported.
96
- window.shakaMediaCapabilities.decodingInfo = async (config) => {
96
+ navigator.mediaCapabilities.decodingInfo = async (config) => {
97
97
  await Promise.resolve();
98
98
  const videoType = config['video'] ?
99
99
  config['video'].contentType.split('/')[0] : null;
@@ -177,7 +177,7 @@ describe('Player', () => {
177
177
  shaka.log.alwaysWarn = originalLogAlwaysWarn;
178
178
  window.MediaSource.isTypeSupported = originalIsTypeSupported;
179
179
  shaka.media.ManifestParser.unregisterParserByMime(fakeMimeType);
180
- window.shakaMediaCapabilities.decodingInfo = originalDecodingInfo;
180
+ navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
181
181
  }
182
182
  });
183
183
 
@@ -1092,8 +1092,8 @@ describe('Player', () => {
1092
1092
  // Image tracks
1093
1093
  manifest.addImageStream(53, (stream) => {
1094
1094
  stream.originalId = 'thumbnail';
1095
- stream.width = 100;
1096
- stream.height = 200;
1095
+ stream.width = 200;
1096
+ stream.height = 400;
1097
1097
  stream.bandwidth = 10;
1098
1098
  stream.mimeType = 'image/jpeg';
1099
1099
  stream.tilesLayout = '1x1';
@@ -1503,8 +1503,8 @@ describe('Player', () => {
1503
1503
  audioBandwidth: null,
1504
1504
  videoBandwidth: null,
1505
1505
  bandwidth: 10,
1506
- width: 100,
1507
- height: 200,
1506
+ width: 200,
1507
+ height: 400,
1508
1508
  frameRate: null,
1509
1509
  pixelAspectRatio: null,
1510
1510
  hdr: null,
@@ -2463,7 +2463,7 @@ describe('Player', () => {
2463
2463
  it('throws CONTENT_UNSUPPORTED_BY_BROWSER', async () => {
2464
2464
  window.MediaSource.isTypeSupported = (mimeType) => false;
2465
2465
 
2466
- window.shakaMediaCapabilities.decodingInfo = async (config) => {
2466
+ navigator.mediaCapabilities.decodingInfo = async (config) => {
2467
2467
  await Promise.resolve();
2468
2468
  return {supported: false};
2469
2469
  };
@@ -2827,7 +2827,7 @@ describe('Player', () => {
2827
2827
  });
2828
2828
  });
2829
2829
 
2830
- window.shakaMediaCapabilities.decodingInfo = async (config) => {
2830
+ navigator.mediaCapabilities.decodingInfo = async (config) => {
2831
2831
  await Promise.resolve();
2832
2832
  const videoType = config['video'] ? config['video'].contentType : '';
2833
2833
  if (videoType.includes('video') &&
@@ -3537,29 +3537,39 @@ describe('Player', () => {
3537
3537
 
3538
3538
  await player.load(fakeManifestUri, 0, fakeMimeType);
3539
3539
 
3540
+ expect(player.getImageTracks()[0].width).toBe(100);
3541
+ expect(player.getImageTracks()[0].height).toBe(50);
3540
3542
  const thumbnail0 = await player.getThumbnails(5, 0);
3541
3543
  const thumbnail1 = await player.getThumbnails(5, 11);
3542
3544
  const thumbnail2 = await player.getThumbnails(5, 21);
3543
3545
  const thumbnail5 = await player.getThumbnails(5, 51);
3544
3546
  expect(thumbnail0).toEqual(jasmine.objectContaining({
3547
+ imageHeight: 150,
3548
+ imageWidth: 200,
3545
3549
  positionX: 0,
3546
3550
  positionY: 0,
3547
3551
  width: 100,
3548
3552
  height: 50,
3549
3553
  }));
3550
3554
  expect(thumbnail1).toEqual(jasmine.objectContaining({
3555
+ imageHeight: 150,
3556
+ imageWidth: 200,
3551
3557
  positionX: 100,
3552
3558
  positionY: 0,
3553
3559
  width: 100,
3554
3560
  height: 50,
3555
3561
  }));
3556
3562
  expect(thumbnail2).toEqual(jasmine.objectContaining({
3563
+ imageHeight: 150,
3564
+ imageWidth: 200,
3557
3565
  positionX: 0,
3558
3566
  positionY: 50,
3559
3567
  width: 100,
3560
3568
  height: 50,
3561
3569
  }));
3562
3570
  expect(thumbnail5).toEqual(jasmine.objectContaining({
3571
+ imageHeight: 150,
3572
+ imageWidth: 200,
3563
3573
  positionX: 100,
3564
3574
  positionY: 100,
3565
3575
  width: 100,
@@ -3,8 +3,8 @@ WEBVTT
3
3
  00:00.000 --> 00:05.000
4
4
  Chapter 1
5
5
 
6
- 00:05.000 --> 00:30.000
6
+ 00:05.000 --> 00:10.000
7
7
  Chapter 2
8
8
 
9
- 00:30.000 --> 01:01.349
9
+ 00:10.000 --> 00:20.000
10
10
  Chapter 3
@@ -0,0 +1,10 @@
1
+ WEBVTT
2
+
3
+ 00:20.000 --> 00:30.000
4
+ Chapter 4
5
+
6
+ 00:30.000 --> 00:40.000
7
+ Chapter 5
8
+
9
+ 00:40.000 --> 01:01.349
10
+ Chapter 6
@@ -0,0 +1,81 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.test.TtmlUtils');
8
+
9
+ shaka.test.TtmlUtils = class {
10
+ /**
11
+ * @param {!Array} expectedCues
12
+ * @param {!Array} actualCues
13
+ * @param {!Object} bodyProperties
14
+ * @param {Object=} divProperties
15
+ */
16
+ static verifyHelper(expectedCues, actualCues, bodyProperties, divProperties) {
17
+ const mapExpected = (cue) => {
18
+ if (cue.region) {
19
+ cue.region = jasmine.objectContaining(cue.region);
20
+ }
21
+
22
+ if (cue.nestedCues && (cue.nestedCues instanceof Array)) {
23
+ cue.nestedCues = cue.nestedCues.map(mapExpected);
24
+ }
25
+
26
+ if (cue.isContainer == undefined) {
27
+ // If not specified to be true, check for isContainer to be false.
28
+ cue.isContainer = false;
29
+ }
30
+
31
+ return jasmine.objectContaining(cue);
32
+ };
33
+
34
+ /**
35
+ * @param {!Object} properties
36
+ * @return {!shaka.extern.Cue}
37
+ */
38
+ const makeContainer = (properties) => {
39
+ const region = {
40
+ id: '',
41
+ viewportAnchorX: 0,
42
+ viewportAnchorY: 0,
43
+ regionAnchorX: 0,
44
+ regionAnchorY: 0,
45
+ width: 100,
46
+ height: 100,
47
+ widthUnits: shaka.text.CueRegion.units.PERCENTAGE,
48
+ heightUnits: shaka.text.CueRegion.units.PERCENTAGE,
49
+ viewportAnchorUnits: shaka.text.CueRegion.units.PERCENTAGE,
50
+ scroll: '',
51
+ };
52
+ const containerCue = /** @type {!shaka.extern.Cue} */ ({
53
+ region,
54
+ nestedCues: jasmine.any(Object),
55
+ payload: '',
56
+ startTime: 0,
57
+ endTime: Infinity,
58
+ isContainer: true,
59
+ });
60
+ Object.assign(containerCue, properties);
61
+ return mapExpected(containerCue);
62
+ };
63
+
64
+ if (expectedCues.length == 0 && !divProperties) {
65
+ expect(actualCues.length).toBe(0);
66
+ } else {
67
+ // Body.
68
+ expect(actualCues.length).toBe(1);
69
+ const body = actualCues[0];
70
+ expect(body).toEqual(makeContainer(bodyProperties));
71
+
72
+ // Div.
73
+ expect(body.nestedCues.length).toBe(1);
74
+ const div = body.nestedCues[0];
75
+ expect(div).toEqual(makeContainer(divProperties || bodyProperties));
76
+
77
+ // Cues.
78
+ expect(div.nestedCues).toEqual(expectedCues.map(mapExpected));
79
+ }
80
+ }
81
+ };
@@ -4,6 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
+ goog.require('shaka.test.TtmlUtils');
7
8
  goog.require('shaka.test.Util');
8
9
  goog.require('shaka.text.Mp4TtmlParser');
9
10
  goog.require('shaka.util.BufferUtils');
@@ -48,7 +49,14 @@ describe('Mp4TtmlParser', () => {
48
49
  parser.parseInit(ttmlInitSegment);
49
50
  const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
50
51
  const ret = parser.parseMedia(ttmlSegmentMultipleMDAT, time);
51
- expect(ret.length).toBe(20);
52
+ // Bodies.
53
+ expect(ret.length).toBe(2);
54
+ // Divs.
55
+ expect(ret[0].nestedCues.length).toBe(1);
56
+ expect(ret[1].nestedCues.length).toBe(1);
57
+ // Cues.
58
+ expect(ret[0].nestedCues[0].nestedCues.length).toBe(10);
59
+ expect(ret[1].nestedCues[0].nestedCues.length).toBe(10);
52
60
  });
53
61
 
54
62
  it('accounts for offset', () => {
@@ -159,22 +167,7 @@ describe('Mp4TtmlParser', () => {
159
167
  parser.parseInit(ttmlInitSegment);
160
168
  const time = {periodStart: 0, segmentStart: 0, segmentEnd: 0};
161
169
  const result = parser.parseMedia(ttmlSegment, time);
162
- verifyHelper(cues, result);
170
+ shaka.test.TtmlUtils.verifyHelper(
171
+ cues, result, {startTime: 23, endTime: 53.5});
163
172
  });
164
-
165
- function verifyHelper(/** !Array */ expected, /** !Array */ actual) {
166
- const mapExpected = (cue) => {
167
- if (cue.region) {
168
- cue.region = jasmine.objectContaining(cue.region);
169
- }
170
-
171
- if (cue.nestedCues) {
172
- cue.nestedCues = cue.nestedCues.map(mapExpected);
173
- }
174
-
175
- return jasmine.objectContaining(cue);
176
- };
177
-
178
- expect(actual).toEqual(expected.map(mapExpected));
179
- }
180
173
  });