shaka-player 4.3.13 → 4.3.15
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/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/.github/ISSUE_TEMPLATE/question.md +7 -0
- package/.github/workflows/release-please.yaml +2 -27
- package/.github/workflows/shaka-bot-commands/lib.sh +37 -12
- package/.github/workflows/shaka-bot-commands/main.sh +4 -2
- package/.github/workflows/talk-to-shaka-bot.yaml +1 -0
- package/AUTHORS +5 -0
- package/CHANGELOG.md +96 -0
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTORS +6 -0
- package/README.md +2 -0
- package/demo/common/asset.js +0 -1
- package/demo/common/assets.js +0 -1
- package/demo/custom.js +2 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +1 -1
- package/dist/demo.compiled.debug.map +1 -1
- package/dist/demo.compiled.js +1 -1
- package/dist/demo.compiled.map +1 -1
- package/dist/deps.js +6 -6
- package/dist/locales.js +30 -30
- package/dist/receiver.compiled.debug.map +1 -1
- package/dist/receiver.compiled.map +1 -1
- package/dist/shaka-player.compiled.d.ts +25 -5
- package/dist/shaka-player.compiled.debug.d.ts +25 -5
- package/dist/shaka-player.compiled.debug.externs.js +73 -45
- package/dist/shaka-player.compiled.debug.js +426 -406
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +73 -45
- package/dist/shaka-player.compiled.js +912 -903
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +37 -6
- package/dist/shaka-player.ui.debug.d.ts +37 -6
- package/dist/shaka-player.ui.debug.externs.js +74 -45
- package/dist/shaka-player.ui.debug.js +449 -428
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +74 -45
- package/dist/shaka-player.ui.js +1060 -1051
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ad_monetization.md +54 -0
- package/docs/tutorials/fairplay.md +2 -2
- package/docs/tutorials/index.json +1 -0
- package/docs/tutorials/plugins.md +4 -0
- package/docs/tutorials/text-displayer.md +15 -0
- package/docs/tutorials/ui-customization.md +29 -0
- package/docs/tutorials/ui.md +4 -1
- package/externs/lcevc.js +6 -0
- package/externs/shaka/manifest_parser.js +8 -0
- package/externs/shaka/player.js +1 -1
- package/externs/shaka/text.js +3 -1
- package/lib/abr/simple_abr_manager.js +1 -1
- package/lib/ads/client_side_ad.js +9 -0
- package/lib/ads/client_side_ad_manager.js +7 -2
- package/lib/ads/server_side_ad_manager.js +4 -0
- package/lib/cast/cast_proxy.js +18 -0
- package/lib/cea/cea608_memory.js +1 -1
- package/lib/cea/cea_decoder.js +11 -1
- package/lib/dash/dash_parser.js +75 -41
- package/lib/dash/mpd_utils.js +39 -27
- package/lib/deprecate/deprecate.js +1 -1
- package/lib/hls/hls_parser.js +106 -28
- package/lib/hls/hls_utils.js +5 -5
- package/lib/media/content_workarounds.js +30 -0
- package/lib/media/drm_engine.js +16 -12
- package/lib/media/manifest_parser.js +2 -1
- package/lib/media/media_source_engine.js +4 -2
- package/lib/media/play_rate_controller.js +1 -0
- package/lib/media/presentation_timeline.js +11 -0
- package/lib/media/quality_observer.js +1 -1
- package/lib/media/segment_reference.js +5 -2
- package/lib/media/streaming_engine.js +50 -30
- package/lib/media/transmuxer.js +1 -1
- package/lib/media/video_wrapper.js +4 -3
- package/lib/offline/offline_manifest_parser.js +5 -0
- package/lib/offline/session_deleter.js +0 -8
- package/lib/offline/storage.js +4 -1
- package/lib/player.js +80 -19
- package/lib/polyfill/media_capabilities.js +23 -3
- package/lib/polyfill/mediasource.js +5 -36
- package/lib/text/mp4_ttml_parser.js +2 -2
- package/lib/text/simple_text_displayer.js +7 -6
- package/lib/text/srt_text_parser.js +2 -2
- package/lib/text/text_engine.js +3 -2
- package/lib/text/ttml_text_parser.js +33 -5
- package/lib/text/ui_text_displayer.js +81 -15
- package/lib/text/vtt_text_parser.js +17 -3
- package/lib/util/buffer_utils.js +26 -4
- package/lib/util/cmcd_manager.js +10 -0
- package/lib/util/error.js +1 -0
- package/lib/util/fairplay_utils.js +1 -1
- package/lib/util/manifest_parser_utils.js +14 -8
- package/lib/util/object_utils.js +1 -1
- package/lib/util/periods.js +91 -36
- package/lib/util/platform.js +39 -2
- package/lib/util/player_configuration.js +5 -3
- package/lib/util/stream_utils.js +36 -28
- package/lib/util/xml_utils.js +5 -0
- package/package.json +3 -3
- package/test/cea/cea_decoder_unit.js +40 -0
- package/test/dash/dash_parser_live_unit.js +5 -8
- package/test/hls/hls_parser_unit.js +78 -3
- package/test/media/buffering_observer_unit.js +13 -0
- package/test/media/content_workarounds_unit.js +1 -1
- package/test/media/drm_engine_unit.js +30 -3
- package/test/media/media_source_engine_unit.js +1 -1
- package/test/media/transmuxer_integration.js +2 -2
- package/test/offline/storage_integration.js +3 -0
- package/test/player_integration.js +49 -41
- package/test/player_load_graph_integration.js +13 -7
- package/test/player_src_equals_integration.js +2 -2
- package/test/player_unit.js +40 -3
- package/test/polyfill/media_capabilities_unit.js +12 -6
- package/test/test/util/fake_drm_engine.js +7 -0
- package/test/test/util/layout_tests.js +2 -1
- package/test/test/util/simple_fakes.js +2 -2
- package/test/test/util/test_scheme.js +3 -0
- package/test/test/util/waiter.js +5 -0
- package/test/text/mp4_ttml_parser_unit.js +4 -4
- package/test/text/simple_text_displayer_unit.js +1 -1
- package/test/text/srt_text_parser_unit.js +1 -1
- package/test/text/text_engine_unit.js +6 -0
- package/test/text/ttml_text_parser_unit.js +49 -18
- package/test/text/ui_text_displayer_unit.js +9 -0
- package/test/text/vtt_text_parser_unit.js +31 -0
- package/test/util/buffer_utils_unit.js +1 -1
- package/test/util/periods_unit.js +113 -0
- package/third_party/closure-uri/uri.js +1 -1
- package/ui/externs/ui.js +24 -0
- package/ui/language_utils.js +11 -5
- package/ui/less/containers.less +1 -0
- package/ui/play_button.js +20 -0
- package/ui/playback_rate_selection.js +4 -0
- package/ui/presentation_time.js +5 -5
- package/ui/small_play_button.js +2 -2
- package/ui/volume_bar.js +10 -6
- /package/.github/{config.yml → ISSUE_TEMPLATE/config.yml} +0 -0
|
@@ -114,8 +114,8 @@ describe('Player Src Equals', () => {
|
|
|
114
114
|
expect(video.currentTime).toBeLessThan(2.0);
|
|
115
115
|
|
|
116
116
|
// Trigger a seek and then wait for the seek to take effect.
|
|
117
|
-
// This seek target is very close to the duration of the video.
|
|
118
|
-
video.currentTime =
|
|
117
|
+
// This seek target is very close to the duration of the video (10.01s).
|
|
118
|
+
video.currentTime = 9.5;
|
|
119
119
|
await waiter.waitForMovementOrFailOnTimeout(video, /* timeout= */10);
|
|
120
120
|
|
|
121
121
|
// Make sure the playhead is roughly where we expect it to be after
|
package/test/player_unit.js
CHANGED
|
@@ -559,15 +559,21 @@ describe('Player', () => {
|
|
|
559
559
|
});
|
|
560
560
|
|
|
561
561
|
describe('when config.streaming.preferNativeHls is set to true', () => {
|
|
562
|
-
|
|
562
|
+
beforeAll(() => {
|
|
563
563
|
shaka.media.ManifestParser.registerParserByMime(
|
|
564
564
|
'application/x-mpegurl',
|
|
565
565
|
() => new shaka.test.FakeManifestParser(manifest));
|
|
566
566
|
});
|
|
567
567
|
|
|
568
|
+
afterAll(() => {
|
|
569
|
+
// IMPORTANT: restore the ORIGINAL parser. DO NOT just unregister the
|
|
570
|
+
// fake!
|
|
571
|
+
shaka.media.ManifestParser.registerParserByMime(
|
|
572
|
+
'application/x-mpegurl',
|
|
573
|
+
() => new shaka.hls.HlsParser());
|
|
574
|
+
});
|
|
575
|
+
|
|
568
576
|
afterEach(() => {
|
|
569
|
-
shaka.media.ManifestParser.unregisterParserByMime(
|
|
570
|
-
'application/x-mpegurl');
|
|
571
577
|
video.canPlayType.calls.reset();
|
|
572
578
|
});
|
|
573
579
|
|
|
@@ -3291,6 +3297,37 @@ describe('Player', () => {
|
|
|
3291
3297
|
expect(tracks[0].id).toBe(2);
|
|
3292
3298
|
});
|
|
3293
3299
|
|
|
3300
|
+
it('removes based on frameRate', async () => {
|
|
3301
|
+
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
3302
|
+
manifest.addVariant(0, (variant) => {
|
|
3303
|
+
variant.addVideo(1, (stream) => {
|
|
3304
|
+
stream.frameRate = 15;
|
|
3305
|
+
});
|
|
3306
|
+
});
|
|
3307
|
+
|
|
3308
|
+
manifest.addVariant(1, (variant) => {
|
|
3309
|
+
variant.addVideo(2, (stream) => {
|
|
3310
|
+
stream.frameRate = 30;
|
|
3311
|
+
});
|
|
3312
|
+
});
|
|
3313
|
+
|
|
3314
|
+
manifest.addVariant(2, (variant) => {
|
|
3315
|
+
variant.addVideo(3, (stream) => {
|
|
3316
|
+
stream.frameRate = 60;
|
|
3317
|
+
});
|
|
3318
|
+
});
|
|
3319
|
+
});
|
|
3320
|
+
|
|
3321
|
+
await player.load(fakeManifestUri, 0, fakeMimeType);
|
|
3322
|
+
expect(player.getVariantTracks().length).toBe(3);
|
|
3323
|
+
|
|
3324
|
+
player.configure({restrictions: {minFrameRate: 20, maxFrameRate: 40}});
|
|
3325
|
+
|
|
3326
|
+
const tracks = player.getVariantTracks();
|
|
3327
|
+
expect(tracks.length).toBe(1);
|
|
3328
|
+
expect(tracks[0].id).toBe(1);
|
|
3329
|
+
});
|
|
3330
|
+
|
|
3294
3331
|
it('removes the whole variant if one stream is restricted', async () => {
|
|
3295
3332
|
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
3296
3333
|
manifest.addVariant(0, (variant) => {
|
|
@@ -178,8 +178,10 @@ describe('MediaCapabilities', () => {
|
|
|
178
178
|
await navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
|
|
179
179
|
|
|
180
180
|
expect(mockCanDisplayType).not.toHaveBeenCalled();
|
|
181
|
-
// 1 (during install()) +
|
|
182
|
-
|
|
181
|
+
// 1 (during install()) +
|
|
182
|
+
// 1 (for video config check) +
|
|
183
|
+
// 1 (for audio config check).
|
|
184
|
+
expect(isChromecastSpy).toHaveBeenCalledTimes(3);
|
|
183
185
|
// 1 (fallback in canCastDisplayType()) +
|
|
184
186
|
// 1 (mockDecodingConfig.audio).
|
|
185
187
|
expect(supportMap.has(mockDecodingConfig.video.contentType))
|
|
@@ -201,8 +203,10 @@ describe('MediaCapabilities', () => {
|
|
|
201
203
|
await navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
|
|
202
204
|
|
|
203
205
|
expect(mockCanDisplayType).not.toHaveBeenCalled();
|
|
204
|
-
// 1 (during install()) +
|
|
205
|
-
|
|
206
|
+
// 1 (during install()) +
|
|
207
|
+
// 1 (for video config check) +
|
|
208
|
+
// 1 (for audio config check).
|
|
209
|
+
expect(isChromecastSpy).toHaveBeenCalledTimes(3);
|
|
206
210
|
// 1 (fallback in canCastDisplayType()) +
|
|
207
211
|
// 1 (mockDecodingConfig.audio).
|
|
208
212
|
expect(supportMap.has(mockDecodingConfig.video.contentType))
|
|
@@ -248,8 +252,10 @@ describe('MediaCapabilities', () => {
|
|
|
248
252
|
shaka.polyfill.MediaCapabilities.install();
|
|
249
253
|
await navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);
|
|
250
254
|
|
|
251
|
-
// 1 (during install()) +
|
|
252
|
-
|
|
255
|
+
// 1 (during install()) +
|
|
256
|
+
// 1 (for video config check) +
|
|
257
|
+
// 1 (for audio config check).
|
|
258
|
+
expect(isChromecastSpy).toHaveBeenCalledTimes(3);
|
|
253
259
|
// 1 (mockDecodingConfig.audio).
|
|
254
260
|
expect(supportMap.has(chromecastType)).toBe(true);
|
|
255
261
|
// Called once in canCastDisplayType.
|
|
@@ -100,4 +100,11 @@ shaka.test.FakeDrmEngine = class {
|
|
|
100
100
|
// Copy the values to break the reference to the input value.
|
|
101
101
|
this.offlineSessions_ = sessions.map((s) => s);
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @override
|
|
106
|
+
*/
|
|
107
|
+
hasManifestInitData() {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
103
110
|
};
|
|
@@ -377,7 +377,8 @@ shaka.test.NativeTextLayoutTests = class extends shaka.test.TextLayoutTests {
|
|
|
377
377
|
|
|
378
378
|
/** @override */
|
|
379
379
|
recreateTextDisplayer() {
|
|
380
|
-
this.textDisplayer = new shaka.text.SimpleTextDisplayer(
|
|
380
|
+
this.textDisplayer = new shaka.text.SimpleTextDisplayer(
|
|
381
|
+
this.video, shaka.Player.TextTrackLabel);
|
|
381
382
|
this.textDisplayer.setTextVisibility(true);
|
|
382
383
|
}
|
|
383
384
|
|
|
@@ -520,7 +520,7 @@ shaka.test.FakeTransmuxer = class {
|
|
|
520
520
|
jasmine.createSpy('transmux').and.returnValue(Promise.resolve(output));
|
|
521
521
|
|
|
522
522
|
/** @type {!jasmine.Spy} */
|
|
523
|
-
this.
|
|
524
|
-
jasmine.createSpy('
|
|
523
|
+
this.getOriginalMimeType =
|
|
524
|
+
jasmine.createSpy('getOriginalMimeType').and.returnValue('mimeType');
|
|
525
525
|
}
|
|
526
526
|
};
|
package/test/test/util/waiter.js
CHANGED
|
@@ -184,6 +184,7 @@ shaka.test.Waiter = class {
|
|
|
184
184
|
}
|
|
185
185
|
this.eventManager_.unlisten(mediaElement, 'timeupdate');
|
|
186
186
|
this.eventManager_.unlisten(mediaElement, 'ended');
|
|
187
|
+
this.eventManager_.unlisten(mediaElement, 'durationchange');
|
|
187
188
|
};
|
|
188
189
|
|
|
189
190
|
const p = new Promise((resolve) => {
|
|
@@ -202,6 +203,10 @@ shaka.test.Waiter = class {
|
|
|
202
203
|
timer.tickEvery(/* seconds= */ 1);
|
|
203
204
|
this.eventManager_.listen(mediaElement, 'timeupdate', check);
|
|
204
205
|
this.eventManager_.listen(mediaElement, 'ended', check);
|
|
206
|
+
// Some tests on Safari expose a condition where the ended flag can be
|
|
207
|
+
// found in the desired state in a brief window during a durationchange
|
|
208
|
+
// event.
|
|
209
|
+
this.eventManager_.listen(mediaElement, 'durationchange', check);
|
|
205
210
|
});
|
|
206
211
|
|
|
207
212
|
return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
|
|
@@ -43,7 +43,7 @@ describe('Mp4TtmlParser', () => {
|
|
|
43
43
|
parser.parseInit(ttmlInitSegment);
|
|
44
44
|
const time =
|
|
45
45
|
{periodStart: 0, segmentStart: 0, segmentEnd: 60, vttOffset: 0};
|
|
46
|
-
const ret = parser.parseMedia(ttmlSegmentMultipleMDAT, time);
|
|
46
|
+
const ret = parser.parseMedia(ttmlSegmentMultipleMDAT, time, null);
|
|
47
47
|
// Bodies.
|
|
48
48
|
expect(ret.length).toBe(2);
|
|
49
49
|
// Divs.
|
|
@@ -63,10 +63,10 @@ describe('Mp4TtmlParser', () => {
|
|
|
63
63
|
const parser = new shaka.text.Mp4TtmlParser();
|
|
64
64
|
parser.parseInit(ttmlInitSegment);
|
|
65
65
|
|
|
66
|
-
const ret1 = parser.parseMedia(ttmlSegment, time1);
|
|
66
|
+
const ret1 = parser.parseMedia(ttmlSegment, time1, null);
|
|
67
67
|
expect(ret1.length).toBeGreaterThan(0);
|
|
68
68
|
|
|
69
|
-
const ret2 = parser.parseMedia(ttmlSegment, time2);
|
|
69
|
+
const ret2 = parser.parseMedia(ttmlSegment, time2, null);
|
|
70
70
|
expect(ret2.length).toBeGreaterThan(0);
|
|
71
71
|
|
|
72
72
|
expect(ret2[0].startTime).toBe(ret1[0].startTime + 7);
|
|
@@ -164,7 +164,7 @@ describe('Mp4TtmlParser', () => {
|
|
|
164
164
|
parser.parseInit(ttmlInitSegment);
|
|
165
165
|
const time =
|
|
166
166
|
{periodStart: 0, segmentStart: 0, segmentEnd: 60, vttOffset: 0};
|
|
167
|
-
const result = parser.parseMedia(ttmlSegment, time);
|
|
167
|
+
const result = parser.parseMedia(ttmlSegment, time, null);
|
|
168
168
|
shaka.test.TtmlUtils.verifyHelper(
|
|
169
169
|
cues, result, {startTime: 23, endTime: 53.5});
|
|
170
170
|
});
|
|
@@ -18,7 +18,7 @@ describe('SimpleTextDisplayer', () => {
|
|
|
18
18
|
|
|
19
19
|
beforeEach(() => {
|
|
20
20
|
video = new shaka.test.FakeVideo();
|
|
21
|
-
displayer = new SimpleTextDisplayer(video);
|
|
21
|
+
displayer = new SimpleTextDisplayer(video, shaka.Player.TextTrackLabel);
|
|
22
22
|
|
|
23
23
|
expect(video.textTracks.length).toBe(1);
|
|
24
24
|
mockTrack = /** @type {!shaka.test.FakeTextTrack} */ (video.textTracks[0]);
|
|
@@ -71,7 +71,7 @@ describe('SrtTextParser', () => {
|
|
|
71
71
|
const data = BufferUtils.toUint8(StringUtils.toUTF8(text));
|
|
72
72
|
|
|
73
73
|
const parser = new shaka.text.SrtTextParser();
|
|
74
|
-
const result = parser.parseMedia(data, time);
|
|
74
|
+
const result = parser.parseMedia(data, time, null);
|
|
75
75
|
|
|
76
76
|
const expected = cues.map((cue) => {
|
|
77
77
|
if (cue.nestedCues) {
|
|
@@ -95,6 +95,7 @@ describe('TextEngine', () => {
|
|
|
95
95
|
expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
|
|
96
96
|
dummyData,
|
|
97
97
|
{periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0},
|
|
98
|
+
undefined,
|
|
98
99
|
]);
|
|
99
100
|
|
|
100
101
|
expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
|
|
@@ -110,6 +111,7 @@ describe('TextEngine', () => {
|
|
|
110
111
|
expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
|
|
111
112
|
dummyData,
|
|
112
113
|
{periodStart: 0, segmentStart: 3, segmentEnd: 5, vttOffset: 0},
|
|
114
|
+
undefined,
|
|
113
115
|
]);
|
|
114
116
|
|
|
115
117
|
expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
|
|
@@ -262,6 +264,7 @@ describe('TextEngine', () => {
|
|
|
262
264
|
expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
|
|
263
265
|
dummyData,
|
|
264
266
|
{periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0},
|
|
267
|
+
undefined,
|
|
265
268
|
]);
|
|
266
269
|
expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
|
|
267
270
|
[
|
|
@@ -276,6 +279,7 @@ describe('TextEngine', () => {
|
|
|
276
279
|
expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
|
|
277
280
|
dummyData,
|
|
278
281
|
{periodStart: 4, segmentStart: 4, segmentEnd: 7, vttOffset: 4},
|
|
282
|
+
undefined,
|
|
279
283
|
]);
|
|
280
284
|
expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([
|
|
281
285
|
[
|
|
@@ -305,6 +309,7 @@ describe('TextEngine', () => {
|
|
|
305
309
|
expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
|
|
306
310
|
dummyData,
|
|
307
311
|
{periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0},
|
|
312
|
+
undefined,
|
|
308
313
|
]);
|
|
309
314
|
|
|
310
315
|
textEngine.setTimestampOffset(8);
|
|
@@ -314,6 +319,7 @@ describe('TextEngine', () => {
|
|
|
314
319
|
expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([
|
|
315
320
|
dummyData,
|
|
316
321
|
{periodStart: 8, segmentStart: 4, segmentEnd: 7, vttOffset: 4},
|
|
322
|
+
undefined,
|
|
317
323
|
]);
|
|
318
324
|
});
|
|
319
325
|
});
|
|
@@ -638,8 +638,8 @@ describe('TtmlTextParser', () => {
|
|
|
638
638
|
id: 'subtitleArea',
|
|
639
639
|
viewportAnchorX: 50,
|
|
640
640
|
viewportAnchorY: 16,
|
|
641
|
-
width:
|
|
642
|
-
height:
|
|
641
|
+
width: 50,
|
|
642
|
+
height: 84,
|
|
643
643
|
},
|
|
644
644
|
startTime: 62.05,
|
|
645
645
|
endTime: 3723.2,
|
|
@@ -666,8 +666,8 @@ describe('TtmlTextParser', () => {
|
|
|
666
666
|
region: {
|
|
667
667
|
viewportAnchorX: 50,
|
|
668
668
|
viewportAnchorY: 16,
|
|
669
|
-
width:
|
|
670
|
-
height:
|
|
669
|
+
width: 50,
|
|
670
|
+
height: 84,
|
|
671
671
|
},
|
|
672
672
|
startTime: 62.05,
|
|
673
673
|
endTime: 3723.2,
|
|
@@ -694,8 +694,8 @@ describe('TtmlTextParser', () => {
|
|
|
694
694
|
region: {
|
|
695
695
|
viewportAnchorX: 50,
|
|
696
696
|
viewportAnchorY: 16,
|
|
697
|
-
width:
|
|
698
|
-
height:
|
|
697
|
+
width: 50,
|
|
698
|
+
height: 84,
|
|
699
699
|
},
|
|
700
700
|
startTime: 62.05,
|
|
701
701
|
endTime: 3723.2,
|
|
@@ -872,8 +872,8 @@ describe('TtmlTextParser', () => {
|
|
|
872
872
|
viewportAnchorY: 16,
|
|
873
873
|
regionAnchorX: 0,
|
|
874
874
|
regionAnchorY: 0,
|
|
875
|
-
width:
|
|
876
|
-
height:
|
|
875
|
+
width: 50,
|
|
876
|
+
height: 84,
|
|
877
877
|
heightUnits: CueRegion.units.PERCENTAGE,
|
|
878
878
|
widthUnits: CueRegion.units.PERCENTAGE,
|
|
879
879
|
viewportAnchorUnits: CueRegion.units.PERCENTAGE,
|
|
@@ -945,8 +945,8 @@ describe('TtmlTextParser', () => {
|
|
|
945
945
|
id: 'subtitleArea',
|
|
946
946
|
viewportAnchorX: 50,
|
|
947
947
|
viewportAnchorY: 16,
|
|
948
|
-
width:
|
|
949
|
-
height:
|
|
948
|
+
width: 50,
|
|
949
|
+
height: 84,
|
|
950
950
|
},
|
|
951
951
|
startTime: 62.05,
|
|
952
952
|
endTime: 3723.2,
|
|
@@ -973,8 +973,8 @@ describe('TtmlTextParser', () => {
|
|
|
973
973
|
region: {
|
|
974
974
|
viewportAnchorX: 50,
|
|
975
975
|
viewportAnchorY: 16,
|
|
976
|
-
width:
|
|
977
|
-
height:
|
|
976
|
+
width: 50,
|
|
977
|
+
height: 84,
|
|
978
978
|
},
|
|
979
979
|
startTime: 62.05,
|
|
980
980
|
endTime: 3723.2,
|
|
@@ -1001,8 +1001,8 @@ describe('TtmlTextParser', () => {
|
|
|
1001
1001
|
region: {
|
|
1002
1002
|
viewportAnchorX: 50,
|
|
1003
1003
|
viewportAnchorY: 16,
|
|
1004
|
-
width:
|
|
1005
|
-
height:
|
|
1004
|
+
width: 50,
|
|
1005
|
+
height: 84,
|
|
1006
1006
|
},
|
|
1007
1007
|
startTime: 62.05,
|
|
1008
1008
|
endTime: 3723.2,
|
|
@@ -1032,8 +1032,8 @@ describe('TtmlTextParser', () => {
|
|
|
1032
1032
|
id: 'subtitleArea',
|
|
1033
1033
|
viewportAnchorX: 12.2,
|
|
1034
1034
|
viewportAnchorY: 50.005,
|
|
1035
|
-
width:
|
|
1036
|
-
height:
|
|
1035
|
+
width: 87.8,
|
|
1036
|
+
height: 49.995,
|
|
1037
1037
|
},
|
|
1038
1038
|
startTime: 62.05,
|
|
1039
1039
|
endTime: 3723.2,
|
|
@@ -1238,6 +1238,35 @@ describe('TtmlTextParser', () => {
|
|
|
1238
1238
|
});
|
|
1239
1239
|
});
|
|
1240
1240
|
|
|
1241
|
+
it('supports smpte:backgroundImage attribute with url', () => {
|
|
1242
|
+
verifyHelper(
|
|
1243
|
+
[
|
|
1244
|
+
{
|
|
1245
|
+
startTime: 62.05,
|
|
1246
|
+
endTime: 3723.2,
|
|
1247
|
+
payload: '',
|
|
1248
|
+
},
|
|
1249
|
+
],
|
|
1250
|
+
'<tt ' +
|
|
1251
|
+
'xmlns:ttm="http://www.w3.org/ns/ttml#metadata" ' +
|
|
1252
|
+
'xmlns:smpte="http://www.smpte-ra.org/schemas/2052-1/2010/smpte-tt">' +
|
|
1253
|
+
'<metadata>' +
|
|
1254
|
+
'<smpte:image imageType="PNG" encoding="Base64" xml:id="img_0">' +
|
|
1255
|
+
'base64EncodedImage</smpte:image>' +
|
|
1256
|
+
'</metadata>' +
|
|
1257
|
+
'<body><div smpte:backgroundImage="img_0.png">' +
|
|
1258
|
+
'<p begin="01:02.05" end="01:02:03.200"></p>' +
|
|
1259
|
+
'</div></body></tt>',
|
|
1260
|
+
{periodStart: 0, segmentStart: 60, segmentEnd: 3730, vttOffset: 0},
|
|
1261
|
+
{startTime: 62.05, endTime: 3723.2},
|
|
1262
|
+
{
|
|
1263
|
+
startTime: 62.05,
|
|
1264
|
+
endTime: 3723.2,
|
|
1265
|
+
backgroundImage: 'foo://bar/img_0.png',
|
|
1266
|
+
isContainer: false,
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1241
1270
|
it('supports smpte:backgroundImage attribute in div element', () => {
|
|
1242
1271
|
verifyHelper(
|
|
1243
1272
|
[],
|
|
@@ -2060,7 +2089,8 @@ describe('TtmlTextParser', () => {
|
|
|
2060
2089
|
function verifyHelper(cues, text, time, bodyProperties, divProperties) {
|
|
2061
2090
|
const data =
|
|
2062
2091
|
shaka.util.BufferUtils.toUint8(shaka.util.StringUtils.toUTF8(text));
|
|
2063
|
-
const result = new shaka.text.TtmlTextParser()
|
|
2092
|
+
const result = new shaka.text.TtmlTextParser()
|
|
2093
|
+
.parseMedia(data, time, 'foo://bar');
|
|
2064
2094
|
shaka.test.TtmlUtils.verifyHelper(
|
|
2065
2095
|
cues, result, bodyProperties, divProperties);
|
|
2066
2096
|
}
|
|
@@ -2087,7 +2117,8 @@ describe('TtmlTextParser', () => {
|
|
|
2087
2117
|
expect(() => {
|
|
2088
2118
|
new shaka.text.TtmlTextParser().parseMedia(
|
|
2089
2119
|
shaka.util.BufferUtils.toUint8(data),
|
|
2090
|
-
{periodStart: 0, segmentStart: 0, segmentEnd: 10, vttOffset: 0}
|
|
2120
|
+
{periodStart: 0, segmentStart: 0, segmentEnd: 10, vttOffset: 0},
|
|
2121
|
+
'foo://bar');
|
|
2091
2122
|
}).toThrow(error);
|
|
2092
2123
|
}
|
|
2093
2124
|
});
|
|
@@ -605,4 +605,13 @@ describe('UITextDisplayer', () => {
|
|
|
605
605
|
(e) => e.nodeType == Node.ELEMENT_NODE);
|
|
606
606
|
expect(childrenOfTwo.length).toBe(3);
|
|
607
607
|
});
|
|
608
|
+
|
|
609
|
+
it('textDisplayer does not crash if destroy is called more than once', () => {
|
|
610
|
+
expect(videoContainer.childNodes.length).toBe(1);
|
|
611
|
+
|
|
612
|
+
textDisplayer.destroy();
|
|
613
|
+
textDisplayer.destroy();
|
|
614
|
+
|
|
615
|
+
expect(videoContainer.childNodes.length).toBe(0);
|
|
616
|
+
});
|
|
608
617
|
});
|
|
@@ -1072,6 +1072,37 @@ describe('VttTextParser', () => {
|
|
|
1072
1072
|
{periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
|
|
1073
1073
|
});
|
|
1074
1074
|
|
|
1075
|
+
it('passes text-shadow when multiple classes included', () => {
|
|
1076
|
+
verifyHelper(
|
|
1077
|
+
[
|
|
1078
|
+
{
|
|
1079
|
+
startTime: 20,
|
|
1080
|
+
endTime: 40,
|
|
1081
|
+
payload: '',
|
|
1082
|
+
nestedCues: [
|
|
1083
|
+
{
|
|
1084
|
+
startTime: 20,
|
|
1085
|
+
endTime: 40,
|
|
1086
|
+
payload: 'Test',
|
|
1087
|
+
fontStyle: Cue.fontStyle.ITALIC,
|
|
1088
|
+
textShadow: 'black 5%',
|
|
1089
|
+
},
|
|
1090
|
+
],
|
|
1091
|
+
},
|
|
1092
|
+
],
|
|
1093
|
+
'WEBVTT\n\n' +
|
|
1094
|
+
'STYLE\n' +
|
|
1095
|
+
'::cue(.shadow) {\n' +
|
|
1096
|
+
' text-shadow: black 5%;\n' +
|
|
1097
|
+
'}\n' +
|
|
1098
|
+
'::cue(.italic) {\n' +
|
|
1099
|
+
' font-style: italic;\n' +
|
|
1100
|
+
'}\n\n' +
|
|
1101
|
+
'00:00:20.000 --> 00:00:40.000\n' +
|
|
1102
|
+
'<c.shadow.italic>Test</c>',
|
|
1103
|
+
{periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0});
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1075
1106
|
it('supports karaoke style text', () => {
|
|
1076
1107
|
verifyHelper(
|
|
1077
1108
|
[
|
|
@@ -598,6 +598,55 @@ describe('PeriodCombiner', () => {
|
|
|
598
598
|
}
|
|
599
599
|
});
|
|
600
600
|
|
|
601
|
+
// Regression test for #6054, where we failed on multi-period content with
|
|
602
|
+
// different numbers of forced-subtitle streams per period.
|
|
603
|
+
it('Does not combine subtitle and forced-subtitle tracks', async () => {
|
|
604
|
+
const videoStreams = [makeVideoStream(1280)];
|
|
605
|
+
const audioStreams = [makeAudioStream('en', /* channels= */ 2)];
|
|
606
|
+
const imageStreams = [];
|
|
607
|
+
|
|
608
|
+
const forcedSubtitle = makeTextStream('de');
|
|
609
|
+
forcedSubtitle.roles = ['forced-subtitle'];
|
|
610
|
+
forcedSubtitle.forced = true;
|
|
611
|
+
|
|
612
|
+
const subtitle = makeTextStream('de');
|
|
613
|
+
subtitle.roles = ['subtitle'];
|
|
614
|
+
|
|
615
|
+
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
616
|
+
const periods = [
|
|
617
|
+
{
|
|
618
|
+
id: '1',
|
|
619
|
+
videoStreams,
|
|
620
|
+
audioStreams,
|
|
621
|
+
textStreams: [
|
|
622
|
+
forcedSubtitle,
|
|
623
|
+
subtitle,
|
|
624
|
+
],
|
|
625
|
+
imageStreams,
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
id: '2',
|
|
629
|
+
videoStreams,
|
|
630
|
+
audioStreams,
|
|
631
|
+
textStreams: [
|
|
632
|
+
subtitle,
|
|
633
|
+
],
|
|
634
|
+
imageStreams,
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
id: '3',
|
|
638
|
+
videoStreams,
|
|
639
|
+
audioStreams,
|
|
640
|
+
textStreams: [],
|
|
641
|
+
imageStreams,
|
|
642
|
+
},
|
|
643
|
+
];
|
|
644
|
+
|
|
645
|
+
await combiner.combinePeriods(periods, /* isDynamic= */ true);
|
|
646
|
+
const textStreams = combiner.getTextStreams();
|
|
647
|
+
expect(textStreams.every((s) => s.roles.length === 1)).toBe(true);
|
|
648
|
+
});
|
|
649
|
+
|
|
601
650
|
// Regression test for #3383, where we failed on multi-period content with
|
|
602
651
|
// multiple image streams per period.
|
|
603
652
|
it('Can handle multiple image streams', async () => {
|
|
@@ -1004,6 +1053,70 @@ describe('PeriodCombiner', () => {
|
|
|
1004
1053
|
expect(audio2.originalId).toBe('2,4');
|
|
1005
1054
|
});
|
|
1006
1055
|
|
|
1056
|
+
it('Matches streams with labels', async () => {
|
|
1057
|
+
const stream1 = makeAudioStream('en', /* channels= */ 2);
|
|
1058
|
+
stream1.originalId = '1';
|
|
1059
|
+
stream1.bandwidth = 129597;
|
|
1060
|
+
stream1.codecs = 'mp4a.40.2';
|
|
1061
|
+
|
|
1062
|
+
const stream2 = makeAudioStream('en', /* channels= */ 2);
|
|
1063
|
+
stream2.originalId = '2';
|
|
1064
|
+
stream2.bandwidth = 129637;
|
|
1065
|
+
stream2.codecs = 'mp4a.40.2';
|
|
1066
|
+
stream2.label = 'description';
|
|
1067
|
+
|
|
1068
|
+
const stream3 = makeAudioStream('en', /* channels= */ 2);
|
|
1069
|
+
stream3.originalId = '3';
|
|
1070
|
+
stream3.bandwidth = 131037;
|
|
1071
|
+
stream3.codecs = 'mp4a.40.2';
|
|
1072
|
+
|
|
1073
|
+
const stream4 = makeAudioStream('en', /* channels= */ 2);
|
|
1074
|
+
stream4.originalId = '4';
|
|
1075
|
+
stream4.bandwidth = 131034;
|
|
1076
|
+
stream4.codecs = 'mp4a.40.2';
|
|
1077
|
+
stream4.label = 'description';
|
|
1078
|
+
|
|
1079
|
+
/** @type {!Array.<shaka.util.PeriodCombiner.Period>} */
|
|
1080
|
+
const periods = [
|
|
1081
|
+
{
|
|
1082
|
+
id: '0',
|
|
1083
|
+
videoStreams: [
|
|
1084
|
+
makeVideoStream(1080),
|
|
1085
|
+
],
|
|
1086
|
+
audioStreams: [
|
|
1087
|
+
stream1,
|
|
1088
|
+
stream2,
|
|
1089
|
+
],
|
|
1090
|
+
textStreams: [],
|
|
1091
|
+
imageStreams: [],
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
id: '1',
|
|
1095
|
+
videoStreams: [
|
|
1096
|
+
makeVideoStream(1080),
|
|
1097
|
+
],
|
|
1098
|
+
audioStreams: [
|
|
1099
|
+
stream3,
|
|
1100
|
+
stream4,
|
|
1101
|
+
],
|
|
1102
|
+
textStreams: [],
|
|
1103
|
+
imageStreams: [],
|
|
1104
|
+
},
|
|
1105
|
+
];
|
|
1106
|
+
|
|
1107
|
+
await combiner.combinePeriods(periods, /* isDynamic= */ true);
|
|
1108
|
+
const variants = combiner.getVariants();
|
|
1109
|
+
expect(variants.length).toBe(2);
|
|
1110
|
+
// We can use the originalId field to see what each track is composed of.
|
|
1111
|
+
const audio1 = variants[0].audio;
|
|
1112
|
+
expect(audio1.label).toBe(null);
|
|
1113
|
+
expect(audio1.originalId).toBe('1,3');
|
|
1114
|
+
|
|
1115
|
+
const audio2 = variants[1].audio;
|
|
1116
|
+
expect(audio2.label).toBe('description');
|
|
1117
|
+
expect(audio2.originalId).toBe('2,4');
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1007
1120
|
it('Matches streams with related codecs', async () => {
|
|
1008
1121
|
const stream1 = makeVideoStream(1080);
|
|
1009
1122
|
stream1.originalId = '1';
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Use new goog.Uri(string) to parse a URI string.
|
|
10
10
|
*
|
|
11
|
-
* e.g
|
|
11
|
+
* e.g.: <code>var myUri = new goog.Uri(window.location);</code>
|
|
12
12
|
*
|
|
13
13
|
* Implements RFC 3986 for parsing/formatting URIs.
|
|
14
14
|
* http://www.ietf.org/rfc/rfc3986.txt
|
package/ui/externs/ui.js
CHANGED
|
@@ -443,3 +443,27 @@ shaka.extern.IUISeekBar.Factory = class {
|
|
|
443
443
|
*/
|
|
444
444
|
create(rootElement, controls) {}
|
|
445
445
|
};
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* @interface
|
|
449
|
+
* @exportDoc
|
|
450
|
+
*/
|
|
451
|
+
shaka.extern.IUIPlayButton = class {
|
|
452
|
+
/**
|
|
453
|
+
* @param {!HTMLElement} parent
|
|
454
|
+
* @param {!shaka.ui.Controls} controls
|
|
455
|
+
*/
|
|
456
|
+
constructor(parent, controls) {
|
|
457
|
+
/**
|
|
458
|
+
* @protected {!HTMLButtonElement}
|
|
459
|
+
* @exportDoc
|
|
460
|
+
*/
|
|
461
|
+
this.button;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/** @return {boolean} */
|
|
465
|
+
isPaused() {}
|
|
466
|
+
|
|
467
|
+
/** @return {boolean} */
|
|
468
|
+
isEnded() {}
|
|
469
|
+
};
|