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.
- package/CHANGELOG.md +54 -0
- package/build/conformance.textproto +183 -169
- package/dist/controls.css +1 -1
- package/dist/deps.js +1 -1
- package/dist/locales.js +30 -30
- package/dist/shaka-player.compiled.d.ts +25 -2
- package/dist/shaka-player.compiled.debug.d.ts +25 -2
- package/dist/shaka-player.compiled.debug.externs.js +22 -1
- package/dist/shaka-player.compiled.debug.js +226 -222
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +22 -1
- package/dist/shaka-player.compiled.js +814 -812
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +25 -2
- package/dist/shaka-player.ui.debug.d.ts +25 -2
- package/dist/shaka-player.ui.debug.externs.js +22 -1
- package/dist/shaka-player.ui.debug.js +244 -240
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +22 -1
- package/dist/shaka-player.ui.js +995 -992
- package/dist/shaka-player.ui.map +4 -4
- package/externs/cmcd.js +186 -0
- package/externs/shaka/player.js +8 -0
- package/externs/shaka/text.js +10 -0
- package/lib/hls/hls_parser.js +30 -0
- package/lib/media/segment_index.js +2 -1
- package/lib/media/segment_reference.js +19 -1
- package/lib/media/streaming_engine.js +5 -2
- package/lib/player.js +23 -17
- package/lib/polyfill/media_capabilities.js +30 -15
- package/lib/text/cue.js +6 -0
- package/lib/text/ttml_text_parser.js +84 -58
- package/lib/text/ui_text_displayer.js +17 -11
- package/lib/util/cmcd_manager.js +47 -201
- package/lib/util/stream_utils.js +86 -10
- package/lib/util/xml_utils.js +19 -0
- package/package.json +2 -2
- package/test/media/drm_engine_unit.js +3 -3
- package/test/media/streaming_engine_integration.js +2 -1
- package/test/media/streaming_engine_unit.js +145 -0
- package/test/player_integration.js +41 -8
- package/test/player_src_equals_integration.js +41 -8
- package/test/player_unit.js +19 -9
- package/test/test/assets/chapters.vtt +2 -2
- package/test/test/assets/chapters2.vtt +10 -0
- package/test/test/util/ttml_utils.js +81 -0
- package/test/text/mp4_ttml_parser_unit.js +11 -18
- package/test/text/ttml_text_parser_unit.js +499 -230
- package/test/util/cmcd_manager_unit.js +29 -15
- package/test/util/stream_utils_unit.js +36 -30
- package/third_party/closure-uri/uri.js +21 -0
- package/ui/text_selection.js +1 -0
- 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
|
|
1067
|
-
const
|
|
1068
|
-
await player.addChaptersTrack(
|
|
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(
|
|
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(
|
|
1085
|
-
expect(chapter3.endTime).toBe(
|
|
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(), '
|
|
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('
|
|
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
|
|
334
|
-
const
|
|
335
|
-
await player.addChaptersTrack(
|
|
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(
|
|
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(
|
|
352
|
-
expect(chapter3.endTime).toBe(
|
|
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(), '
|
|
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('
|
|
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');
|
package/test/player_unit.js
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
1096
|
-
stream.height =
|
|
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:
|
|
1507
|
-
height:
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -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
|
-
|
|
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(
|
|
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
|
});
|