shaka-player 3.1.4 → 3.1.5
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 +39 -0
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/locales.js +29 -29
- package/dist/shaka-player.compiled.d.ts +14 -0
- package/dist/shaka-player.compiled.debug.d.ts +14 -0
- package/dist/shaka-player.compiled.debug.externs.js +11 -0
- package/dist/shaka-player.compiled.debug.js +170 -168
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +11 -0
- package/dist/shaka-player.compiled.js +650 -650
- package/dist/shaka-player.compiled.map +2 -2
- package/dist/shaka-player.ui.d.ts +14 -0
- package/dist/shaka-player.ui.debug.d.ts +14 -0
- package/dist/shaka-player.ui.debug.externs.js +11 -0
- package/dist/shaka-player.ui.debug.js +178 -176
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +11 -0
- package/dist/shaka-player.ui.js +792 -792
- package/dist/shaka-player.ui.map +2 -2
- package/externs/shaka/text.js +10 -0
- package/lib/dash/dash_parser.js +4 -2
- package/lib/media/streaming_engine.js +5 -2
- package/lib/player.js +1 -1
- 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/stream_utils.js +58 -7
- package/lib/util/xml_utils.js +19 -0
- package/package.json +2 -2
- package/test/dash/dash_parser_manifest_unit.js +33 -1
- 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_unit.js +5 -5
- 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 +495 -228
- package/test/util/stream_utils_unit.js +35 -29
- package/ui/less/buttons.less +0 -4
- package/ui/text_selection.js +1 -0
- package/externs/media_capabilities.js +0 -16
|
@@ -1830,7 +1830,7 @@ describe('DashParser Manifest', () => {
|
|
|
1830
1830
|
expect(textStream.kind).toBe('caption');
|
|
1831
1831
|
});
|
|
1832
1832
|
|
|
1833
|
-
it('converts Roles element to "forced"', async () => {
|
|
1833
|
+
it('converts Roles element to "forced" (old role)', async () => {
|
|
1834
1834
|
const manifestText = [
|
|
1835
1835
|
'<MPD minBufferTime="PT75S">',
|
|
1836
1836
|
' <Period id="1" duration="PT30S">',
|
|
@@ -1862,6 +1862,38 @@ describe('DashParser Manifest', () => {
|
|
|
1862
1862
|
expect(textStream.forced).toBe(true);
|
|
1863
1863
|
});
|
|
1864
1864
|
|
|
1865
|
+
it('converts Roles element to "forced"', async () => {
|
|
1866
|
+
const manifestText = [
|
|
1867
|
+
'<MPD minBufferTime="PT75S">',
|
|
1868
|
+
' <Period id="1" duration="PT30S">',
|
|
1869
|
+
' <AdaptationSet id="1" contentType="text">',
|
|
1870
|
+
' <Accessibility schemeIdUri="urn:mpeg:dash:role:2011" ',
|
|
1871
|
+
' value="captions" />',
|
|
1872
|
+
' <Accessibility schemeIdUri="urn:mpeg:dash:role:2011" ',
|
|
1873
|
+
' value="forced-subtitle" />',
|
|
1874
|
+
' <Accessibility schemeIdUri="foobar" value="bar" />',
|
|
1875
|
+
' <Representation id="text-en" mimeType="text/webvtt">',
|
|
1876
|
+
' <BaseURL>t-en.vtt</BaseURL>',
|
|
1877
|
+
' </Representation>',
|
|
1878
|
+
' </AdaptationSet>',
|
|
1879
|
+
' <AdaptationSet id="1" mimeType="video/mp4">',
|
|
1880
|
+
' <Representation id="video-sd" width="640" height="480">',
|
|
1881
|
+
' <BaseURL>v-sd.mp4</BaseURL>',
|
|
1882
|
+
' <SegmentBase indexRange="100-200" />',
|
|
1883
|
+
' </Representation>',
|
|
1884
|
+
' </AdaptationSet>',
|
|
1885
|
+
' </Period>',
|
|
1886
|
+
'</MPD>',
|
|
1887
|
+
].join('\n');
|
|
1888
|
+
|
|
1889
|
+
fakeNetEngine.setResponseText('dummy://foo', manifestText);
|
|
1890
|
+
/** @type {shaka.extern.Manifest} */
|
|
1891
|
+
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
1892
|
+
const textStream = manifest.textStreams[0];
|
|
1893
|
+
expect(textStream.roles).toEqual(['captions', 'forced-subtitle']);
|
|
1894
|
+
expect(textStream.forced).toBe(true);
|
|
1895
|
+
});
|
|
1896
|
+
|
|
1865
1897
|
it('supports HDR signaling via profiles', async () => {
|
|
1866
1898
|
// (DASH-IF IOP v4.3 10.3.3.)
|
|
1867
1899
|
const hdrProfile =
|
|
@@ -37,7 +37,7 @@ function testDrmEngine(useMediaCapabilities) {
|
|
|
37
37
|
navigator.requestMediaKeySystemAccess;
|
|
38
38
|
const originalLogError = shaka.log.error;
|
|
39
39
|
const originalBatchTime = shaka.media.DrmEngine.KEY_STATUS_BATCH_TIME;
|
|
40
|
-
const originalDecodingInfo =
|
|
40
|
+
const originalDecodingInfo = navigator.mediaCapabilities.decodingInfo;
|
|
41
41
|
|
|
42
42
|
/** @type {!jasmine.Spy} */
|
|
43
43
|
let requestMediaKeySystemAccessSpy;
|
|
@@ -88,7 +88,7 @@ function testDrmEngine(useMediaCapabilities) {
|
|
|
88
88
|
navigator.requestMediaKeySystemAccess =
|
|
89
89
|
shaka.test.Util.spyFunc(requestMediaKeySystemAccessSpy);
|
|
90
90
|
decodingInfoSpy = jasmine.createSpy('decodingInfo');
|
|
91
|
-
|
|
91
|
+
navigator.mediaCapabilities.decodingInfo =
|
|
92
92
|
shaka.test.Util.spyFunc(decodingInfoSpy);
|
|
93
93
|
|
|
94
94
|
logErrorSpy = jasmine.createSpy('shaka.log.error');
|
|
@@ -165,7 +165,7 @@ function testDrmEngine(useMediaCapabilities) {
|
|
|
165
165
|
|
|
166
166
|
navigator.requestMediaKeySystemAccess =
|
|
167
167
|
originalRequestMediaKeySystemAccess;
|
|
168
|
-
|
|
168
|
+
navigator.mediaCapabilities.decodingInfo = originalDecodingInfo;
|
|
169
169
|
shaka.log.error = originalLogError;
|
|
170
170
|
});
|
|
171
171
|
|
|
@@ -419,8 +419,9 @@ describe('StreamingEngine', () => {
|
|
|
419
419
|
// 3. Playhead seeks to force us back inside the window
|
|
420
420
|
// 4. (maybe) seek if there is a gap at the period boundary
|
|
421
421
|
// 5. (maybe) seek to flush a pipeline stall
|
|
422
|
+
// 6. (maybe) on slower platforms (e.g. GitHub actions)
|
|
422
423
|
expect(seekCount).toBeGreaterThan(2);
|
|
423
|
-
expect(seekCount).toBeLessThan(
|
|
424
|
+
expect(seekCount).toBeLessThan(7);
|
|
424
425
|
});
|
|
425
426
|
});
|
|
426
427
|
|
|
@@ -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
|
});
|
|
@@ -822,6 +826,53 @@ describe('StreamingEngine', () => {
|
|
|
822
826
|
.toHaveBeenCalledWith('video', 0, lt20, gt40);
|
|
823
827
|
});
|
|
824
828
|
|
|
829
|
+
// Regression test for https://github.com/google/shaka-player/issues/3717
|
|
830
|
+
it('applies fudge factors for the duration', async () => {
|
|
831
|
+
setupVod();
|
|
832
|
+
|
|
833
|
+
// In #3717, the duration was just barely large enough to encompass an
|
|
834
|
+
// additional segment, but that segment didn't exist, so playback never
|
|
835
|
+
// completed. Here, we set the duration to just beyond the 3rd segment, and
|
|
836
|
+
// we make the 4th segment fail when requested.
|
|
837
|
+
const duration = 30.000000005;
|
|
838
|
+
timeline.getDuration.and.returnValue(duration);
|
|
839
|
+
|
|
840
|
+
const targetUri = '1_video_3'; // The URI of the 4th video segment.
|
|
841
|
+
failRequestsForTarget(netEngine, targetUri);
|
|
842
|
+
|
|
843
|
+
mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
|
|
844
|
+
createStreamingEngine();
|
|
845
|
+
|
|
846
|
+
// Here we go!
|
|
847
|
+
streamingEngine.switchVariant(variant);
|
|
848
|
+
streamingEngine.switchTextStream(textStream);
|
|
849
|
+
await streamingEngine.start();
|
|
850
|
+
playing = true;
|
|
851
|
+
await runTest();
|
|
852
|
+
|
|
853
|
+
// The end of the stream should have been reached, and the 4th segment from
|
|
854
|
+
// each type should never have been requested.
|
|
855
|
+
expect(mediaSourceEngine.endOfStream).toHaveBeenCalled();
|
|
856
|
+
|
|
857
|
+
const segmentType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
|
|
858
|
+
|
|
859
|
+
netEngine.expectRequest('0_audio_0', segmentType);
|
|
860
|
+
netEngine.expectRequest('0_video_0', segmentType);
|
|
861
|
+
netEngine.expectRequest('0_text_0', segmentType);
|
|
862
|
+
|
|
863
|
+
netEngine.expectRequest('0_audio_1', segmentType);
|
|
864
|
+
netEngine.expectRequest('0_video_1', segmentType);
|
|
865
|
+
netEngine.expectRequest('0_text_1', segmentType);
|
|
866
|
+
|
|
867
|
+
netEngine.expectRequest('1_audio_2', segmentType);
|
|
868
|
+
netEngine.expectRequest('1_video_2', segmentType);
|
|
869
|
+
netEngine.expectRequest('1_text_2', segmentType);
|
|
870
|
+
|
|
871
|
+
netEngine.expectNoRequest('1_audio_3', segmentType);
|
|
872
|
+
netEngine.expectNoRequest('1_video_3', segmentType);
|
|
873
|
+
netEngine.expectNoRequest('1_text_3', segmentType);
|
|
874
|
+
});
|
|
875
|
+
|
|
825
876
|
it('does not buffer one media type ahead of another', async () => {
|
|
826
877
|
setupVod();
|
|
827
878
|
mediaSourceEngine = new shaka.test.FakeMediaSourceEngine(segmentData);
|
|
@@ -1389,6 +1440,66 @@ describe('StreamingEngine', () => {
|
|
|
1389
1440
|
});
|
|
1390
1441
|
});
|
|
1391
1442
|
|
|
1443
|
+
it('into unbuffered regions when nothing is buffered ' +
|
|
1444
|
+
'and mediaState is performing an update', async () => {
|
|
1445
|
+
// Here we go!
|
|
1446
|
+
streamingEngine.switchVariant(variant);
|
|
1447
|
+
streamingEngine.switchTextStream(textStream);
|
|
1448
|
+
// ensure init source buffer promise does not resolve before seeked()
|
|
1449
|
+
// so mediaState remains in "performingUpdate" state
|
|
1450
|
+
const initSourceBufferPromise = new shaka.util.PublicPromise();
|
|
1451
|
+
mediaSourceEngine.setStreamProperties.and
|
|
1452
|
+
.returnValue(initSourceBufferPromise);
|
|
1453
|
+
await streamingEngine.start();
|
|
1454
|
+
playing = true;
|
|
1455
|
+
|
|
1456
|
+
// tick to trigger mediaState updates
|
|
1457
|
+
jasmine.clock().tick(1);
|
|
1458
|
+
// give a chance for fetchAndAppend_ to be invoked
|
|
1459
|
+
// by async onUpdate_ callback
|
|
1460
|
+
await Util.shortDelay(realSetTimeout);
|
|
1461
|
+
|
|
1462
|
+
// Nothing is buffered yet.
|
|
1463
|
+
expect(mediaSourceEngine.segments).toEqual({
|
|
1464
|
+
audio: [false, false, false, false],
|
|
1465
|
+
video: [false, false, false, false],
|
|
1466
|
+
text: [false, false, false, false],
|
|
1467
|
+
});
|
|
1468
|
+
|
|
1469
|
+
// Seek forward to an unbuffered region in the first Period.
|
|
1470
|
+
presentationTimeInSeconds = 15;
|
|
1471
|
+
streamingEngine.seeked();
|
|
1472
|
+
|
|
1473
|
+
// resolve initSourceBufferPromise after seeked(), waitingToClearBuffer
|
|
1474
|
+
// should have been set, so this will now trigger the actual flush of
|
|
1475
|
+
// the buffer
|
|
1476
|
+
initSourceBufferPromise.resolve();
|
|
1477
|
+
mediaSourceEngine.setStreamProperties.and
|
|
1478
|
+
.returnValue(Promise.resolve());
|
|
1479
|
+
|
|
1480
|
+
// allow mediaState update to resolve
|
|
1481
|
+
await Util.shortDelay(realSetTimeout);
|
|
1482
|
+
|
|
1483
|
+
onTick.and.callFake(() => {
|
|
1484
|
+
expect(mediaSourceEngine.clear).toHaveBeenCalled();
|
|
1485
|
+
onTick.and.stub();
|
|
1486
|
+
});
|
|
1487
|
+
|
|
1488
|
+
await runTest(Util.spyFunc(onTick));
|
|
1489
|
+
|
|
1490
|
+
// Verify buffers.
|
|
1491
|
+
expect(mediaSourceEngine.initSegments).toEqual({
|
|
1492
|
+
audio: [false, true],
|
|
1493
|
+
video: [false, true],
|
|
1494
|
+
text: [],
|
|
1495
|
+
});
|
|
1496
|
+
expect(mediaSourceEngine.segments).toEqual({
|
|
1497
|
+
audio: [false, true, true, true],
|
|
1498
|
+
video: [false, true, true, true],
|
|
1499
|
+
text: [false, true, true, true],
|
|
1500
|
+
});
|
|
1501
|
+
});
|
|
1502
|
+
|
|
1392
1503
|
it('into unbuffered regions near segment start', async () => {
|
|
1393
1504
|
// Here we go!
|
|
1394
1505
|
streamingEngine.switchVariant(variant);
|
|
@@ -3388,6 +3499,40 @@ describe('StreamingEngine', () => {
|
|
|
3388
3499
|
segmentAvailability.end++;
|
|
3389
3500
|
}
|
|
3390
3501
|
|
|
3502
|
+
/**
|
|
3503
|
+
* @param {!shaka.test.FakeNetworkingEngine} netEngine A NetworkingEngine
|
|
3504
|
+
* look-alike.
|
|
3505
|
+
* @param {string} targetUri
|
|
3506
|
+
* @param {shaka.util.Error.Code=} errorCode
|
|
3507
|
+
*/
|
|
3508
|
+
function failRequestsForTarget(
|
|
3509
|
+
netEngine, targetUri, errorCode=shaka.util.Error.Code.BAD_HTTP_STATUS) {
|
|
3510
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
3511
|
+
const originalNetEngineRequest = netEngine.request.bind(netEngine);
|
|
3512
|
+
|
|
3513
|
+
netEngine.request = jasmine.createSpy('request').and.callFake(
|
|
3514
|
+
(requestType, request) => {
|
|
3515
|
+
if (request.uris[0] == targetUri) {
|
|
3516
|
+
const data = [targetUri];
|
|
3517
|
+
|
|
3518
|
+
if (errorCode == shaka.util.Error.Code.BAD_HTTP_STATUS) {
|
|
3519
|
+
data.push(404);
|
|
3520
|
+
data.push('');
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
// The compiler still sees the error code parameter as potentially
|
|
3524
|
+
// undefined, even though we gave it a default value.
|
|
3525
|
+
goog.asserts.assert(errorCode != undefined, 'Undefined error code');
|
|
3526
|
+
|
|
3527
|
+
return shaka.util.AbortableOperation.failed(new shaka.util.Error(
|
|
3528
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
3529
|
+
shaka.util.Error.Category.NETWORK,
|
|
3530
|
+
errorCode, data));
|
|
3531
|
+
}
|
|
3532
|
+
return originalNetEngineRequest(requestType, request);
|
|
3533
|
+
});
|
|
3534
|
+
}
|
|
3535
|
+
|
|
3391
3536
|
/**
|
|
3392
3537
|
* @param {!shaka.test.FakeNetworkingEngine} netEngine A NetworkingEngine
|
|
3393
3538
|
* look-alike.
|
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
|
|
|
@@ -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
|
};
|
|
@@ -2837,7 +2837,7 @@ describe('Player', () => {
|
|
|
2837
2837
|
});
|
|
2838
2838
|
|
|
2839
2839
|
if (useMediaCapabilities) {
|
|
2840
|
-
|
|
2840
|
+
navigator.mediaCapabilities.decodingInfo = async (config) => {
|
|
2841
2841
|
await Promise.resolve();
|
|
2842
2842
|
const videoType = config['video'] ? config['video'].contentType : '';
|
|
2843
2843
|
if (videoType.includes('video') &&
|
|
@@ -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
|
});
|