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
|
@@ -7,6 +7,60 @@ other ad providers in v3.1+.
|
|
|
7
7
|
Please note that the current API is likely to undergo significant
|
|
8
8
|
changes as our support extends.
|
|
9
9
|
|
|
10
|
+
#### AWS Elemental MediaTailor Integration
|
|
11
|
+
|
|
12
|
+
Shaka Player provides an integration with the [AWS Elemental MediaTailor][].
|
|
13
|
+
We support Client Side, Server Side and overlays ad insertion.
|
|
14
|
+
|
|
15
|
+
[AWS Elemental MediaTailor]: https://aws.amazon.com/mediatailor/
|
|
16
|
+
|
|
17
|
+
All ad insertion experiences are available through the
|
|
18
|
+
{@linksource shaka.extern.IAdManager} object on the Player.
|
|
19
|
+
|
|
20
|
+
If you're not using Shaka's UI library, you will
|
|
21
|
+
also need to create a `<div>` over your video element to serve as an ad
|
|
22
|
+
container.
|
|
23
|
+
|
|
24
|
+
Start by initializing the server side logic.
|
|
25
|
+
With Shaka UI:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
const video = document.getElementById('video');
|
|
29
|
+
const ui = video['ui'];
|
|
30
|
+
const controls = video.ui.getControls();
|
|
31
|
+
// If you're using a non-UI build, this is the div you'll need to create
|
|
32
|
+
// for your layout.
|
|
33
|
+
const container = controls.getServerSideAdContainer();
|
|
34
|
+
const player = controls.getPlayer();
|
|
35
|
+
const netEngine = player.getNetworkingEngine();
|
|
36
|
+
const adManager = player.getAdManager();
|
|
37
|
+
adManager.initMediaTailor(container, netEngine, video);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Requesting a Client Side stream:
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
const mediaTailorUrl = 'https://d305rncpy6ne2q.cloudfront.net/v1/session/94063eadf7d8c56e9e2edd84fdf897826a70d0df/SFP-MediaTailor-VOD-HLS-DASH/out/v1/b94f3611978f419985a18335bac9d9cb/ddb73bf548a44551a0059c346226445a/eaa5485198bf497284559efb8172425e/index.mpd';
|
|
44
|
+
const mediaTailorAdsParams = {
|
|
45
|
+
adsParams: {
|
|
46
|
+
assetid: 'test2',
|
|
47
|
+
podduration: '15',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const uri = await adManager.requestMediaTailorStream(mediaTailorUrl, mediaTailorAdsParams);
|
|
51
|
+
player.load(uri);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Requesting a Server Side stream:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
const mediaTailorUrl = 'https://ad391cc0d55b44c6a86d232548adc225.mediatailor.us-east-1.amazonaws.com/v1/session/d02fedbbc5a68596164208dd24e9b48aa60dadc7/singssai/master.m3u8';
|
|
58
|
+
const uri = await adManager.requestMediaTailorStream(mediaTailorUrl);
|
|
59
|
+
player.load(uri);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Note: overlays ad insertions is the same as server side.
|
|
63
|
+
|
|
10
64
|
#### IMA SDK Integration
|
|
11
65
|
|
|
12
66
|
Shaka Player provides an integration with the [Interactive Media Ads][] SDKs.
|
|
@@ -98,9 +98,9 @@ player.getNetworkingEngine().registerRequestFilter((type, request) => {
|
|
|
98
98
|
const originalPayload = new Uint8Array(request.body);
|
|
99
99
|
const base64Payload =
|
|
100
100
|
shaka.util.Uint8ArrayUtils.toStandardBase64(originalPayload);
|
|
101
|
-
const params = 'spc=' + base64Payload;
|
|
101
|
+
const params = 'spc=' + encodeURIComponent(base64Payload);
|
|
102
102
|
request.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
103
|
-
request.body = shaka.util.StringUtils.toUTF8(
|
|
103
|
+
request.body = shaka.util.StringUtils.toUTF8(params);
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
player.getNetworkingEngine().registerResponseFilter((type, response) => {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
{ "license-wrapping": { "title": "License Wrapping" } },
|
|
10
10
|
{ "ui": { "title": "UI Library" } },
|
|
11
11
|
{ "ui-customization": { "title": "Configuring the UI" } },
|
|
12
|
+
{ "text-displayer": { "title": "Configuring text displayer" } },
|
|
12
13
|
{ "errors": { "title": "Error Handling" } },
|
|
13
14
|
{ "a11y": { "title": "Creating accessible buttons" } },
|
|
14
15
|
{ "ad_monetization": { "title": "Serving ads with our IMA SDK integration" } },
|
|
@@ -38,6 +38,10 @@ __Subtitle/caption parsers__
|
|
|
38
38
|
{@linksource shaka.text.Mp4VttParser}
|
|
39
39
|
- TTML: {@linksource shaka.text.TtmlTextParser} and
|
|
40
40
|
{@linksource shaka.text.Mp4TtmlParser}
|
|
41
|
+
- SubRip (SRT): {@linksource shaka.text.SrtTextParser}
|
|
42
|
+
- LyRiCs (LRC): {@linksource shaka.text.LrcTextParser}
|
|
43
|
+
- SubStation Alpha (SSA, ASS): {@linksource shaka.text.SsaTextParser}
|
|
44
|
+
- SubViewer (SBV): {@linksource shaka.text.SbvTextParser}
|
|
41
45
|
|
|
42
46
|
__Subtitle/caption displayers__
|
|
43
47
|
- Configured at runtime on a Player instance
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Configuring text displayer`
|
|
2
|
+
|
|
3
|
+
Shaka Player supports two types of Text Displayer.
|
|
4
|
+
1) Using the browser's native API, Shaka Player creates a textTrack along
|
|
5
|
+
with the AUDIO or VIDEO Element.
|
|
6
|
+
2) Rendering the subtitles in a container in the DOM.
|
|
7
|
+
3) Providing a custom text displayer factory would allow a developer to make
|
|
8
|
+
their own custom text displayer that fits neither category.
|
|
9
|
+
|
|
10
|
+
By default, if not configured otherwise, the player will use type 1.
|
|
11
|
+
To configure type 2, you have to call `setVideoContainer` function before
|
|
12
|
+
making `load` call in the player.
|
|
13
|
+
|
|
14
|
+
Note: The UI calls setVideoContainer for you if the video's controls are
|
|
15
|
+
disabled, so this isn't always necessary when using the UI.
|
|
@@ -265,3 +265,32 @@ PR contributions to [the gallery repo][] are welcome.
|
|
|
265
265
|
[@lucksy]: https://github.com/lucksy
|
|
266
266
|
[pre-packaged Shaka UI themes]: https://lucksy.github.io/shaka-player-themes/
|
|
267
267
|
[the gallery repo]: https://github.com/lucksy/shaka-player-themes
|
|
268
|
+
|
|
269
|
+
#### Add custom localization
|
|
270
|
+
|
|
271
|
+
Load specific locale data at runtime (adjust the URL and language as needed):
|
|
272
|
+
```js
|
|
273
|
+
const locale = 'el';
|
|
274
|
+
const controls = ui.getControls();
|
|
275
|
+
const localization = controls.getLocalization();
|
|
276
|
+
const response = await fetch('ui/locales/' + locale + '.json'); // <----- JSON translation URL here
|
|
277
|
+
const translations = await response.json();
|
|
278
|
+
const translation_map = new Map(Object.entries(translations));
|
|
279
|
+
localization.insert(locale, translation_map);
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Lazy-load any requested locale data at runtime (adjust the URL as needed):
|
|
283
|
+
```js
|
|
284
|
+
const controls = ui.getControls();
|
|
285
|
+
const localization = controls.getLocalization();
|
|
286
|
+
|
|
287
|
+
localization.addEventListener('unknown-locales', async (e) => {
|
|
288
|
+
for (const locale of e.locales) {
|
|
289
|
+
const response = await fetch('ui/locales/' + locale + '.json'); // <----- JSON translation URL here
|
|
290
|
+
const translations = await response.json();
|
|
291
|
+
const translation_map = new Map(Object.entries(translations));
|
|
292
|
+
localization.insert(locale, translation_map);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
package/docs/tutorials/ui.md
CHANGED
|
@@ -203,11 +203,14 @@ constructor.
|
|
|
203
203
|
```js
|
|
204
204
|
// "local" because it is for local playback only, as opposed to the player proxy
|
|
205
205
|
// object, which will route your calls to the ChromeCast receiver as necessary.
|
|
206
|
-
const localPlayer = new shaka.Player(
|
|
206
|
+
const localPlayer = new shaka.Player();
|
|
207
207
|
// "Overlay" because the UI will add DOM elements inside the container,
|
|
208
208
|
// to visually overlay the video element
|
|
209
209
|
const ui = new shaka.ui.Overlay(localPlayer, videoContainerElement,
|
|
210
210
|
videoElement);
|
|
211
|
+
// Now that the player has been configured to be part of a UI, attach it to the
|
|
212
|
+
// video.
|
|
213
|
+
await localPlayer.attach(videoElement);
|
|
211
214
|
|
|
212
215
|
// As with DOM-based setup, get access to the UI controls and player from the
|
|
213
216
|
// UI.
|
package/externs/lcevc.js
CHANGED
|
@@ -94,6 +94,14 @@ shaka.extern.ManifestParser = class {
|
|
|
94
94
|
* @exportDoc
|
|
95
95
|
*/
|
|
96
96
|
onExpirationUpdated(sessionId, expiration) {}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Tell the parser that the initial variant has been chosen.
|
|
100
|
+
*
|
|
101
|
+
* @param {shaka.extern.Variant} variant
|
|
102
|
+
* @exportDoc
|
|
103
|
+
*/
|
|
104
|
+
onInitialVariantChosen(variant) {}
|
|
97
105
|
};
|
|
98
106
|
|
|
99
107
|
|
package/externs/shaka/player.js
CHANGED
|
@@ -561,7 +561,7 @@ shaka.extern.TimelineRegionInfo;
|
|
|
561
561
|
* @property {?number} channelsCount
|
|
562
562
|
* The number of audio channels, or null if unknown.
|
|
563
563
|
* @property {?string} pixelAspectRatio
|
|
564
|
-
* The pixel aspect ratio value; e.g "1:1".
|
|
564
|
+
* The pixel aspect ratio value; e.g. "1:1".
|
|
565
565
|
* @property {?number} width
|
|
566
566
|
* The video width in pixels.
|
|
567
567
|
* @exportDoc
|
package/externs/shaka/text.js
CHANGED
|
@@ -417,11 +417,13 @@ shaka.extern.TextParser = class {
|
|
|
417
417
|
* @param {shaka.extern.TextParser.TimeContext} timeContext
|
|
418
418
|
* The time information that should be used to adjust the times values
|
|
419
419
|
* for each cue.
|
|
420
|
+
* @param {?(string|undefined)} uri
|
|
421
|
+
* The media uri.
|
|
420
422
|
* @return {!Array.<!shaka.extern.Cue>}
|
|
421
423
|
*
|
|
422
424
|
* @exportDoc
|
|
423
425
|
*/
|
|
424
|
-
parseMedia(data, timeContext) {}
|
|
426
|
+
parseMedia(data, timeContext, uri) {}
|
|
425
427
|
|
|
426
428
|
/**
|
|
427
429
|
* Notifies the stream if the manifest is in sequence mode or not.
|
|
@@ -63,7 +63,7 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
63
63
|
this.bandwidthEstimator_.configure(this.config_.advanced);
|
|
64
64
|
}
|
|
65
65
|
const chosenVariant = this.chooseVariant();
|
|
66
|
-
if (chosenVariant) {
|
|
66
|
+
if (chosenVariant && navigator.onLine) {
|
|
67
67
|
this.switch_(chosenVariant);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -207,6 +207,15 @@ shaka.ads.ClientSideAd = class {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
/**
|
|
211
|
+
* It's required for a muted ad to start when autoplaying.
|
|
212
|
+
*
|
|
213
|
+
* @param {number} videoVolume
|
|
214
|
+
*/
|
|
215
|
+
setInitialMuted(videoVolume) {
|
|
216
|
+
this.volume_ = videoVolume;
|
|
217
|
+
this.manager_.setVolume(0);
|
|
218
|
+
}
|
|
210
219
|
|
|
211
220
|
/**
|
|
212
221
|
* @override
|
|
@@ -13,6 +13,10 @@ goog.provide('shaka.ads.ClientSideAdManager');
|
|
|
13
13
|
|
|
14
14
|
goog.require('goog.asserts');
|
|
15
15
|
goog.require('shaka.ads.ClientSideAd');
|
|
16
|
+
goog.require('shaka.log');
|
|
17
|
+
goog.require('shaka.util.Dom');
|
|
18
|
+
goog.require('shaka.util.EventManager');
|
|
19
|
+
goog.require('shaka.util.FakeEvent');
|
|
16
20
|
goog.require('shaka.util.IReleasable');
|
|
17
21
|
|
|
18
22
|
/**
|
|
@@ -452,9 +456,10 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
452
456
|
if (this.ad_.isLinear()) {
|
|
453
457
|
this.adContainer_.setAttribute('ad-active', 'true');
|
|
454
458
|
this.video_.pause();
|
|
455
|
-
this.ad_.setVolume(this.video_.volume);
|
|
456
459
|
if (this.video_.muted) {
|
|
457
|
-
this.ad_.
|
|
460
|
+
this.ad_.setInitialMuted(this.video_.volume);
|
|
461
|
+
} else {
|
|
462
|
+
this.ad_.setVolume(this.video_.volume);
|
|
458
463
|
}
|
|
459
464
|
}
|
|
460
465
|
}
|
|
@@ -14,7 +14,11 @@ goog.provide('shaka.ads.ServerSideAdManager');
|
|
|
14
14
|
goog.require('goog.asserts');
|
|
15
15
|
goog.require('shaka.ads.ServerSideAd');
|
|
16
16
|
goog.require('shaka.log');
|
|
17
|
+
goog.require('shaka.util.EventManager');
|
|
18
|
+
goog.require('shaka.util.Error');
|
|
19
|
+
goog.require('shaka.util.FakeEvent');
|
|
17
20
|
goog.require('shaka.util.IReleasable');
|
|
21
|
+
goog.require('shaka.util.PublicPromise');
|
|
18
22
|
|
|
19
23
|
|
|
20
24
|
/**
|
package/lib/cast/cast_proxy.js
CHANGED
|
@@ -496,6 +496,16 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
496
496
|
startTime = this.sender_.get('video', 'currentTime');
|
|
497
497
|
}
|
|
498
498
|
|
|
499
|
+
let activeTextTrack;
|
|
500
|
+
const textTracks = this.sender_.get('player', 'getTextTracks')();
|
|
501
|
+
|
|
502
|
+
if (textTracks && textTracks.length) {
|
|
503
|
+
activeTextTrack = textTracks.find((t) => t.active);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const isTextTrackVisible =
|
|
507
|
+
this.sender_.get('player', 'isTextTrackVisible')();
|
|
508
|
+
|
|
499
509
|
// Now load the manifest, if present.
|
|
500
510
|
if (assetUri) {
|
|
501
511
|
// Don't autoplay the content until we finish setting up initial state.
|
|
@@ -527,6 +537,14 @@ shaka.cast.CastProxy = class extends shaka.util.FakeEventTarget {
|
|
|
527
537
|
/** @type {Object} */(this.localPlayer_)[setter](value);
|
|
528
538
|
}
|
|
529
539
|
|
|
540
|
+
this.localPlayer_.setTextTrackVisibility(isTextTrackVisible);
|
|
541
|
+
if (activeTextTrack) {
|
|
542
|
+
this.localPlayer_.selectTextLanguage(
|
|
543
|
+
activeTextTrack.language,
|
|
544
|
+
activeTextTrack.roles,
|
|
545
|
+
activeTextTrack.forced);
|
|
546
|
+
}
|
|
547
|
+
|
|
530
548
|
// Restore the original autoplay setting.
|
|
531
549
|
this.localVideo_.autoplay = autoplay;
|
|
532
550
|
if (assetUri) {
|
package/lib/cea/cea608_memory.js
CHANGED
|
@@ -80,7 +80,7 @@ shaka.cea.Cea608Memory = class {
|
|
|
80
80
|
* @return {?shaka.cea.ICaptionDecoder.ClosedCaption}
|
|
81
81
|
*/
|
|
82
82
|
forceEmit(startTime, endTime) {
|
|
83
|
-
const stream = `CC${(this.fieldNum_<< 1) | this.channelNum_ +1}`;
|
|
83
|
+
const stream = `CC${((this.fieldNum_<< 1) | this.channelNum_) + 1}`;
|
|
84
84
|
const topLevelCue = new shaka.text.Cue(
|
|
85
85
|
startTime, endTime, /* payload= */ '');
|
|
86
86
|
return shaka.cea.CeaUtils.getParsedCaption(
|
package/lib/cea/cea_decoder.js
CHANGED
|
@@ -117,6 +117,9 @@ shaka.cea.CeaDecoder = class {
|
|
|
117
117
|
const reader = new shaka.util.DataViewReader(
|
|
118
118
|
userDataSeiMessage, shaka.util.DataViewReader.Endianness.BIG_ENDIAN);
|
|
119
119
|
|
|
120
|
+
if (reader.getLength() < shaka.cea.CeaDecoder.MIN_LENGTH) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
120
123
|
if (reader.readUint8() !== shaka.cea.CeaDecoder.USA_COUNTRY_CODE) {
|
|
121
124
|
return;
|
|
122
125
|
}
|
|
@@ -260,7 +263,7 @@ shaka.cea.CeaDecoder = class {
|
|
|
260
263
|
// Get the correct stream for this caption packet (CC1, ..., CC4)
|
|
261
264
|
const selectedChannel = fieldNum ?
|
|
262
265
|
this.currentField2Channel_ : this.currentField1Channel_;
|
|
263
|
-
const selectedMode = `CC${(fieldNum << 1) | selectedChannel + 1}`;
|
|
266
|
+
const selectedMode = `CC${((fieldNum << 1) | selectedChannel) + 1}`;
|
|
264
267
|
const selectedStream = this.cea608ModeToStream_.get(selectedMode);
|
|
265
268
|
|
|
266
269
|
// Check for bad frames (bad pairs). This can be two 0xff, two 0x00, or any
|
|
@@ -402,3 +405,10 @@ shaka.cea.CeaDecoder.NTSC_CC_FIELD_2 = 1;
|
|
|
402
405
|
* @private @const {number}
|
|
403
406
|
*/
|
|
404
407
|
shaka.cea.CeaDecoder.USA_COUNTRY_CODE = 0xb5;
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Caption packet min length
|
|
411
|
+
* Country Code + ATSC_PROVIDER_CODE + ATSC_1_USER_IDENTIFIER + USER_DATA_TYPE
|
|
412
|
+
* @private @const {number}
|
|
413
|
+
*/
|
|
414
|
+
shaka.cea.CeaDecoder.MIN_LENGTH = 8;
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -213,6 +213,33 @@ shaka.dash.DashParser = class {
|
|
|
213
213
|
// No-op
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
/**
|
|
217
|
+
* @override
|
|
218
|
+
* @exportInterface
|
|
219
|
+
*/
|
|
220
|
+
onInitialVariantChosen(variant) {
|
|
221
|
+
// For live it is necessary that the first time we update the manifest with
|
|
222
|
+
// a shorter time than indicated to take into account that the last segment
|
|
223
|
+
// added could be halfway, for example
|
|
224
|
+
if (this.manifest_ && this.manifest_.presentationTimeline.isLive()) {
|
|
225
|
+
const stream = variant.video || variant.audio;
|
|
226
|
+
if (stream && stream.segmentIndex) {
|
|
227
|
+
const availabilityEnd =
|
|
228
|
+
this.manifest_.presentationTimeline.getSegmentAvailabilityEnd();
|
|
229
|
+
const position = stream.segmentIndex.find(availabilityEnd);
|
|
230
|
+
if (position == null) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const reference = stream.segmentIndex.get(position);
|
|
234
|
+
if (!reference) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this.updatePeriod_ = reference.endTime - availabilityEnd;
|
|
238
|
+
this.setUpdateTimer_(/* offset= */ 0);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
216
243
|
/**
|
|
217
244
|
* Makes a network request for the manifest and parses the resulting data.
|
|
218
245
|
*
|
|
@@ -242,7 +269,8 @@ shaka.dash.DashParser = class {
|
|
|
242
269
|
|
|
243
270
|
// For redirections add the response uri to the first entry in the
|
|
244
271
|
// Manifest Uris array.
|
|
245
|
-
if (response.uri &&
|
|
272
|
+
if (response.uri && response.uri != response.originalUri &&
|
|
273
|
+
!this.manifestUris_.includes(response.uri)) {
|
|
246
274
|
this.manifestUris_.unshift(response.uri);
|
|
247
275
|
}
|
|
248
276
|
|
|
@@ -489,6 +517,12 @@ shaka.dash.DashParser = class {
|
|
|
489
517
|
|
|
490
518
|
await this.periodCombiner_.combinePeriods(periods, context.dynamic);
|
|
491
519
|
|
|
520
|
+
// Set minBufferTime to 0 for low-latency DASH live stream to achieve the
|
|
521
|
+
// best latency
|
|
522
|
+
if (this.lowLatencyMode_) {
|
|
523
|
+
minBufferTime = 0;
|
|
524
|
+
}
|
|
525
|
+
|
|
492
526
|
// These steps are not done on manifest update.
|
|
493
527
|
if (!this.manifest_) {
|
|
494
528
|
this.manifest_ = {
|
|
@@ -780,40 +814,29 @@ shaka.dash.DashParser = class {
|
|
|
780
814
|
}
|
|
781
815
|
}
|
|
782
816
|
|
|
783
|
-
const
|
|
784
|
-
this.
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const
|
|
788
|
-
this.
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
817
|
+
const audioStreams = this.getStreamsFromSets_(
|
|
818
|
+
this.config_.disableAudio,
|
|
819
|
+
normalAdaptationSets,
|
|
820
|
+
ContentType.AUDIO);
|
|
821
|
+
const videoStreams = this.getStreamsFromSets_(
|
|
822
|
+
this.config_.disableVideo,
|
|
823
|
+
normalAdaptationSets,
|
|
824
|
+
ContentType.VIDEO);
|
|
825
|
+
const textStreams = this.getStreamsFromSets_(
|
|
826
|
+
this.config_.disableText,
|
|
827
|
+
normalAdaptationSets,
|
|
828
|
+
ContentType.TEXT);
|
|
829
|
+
const imageStreams = this.getStreamsFromSets_(
|
|
830
|
+
this.config_.disableThumbnails,
|
|
831
|
+
normalAdaptationSets,
|
|
832
|
+
ContentType.IMAGE);
|
|
833
|
+
|
|
834
|
+
if (videoStreams.length === 0 && audioStreams.length === 0) {
|
|
793
835
|
throw new shaka.util.Error(
|
|
794
836
|
shaka.util.Error.Severity.CRITICAL,
|
|
795
837
|
shaka.util.Error.Category.MANIFEST,
|
|
796
|
-
shaka.util.Error.Code.DASH_EMPTY_PERIOD
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
const audioStreams = [];
|
|
800
|
-
for (const audioSet of audioSets) {
|
|
801
|
-
audioStreams.push(...audioSet.streams);
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
const videoStreams = [];
|
|
805
|
-
for (const videoSet of videoSets) {
|
|
806
|
-
videoStreams.push(...videoSet.streams);
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
const textStreams = [];
|
|
810
|
-
for (const textSet of textSets) {
|
|
811
|
-
textStreams.push(...textSet.streams);
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
const imageStreams = [];
|
|
815
|
-
for (const imageSet of imageSets) {
|
|
816
|
-
imageStreams.push(...imageSet.streams);
|
|
838
|
+
shaka.util.Error.Code.DASH_EMPTY_PERIOD,
|
|
839
|
+
);
|
|
817
840
|
}
|
|
818
841
|
|
|
819
842
|
return {
|
|
@@ -826,15 +849,26 @@ shaka.dash.DashParser = class {
|
|
|
826
849
|
}
|
|
827
850
|
|
|
828
851
|
/**
|
|
852
|
+
* Gets the streams from the given sets or returns an empty array if disabled
|
|
853
|
+
* or no streams are found.
|
|
854
|
+
* @param {boolean} disabled
|
|
829
855
|
* @param {!Array.<!shaka.dash.DashParser.AdaptationInfo>} adaptationSets
|
|
830
|
-
* @param {string}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
856
|
+
* @param {string} contentType
|
|
857
|
+
@private
|
|
858
|
+
*/
|
|
859
|
+
getStreamsFromSets_(disabled, adaptationSets, contentType) {
|
|
860
|
+
if (disabled || !adaptationSets.length) {
|
|
861
|
+
return [];
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
return adaptationSets.reduce((all, part) => {
|
|
865
|
+
if (part.contentType != contentType) {
|
|
866
|
+
return all;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
all.push(...part.streams);
|
|
870
|
+
return all;
|
|
871
|
+
}, []);
|
|
838
872
|
}
|
|
839
873
|
|
|
840
874
|
/**
|
|
@@ -1407,7 +1441,7 @@ shaka.dash.DashParser = class {
|
|
|
1407
1441
|
// NOTE: An updatePeriod_ of -1 means the attribute was missing.
|
|
1408
1442
|
// An attribute which is present and set to 0 should still result in
|
|
1409
1443
|
// periodic updates. For more, see:
|
|
1410
|
-
// https://github.com/
|
|
1444
|
+
// https://github.com/Dash-Industry-Forum/Guidelines-TimingModel/issues/48
|
|
1411
1445
|
if (this.updatePeriod_ < 0) {
|
|
1412
1446
|
return;
|
|
1413
1447
|
}
|
package/lib/dash/mpd_utils.js
CHANGED
|
@@ -310,30 +310,46 @@ shaka.dash.MpdUtils = class {
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
/**
|
|
313
|
-
*
|
|
314
|
-
*
|
|
313
|
+
* Parses common attributes for Representation, AdaptationSet, and Period.
|
|
315
314
|
* @param {shaka.dash.DashParser.Context} context
|
|
316
315
|
* @param {function(?shaka.dash.DashParser.InheritanceFrame):Element} callback
|
|
317
|
-
*
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
*/
|
|
321
|
-
static inheritAttribute(context, callback, attribute) {
|
|
316
|
+
* @return {!Array.<!Element>}
|
|
317
|
+
*/
|
|
318
|
+
static getNodes(context, callback) {
|
|
322
319
|
const Functional = shaka.util.Functional;
|
|
323
320
|
goog.asserts.assert(
|
|
324
321
|
callback(context.representation),
|
|
325
|
-
'There must be at least one element of the given type'
|
|
322
|
+
'There must be at least one element of the given type',
|
|
323
|
+
);
|
|
326
324
|
|
|
327
|
-
|
|
328
|
-
const nodes = [
|
|
325
|
+
return [
|
|
329
326
|
callback(context.representation),
|
|
330
327
|
callback(context.adaptationSet),
|
|
331
328
|
callback(context.period),
|
|
332
329
|
].filter(Functional.isNotNull);
|
|
330
|
+
}
|
|
333
331
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Searches the inheritance for a Segment* with the given attribute.
|
|
334
|
+
*
|
|
335
|
+
* @param {shaka.dash.DashParser.Context} context
|
|
336
|
+
* @param {function(?shaka.dash.DashParser.InheritanceFrame):Element} callback
|
|
337
|
+
* Gets the Element that contains the attribute to inherit.
|
|
338
|
+
* @param {string} attribute
|
|
339
|
+
* @return {?string}
|
|
340
|
+
*/
|
|
341
|
+
static inheritAttribute(context, callback, attribute) {
|
|
342
|
+
const MpdUtils = shaka.dash.MpdUtils;
|
|
343
|
+
const nodes = MpdUtils.getNodes(context, callback);
|
|
344
|
+
|
|
345
|
+
let result = null;
|
|
346
|
+
for (const node of nodes) {
|
|
347
|
+
result = node.getAttribute(attribute);
|
|
348
|
+
if (result) {
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return result;
|
|
337
353
|
}
|
|
338
354
|
|
|
339
355
|
/**
|
|
@@ -346,22 +362,18 @@ shaka.dash.MpdUtils = class {
|
|
|
346
362
|
* @return {Element}
|
|
347
363
|
*/
|
|
348
364
|
static inheritChild(context, callback, child) {
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
callback(context.representation),
|
|
352
|
-
'There must be at least one element of the given type');
|
|
353
|
-
|
|
354
|
-
/** @type {!Array.<!Element>} */
|
|
355
|
-
const nodes = [
|
|
356
|
-
callback(context.representation),
|
|
357
|
-
callback(context.adaptationSet),
|
|
358
|
-
callback(context.period),
|
|
359
|
-
].filter(Functional.isNotNull);
|
|
365
|
+
const MpdUtils = shaka.dash.MpdUtils;
|
|
366
|
+
const nodes = MpdUtils.getNodes(context, callback);
|
|
360
367
|
|
|
361
368
|
const XmlUtils = shaka.util.XmlUtils;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
369
|
+
let result = null;
|
|
370
|
+
for (const node of nodes) {
|
|
371
|
+
result = XmlUtils.findChild(node, child);
|
|
372
|
+
if (result) {
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return result;
|
|
365
377
|
}
|
|
366
378
|
|
|
367
379
|
/**
|