shaka-player 3.2.18 → 3.2.20
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/workflows/build-and-test.yaml +4 -4
- package/.github/workflows/demo-version-index.yaml +6 -0
- package/.github/workflows/selenium-lab-tests.yaml +72 -11
- package/.github/workflows/update-screenshots.yaml +142 -0
- package/CHANGELOG.md +38 -0
- package/demo/common/asset.js +15 -0
- package/demo/common/assets.js +4 -2
- package/demo/common/message_ids.js +1 -0
- package/demo/custom.js +19 -0
- package/demo/locales/en.json +1 -0
- package/demo/locales/source.json +4 -0
- package/demo/main.js +14 -0
- package/dist/demo.compiled.debug.js +150 -148
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +150 -148
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +1 -1
- package/dist/locales.js +29 -29
- package/dist/receiver.compiled.debug.js +19 -19
- package/dist/receiver.compiled.debug.map +2 -2
- package/dist/receiver.compiled.js +19 -19
- package/dist/receiver.compiled.map +2 -2
- package/dist/shaka-player.compiled.d.ts +12 -0
- package/dist/shaka-player.compiled.debug.d.ts +12 -0
- package/dist/shaka-player.compiled.debug.externs.js +4 -0
- package/dist/shaka-player.compiled.debug.js +102 -97
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +4 -0
- package/dist/shaka-player.compiled.js +192 -188
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +12 -0
- package/dist/shaka-player.ui.debug.d.ts +12 -0
- package/dist/shaka-player.ui.debug.externs.js +4 -0
- package/dist/shaka-player.ui.debug.js +116 -111
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +4 -0
- package/dist/shaka-player.ui.js +213 -209
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/errors.md +94 -0
- package/docs/tutorials/index.json +2 -0
- package/docs/tutorials/widevine-service-certs.md +45 -0
- package/externs/ima.js +9 -0
- package/externs/shaka/text.js +7 -0
- package/lib/ads/client_side_ad_manager.js +6 -3
- package/lib/dash/segment_template.js +17 -5
- package/lib/hls/hls_parser.js +3 -1
- package/lib/media/transmuxer.js +13 -7
- package/lib/media/video_wrapper.js +3 -3
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/player.js +3 -1
- package/lib/polyfill/media_capabilities.js +3 -8
- package/lib/polyfill/mediasource.js +7 -2
- package/lib/text/cue.js +6 -0
- package/lib/text/ui_text_displayer.js +2 -5
- package/lib/text/vtt_text_parser.js +257 -93
- package/lib/util/mime_utils.js +1 -1
- package/lib/util/platform.js +8 -0
- package/lib/util/stream_utils.js +26 -14
- package/package.json +1 -1
- package/support.html +1 -0
- package/test/dash/dash_parser_manifest_unit.js +0 -36
- package/test/polyfill/media_capabilities_unit.js +20 -22
- package/test/test/util/layout_tests.js +433 -0
- package/test/test/util/util.js +0 -120
- package/test/{ui → text}/text_displayer_layout_unit.js +59 -235
- package/test/text/ui_text_displayer_unit.js +2 -4
- package/test/text/vtt_text_parser_unit.js +151 -6
- package/test/text/web_vtt_layout_integration.js +525 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Error Handling
|
|
2
|
+
|
|
3
|
+
The basics for handling native Error and {@link shaka.util.Error} thrown by Shaka.
|
|
4
|
+
|
|
5
|
+
## Listening To and Handling Errors
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
const handleError = (error) => {
|
|
9
|
+
if (error instanceof Error) {
|
|
10
|
+
// shaka crashed with an unhandled native error
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (error.severity === shaka.util.Error.Severity.CRITICAL) {
|
|
14
|
+
// handle fatal error, playback can not continue
|
|
15
|
+
} else {
|
|
16
|
+
// handle non-fatal error, playback can continue
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const player = new shaka.Player(video);
|
|
21
|
+
|
|
22
|
+
// handle errors that occur after load
|
|
23
|
+
player.addEventListener('error', handleError);
|
|
24
|
+
|
|
25
|
+
// there are two options for catching errors that occur during load
|
|
26
|
+
|
|
27
|
+
// it's possible to listen directly on the promise
|
|
28
|
+
player.load(url).catch(handleError);
|
|
29
|
+
|
|
30
|
+
// or to use async/await with a try/catch
|
|
31
|
+
try {
|
|
32
|
+
await player.load(url);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
handleError(e);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Custom Handling of Streaming Errors
|
|
39
|
+
|
|
40
|
+
The `streaming.failureCallback` property of {@link shaka.extern.PlayerConfiguration} can be used to add custom handling or error conversion of errors that occur during streaming.
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
player.configure('streaming.failureCallback', (error) => {
|
|
44
|
+
if (error.severity === shaka.util.Error.Severity.CRITICAL) {
|
|
45
|
+
// custom handling of critical error
|
|
46
|
+
// e.g. player.retryStreaming();
|
|
47
|
+
} else {
|
|
48
|
+
// custom handling of recoverable error
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Custom Handling of Retries
|
|
54
|
+
|
|
55
|
+
When configuring retry parameters in Shaka there may be known error codes that should not be retried, or the need to break out of an infinite retry loop in a live context. Retries for failed network requests are not reported as `RECOVERABLE` errors.
|
|
56
|
+
|
|
57
|
+
For example, if a VOD manifest is missing, unlike when a LIVE manifest is missing, it can be expected to not show up and there is no need to retry.
|
|
58
|
+
|
|
59
|
+
This is how to convert a retry into a critical error, see {@link shaka.net.NetworkingEngine.RetryEvent} and {@link shaka.util.Error} to decipher how the event can be parsed:
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
const nwEngine = player.getNetworkingEngine();
|
|
63
|
+
|
|
64
|
+
const vodManifestNotFoundHandler = (event /* shaka.net.NetworkingEngine.RetryEvent */) => {
|
|
65
|
+
const code = event.error.code;
|
|
66
|
+
const data = event.error.data;
|
|
67
|
+
|
|
68
|
+
if (code === shaka.util.Error.Code.BAD_HTTP_STATUS) {
|
|
69
|
+
if (
|
|
70
|
+
// each type of error has its own data structure (or none at all), tread with care
|
|
71
|
+
Array.isArray(data) &&
|
|
72
|
+
data[1] === 404 &&
|
|
73
|
+
data[4] === shaka.net.NetworkingEngine.RequestType.MANIFEST
|
|
74
|
+
) {
|
|
75
|
+
// Throwing inside a retry callback will immediately stop retries
|
|
76
|
+
throw error;
|
|
77
|
+
|
|
78
|
+
// A proprietary error code can also be thrown
|
|
79
|
+
// throw new shaka.util.Error(
|
|
80
|
+
// shaka.util.Error.Severity.CRITICAL,
|
|
81
|
+
// shaka.util.Error.Category.NETWORK,
|
|
82
|
+
// 'RECOGNIZABLE_ERROR_MESSAGE'
|
|
83
|
+
// );
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
nwEngine.addEventListener('retry', vodManifestNotFoundHandler);
|
|
89
|
+
|
|
90
|
+
player.addEventListener('load'() => {
|
|
91
|
+
nwEngine.removeEventListener('retry', vodManifestNotFoundHandler);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
```
|
|
@@ -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
|
+
{ "errors": { "title": "Error Handling" } },
|
|
12
13
|
{ "a11y": { "title": "Creating accessible buttons" } },
|
|
13
14
|
{ "ad_monetization": { "title": "Serving ads with our IMA SDK integration" } },
|
|
14
15
|
{ "plugins": { "title": "Plugins and Customizing the Build" } },
|
|
@@ -16,6 +17,7 @@
|
|
|
16
17
|
{ "architecture": { "title": "Architecture Diagrams" } },
|
|
17
18
|
{ "service-worker": { "title": "Service Worker Caching" } },
|
|
18
19
|
{ "offline": { "title": "Offline Storage and Playback" } },
|
|
20
|
+
{ "widevine-service-certs": { "title": "Widevine Service Certificates" } },
|
|
19
21
|
{ "fairplay": { "title": "FairPlay support" } },
|
|
20
22
|
{ "application-level-redirects": { "title": "Application-Level Redirects" } },
|
|
21
23
|
{ "selenium-grid-config": { "title": "Selenium Grid Config" } },
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Widevine Service Certificates
|
|
2
|
+
|
|
3
|
+
With Widevine, you can eliminate one round-trip to your license server or proxy
|
|
4
|
+
per session by preloading a Widevine service certificate. You can either provide
|
|
5
|
+
it directly or set a URI and let Shaka fetch it for you. Do this before calling
|
|
6
|
+
`player.load()`. The values will persist across multiple calls to `load()` on
|
|
7
|
+
the same `shaka.Player` instance.
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
// This is an example of loading the certificate from your site at runtime.
|
|
11
|
+
// You could also choose to bundle it into your JavaScript as a Uint8Array.
|
|
12
|
+
const req = await fetch('https://example.com/service.cert');
|
|
13
|
+
const cert = new Uint8Array(await req.arrayBuffer());
|
|
14
|
+
|
|
15
|
+
// This is the short form for configuration of a certificate:
|
|
16
|
+
player.configure('drm.advanced.com\\.widevine\\.alpha.serverCertificate',
|
|
17
|
+
cert);
|
|
18
|
+
|
|
19
|
+
// This is the long form:
|
|
20
|
+
player.configure({
|
|
21
|
+
drm: {
|
|
22
|
+
advanced: {
|
|
23
|
+
'com.widevine.alpha': {
|
|
24
|
+
'serverCertificate': cert,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
// This is the short form for configuration of a certificate URI:
|
|
32
|
+
player.configure('drm.advanced.com\\.widevine\\.alpha.serverCertificateUri',
|
|
33
|
+
'https://example.com/service.cert');
|
|
34
|
+
|
|
35
|
+
// This is the long form:
|
|
36
|
+
player.configure({
|
|
37
|
+
drm: {
|
|
38
|
+
advanced: {
|
|
39
|
+
'com.widevine.alpha': {
|
|
40
|
+
'serverCertificateUri': 'https://example.com/service.cert',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
```
|
package/externs/ima.js
CHANGED
|
@@ -498,6 +498,15 @@ google.ima.dai.api.StreamRequest.prototype.streamActivityMonitorId;
|
|
|
498
498
|
google.ima.dai.api.StreamRequest.prototype.format;
|
|
499
499
|
|
|
500
500
|
|
|
501
|
+
/**
|
|
502
|
+
* @enum {string}
|
|
503
|
+
*/
|
|
504
|
+
google.ima.dai.api.StreamRequest.StreamFormat = {
|
|
505
|
+
DASH: 'dash',
|
|
506
|
+
HLS: 'hls',
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
|
|
501
510
|
/** @const */
|
|
502
511
|
google.ima.dai.api.VODStreamRequest =
|
|
503
512
|
class extends google.ima.dai.api.StreamRequest {};
|
package/externs/shaka/text.js
CHANGED
|
@@ -297,6 +297,13 @@ shaka.extern.Cue = class {
|
|
|
297
297
|
*/
|
|
298
298
|
this.fontFamily;
|
|
299
299
|
|
|
300
|
+
/**
|
|
301
|
+
* Text shadow color as a CSS text-shadow value.
|
|
302
|
+
* @type {string}
|
|
303
|
+
* @exportDoc
|
|
304
|
+
*/
|
|
305
|
+
this.textShadow = '';
|
|
306
|
+
|
|
300
307
|
/**
|
|
301
308
|
* Text letter spacing as a CSS letter-spacing value.
|
|
302
309
|
* @type {string}
|
|
@@ -79,9 +79,9 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
// Notify the SDK when the video has ended, so it can play post-roll ads.
|
|
82
|
-
this.video_
|
|
82
|
+
this.eventManager_.listen(this.video_, 'ended', () => {
|
|
83
83
|
this.adsLoader_.contentComplete();
|
|
84
|
-
};
|
|
84
|
+
});
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
@@ -401,6 +401,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
401
401
|
shaka.ads.AdManager.AD_STARTED, data));
|
|
402
402
|
this.adContainer_.setAttribute('ad-active', 'true');
|
|
403
403
|
this.video_.pause();
|
|
404
|
+
this.ad_.setVolume(this.video_.muted ? 0 : this.video_.volume);
|
|
404
405
|
}
|
|
405
406
|
|
|
406
407
|
/**
|
|
@@ -411,6 +412,8 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
411
412
|
this.onEvent_(new shaka.util.FakeEvent(shaka.ads.AdManager.AD_STOPPED,
|
|
412
413
|
(new Map()).set('originalEvent', e)));
|
|
413
414
|
this.adContainer_.removeAttribute('ad-active');
|
|
414
|
-
this.video_.
|
|
415
|
+
if (!this.video_.ended) {
|
|
416
|
+
this.video_.play();
|
|
417
|
+
}
|
|
415
418
|
}
|
|
416
419
|
};
|
|
@@ -98,11 +98,23 @@ shaka.dash.SegmentTemplate = class {
|
|
|
98
98
|
const periodEnd = context.periodInfo.duration ?
|
|
99
99
|
context.periodInfo.start + context.periodInfo.duration : Infinity;
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
/* When to fit segments. All refactors should honor/update this table:
|
|
102
|
+
*
|
|
103
|
+
* | dynamic | infinite | last | should | notes |
|
|
104
|
+
* | | period | period | fit | |
|
|
105
|
+
* | ------- | -------- | ------ | ------ | ------------------------- |
|
|
106
|
+
* | F | F | X | T | typical VOD |
|
|
107
|
+
* | F | T | X | X | impossible: infinite VOD |
|
|
108
|
+
* | T | F | F | T | typical live, old period |
|
|
109
|
+
* | T | F | T | F | typical IPR |
|
|
110
|
+
* | T | T | F | X | impossible: old, infinite |
|
|
111
|
+
* | T | T | T | F | typical live, new period |
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
// We never fit the final period of dynamic content, which could be
|
|
115
|
+
// infinite live (with no limit to fit to) or IPR (which would expand the
|
|
116
|
+
// most recent segment to the end of the presentation).
|
|
117
|
+
const shouldFit = !(context.dynamic && context.periodInfo.isLastPeriod);
|
|
106
118
|
|
|
107
119
|
if (segmentIndex) {
|
|
108
120
|
if (shouldFit) {
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -2925,6 +2925,7 @@ shaka.hls.HlsParser.AUDIO_EXTENSIONS_TO_MIME_TYPES_ = {
|
|
|
2925
2925
|
'cmfa': 'audio/mp4',
|
|
2926
2926
|
// MPEG2-TS also uses video/ for audio: https://bit.ly/TsMse
|
|
2927
2927
|
'ts': 'video/mp2t',
|
|
2928
|
+
'tsa': 'video/mp2t',
|
|
2928
2929
|
|
|
2929
2930
|
// Raw formats:
|
|
2930
2931
|
'aac': 'audio/aac',
|
|
@@ -2962,6 +2963,7 @@ shaka.hls.HlsParser.VIDEO_EXTENSIONS_TO_MIME_TYPES_ = {
|
|
|
2962
2963
|
'm4f': 'video/mp4',
|
|
2963
2964
|
'cmfv': 'video/mp4',
|
|
2964
2965
|
'ts': 'video/mp2t',
|
|
2966
|
+
'tsv': 'video/mp2t',
|
|
2965
2967
|
};
|
|
2966
2968
|
|
|
2967
2969
|
|
|
@@ -2976,7 +2978,7 @@ shaka.hls.HlsParser.TEXT_EXTENSIONS_TO_MIME_TYPES_ = {
|
|
|
2976
2978
|
'm4f': 'application/mp4',
|
|
2977
2979
|
'cmft': 'application/mp4',
|
|
2978
2980
|
'vtt': 'text/vtt',
|
|
2979
|
-
'webvtt': '
|
|
2981
|
+
'webvtt': 'text/vtt',
|
|
2980
2982
|
'ttml': 'application/ttml+xml',
|
|
2981
2983
|
};
|
|
2982
2984
|
|
package/lib/media/transmuxer.js
CHANGED
|
@@ -29,9 +29,7 @@ shaka.media.Transmuxer = class {
|
|
|
29
29
|
this.muxjs_ = shaka.dependencies.muxjs();
|
|
30
30
|
|
|
31
31
|
/** @private {muxjs.mp4.Transmuxer} */
|
|
32
|
-
this.muxTransmuxer_ =
|
|
33
|
-
'keepOriginalTimestamps': true,
|
|
34
|
-
});
|
|
32
|
+
this.muxTransmuxer_ = null;
|
|
35
33
|
|
|
36
34
|
/** @private {shaka.util.PublicPromise} */
|
|
37
35
|
this.transmuxPromise_ = null;
|
|
@@ -48,16 +46,22 @@ shaka.media.Transmuxer = class {
|
|
|
48
46
|
/** @private {boolean} */
|
|
49
47
|
this.isTransmuxing_ = false;
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
if (this.muxjs_) {
|
|
50
|
+
this.muxTransmuxer_ = new this.muxjs_.mp4.Transmuxer({
|
|
51
|
+
'keepOriginalTimestamps': true,
|
|
52
|
+
});
|
|
53
|
+
this.muxTransmuxer_.on('data', (segment) => this.onTransmuxed_(segment));
|
|
54
|
+
this.muxTransmuxer_.on('done', () => this.onTransmuxDone_());
|
|
55
|
+
}
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
/**
|
|
57
59
|
* @override
|
|
58
60
|
*/
|
|
59
61
|
destroy() {
|
|
60
|
-
this.muxTransmuxer_
|
|
62
|
+
if (this.muxTransmuxer_) {
|
|
63
|
+
this.muxTransmuxer_.dispose();
|
|
64
|
+
}
|
|
61
65
|
this.muxTransmuxer_ = null;
|
|
62
66
|
return Promise.resolve();
|
|
63
67
|
}
|
|
@@ -156,6 +160,8 @@ shaka.media.Transmuxer = class {
|
|
|
156
160
|
* metadata: !Array.<!Object>}>}
|
|
157
161
|
*/
|
|
158
162
|
transmux(data) {
|
|
163
|
+
goog.asserts.assert(this.muxTransmuxer_,
|
|
164
|
+
'mux.js should be available.');
|
|
159
165
|
goog.asserts.assert(!this.isTransmuxing_,
|
|
160
166
|
'No transmuxing should be in progress.');
|
|
161
167
|
this.isTransmuxing_ = true;
|
|
@@ -135,15 +135,15 @@ shaka.media.VideoWrapper = class {
|
|
|
135
135
|
// calling |Player.load|, meaning that |currentTime| is more meaningful than
|
|
136
136
|
// |startTime|.
|
|
137
137
|
//
|
|
138
|
-
// Seeking to the current time is a work around for Issue 1298
|
|
139
|
-
// do this, the video may get stuck and not play.
|
|
138
|
+
// Seeking to the current time is a work around for Issue 1298 and 4888.
|
|
139
|
+
// If we don't do this, the video may get stuck and not play.
|
|
140
140
|
//
|
|
141
141
|
// TODO: Need further investigation why it happens. Before and after
|
|
142
142
|
// setting the current time, video.readyState is 1, video.paused is true,
|
|
143
143
|
// and video.buffered's TimeRanges length is 0.
|
|
144
144
|
// See: https://github.com/shaka-project/shaka-player/issues/1298
|
|
145
145
|
this.mover_.moveTo(
|
|
146
|
-
this.video_.currentTime == 0 ?
|
|
146
|
+
(!this.video_.currentTime || this.video_.currentTime == 0) ?
|
|
147
147
|
startTime :
|
|
148
148
|
this.video_.currentTime);
|
|
149
149
|
}
|
|
@@ -67,7 +67,7 @@ shaka.offline.indexeddb.StorageMechanism = class {
|
|
|
67
67
|
shaka.util.Error.Category.STORAGE,
|
|
68
68
|
shaka.util.Error.Code.INDEXED_DB_INIT_TIMED_OUT));
|
|
69
69
|
});
|
|
70
|
-
timeOutTimer.tickAfter(
|
|
70
|
+
timeOutTimer.tickAfter(5);
|
|
71
71
|
|
|
72
72
|
const open = window.indexedDB.open(name, version);
|
|
73
73
|
open.onsuccess = (event) => {
|
package/lib/player.js
CHANGED
|
@@ -2297,6 +2297,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2297
2297
|
// goes wrong.
|
|
2298
2298
|
new shaka.util.Timer(resolve).tickAfter(1);
|
|
2299
2299
|
});
|
|
2300
|
+
} else if (textTracks.length > 0) {
|
|
2301
|
+
this.isTextVisible_ = true;
|
|
2300
2302
|
}
|
|
2301
2303
|
|
|
2302
2304
|
// If we have moved on to another piece of content while waiting for
|
|
@@ -6459,7 +6461,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6459
6461
|
* @define {string} A version number taken from git at compile time.
|
|
6460
6462
|
* @export
|
|
6461
6463
|
*/
|
|
6462
|
-
shaka.Player.version = 'v3.2.
|
|
6464
|
+
shaka.Player.version = 'v3.2.20-uncompiled';
|
|
6463
6465
|
|
|
6464
6466
|
// Initialize the deprecation system using the version string we just set
|
|
6465
6467
|
// on the player.
|
|
@@ -8,7 +8,6 @@ goog.provide('shaka.polyfill.MediaCapabilities');
|
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.log');
|
|
10
10
|
goog.require('shaka.polyfill');
|
|
11
|
-
goog.require('shaka.util.Error');
|
|
12
11
|
goog.require('shaka.util.Platform');
|
|
13
12
|
|
|
14
13
|
|
|
@@ -45,6 +44,7 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
45
44
|
!shaka.util.Platform.isWebOS() &&
|
|
46
45
|
!shaka.util.Platform.isTizen() &&
|
|
47
46
|
!shaka.util.Platform.isEOS() &&
|
|
47
|
+
!shaka.util.Platform.isHisense() &&
|
|
48
48
|
navigator.mediaCapabilities) {
|
|
49
49
|
shaka.log.info(
|
|
50
50
|
'MediaCapabilities: Native mediaCapabilities support found.');
|
|
@@ -211,13 +211,8 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
211
211
|
* @private
|
|
212
212
|
*/
|
|
213
213
|
static canCastDisplayType_(videoConfig) {
|
|
214
|
-
if (!(window.cast
|
|
215
|
-
|
|
216
|
-
throw new shaka.util.Error(
|
|
217
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
218
|
-
shaka.util.Error.Category.CAST,
|
|
219
|
-
shaka.util.Error.Code.CAST_API_UNAVAILABLE);
|
|
220
|
-
} else if (!(cast.__platform__ && cast.__platform__.canDisplayType)) {
|
|
214
|
+
if (!(window.cast &&
|
|
215
|
+
cast.__platform__ && cast.__platform__.canDisplayType)) {
|
|
221
216
|
shaka.log.warning('Expected cast APIs to be available! Falling back to ' +
|
|
222
217
|
'MediaSource.isTypeSupported() for type support.');
|
|
223
218
|
return MediaSource.isTypeSupported(videoConfig.contentType);
|
|
@@ -58,14 +58,19 @@ shaka.polyfill.MediaSource = class {
|
|
|
58
58
|
// Offsetting the end of the removal range seems to help.
|
|
59
59
|
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=177884
|
|
60
60
|
shaka.polyfill.MediaSource.patchRemovalRange_();
|
|
61
|
-
} else {
|
|
62
|
-
shaka.log.info('Patching Safari 13 MSE bugs.');
|
|
61
|
+
} else if (safariVersion <= 15) {
|
|
62
|
+
shaka.log.info('Patching Safari 13 & 14 & 15 MSE bugs.');
|
|
63
63
|
// Safari 13 does not correctly implement abort() on SourceBuffer.
|
|
64
64
|
// Calling abort() before appending a segment causes that segment to be
|
|
65
65
|
// incomplete in the buffer.
|
|
66
66
|
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
|
|
67
67
|
shaka.polyfill.MediaSource.stubAbort_();
|
|
68
68
|
}
|
|
69
|
+
} else if (shaka.util.Platform.isEdge()) {
|
|
70
|
+
shaka.log.info('Rejecting TS container.');
|
|
71
|
+
// TS content is broken on Edge in general.
|
|
72
|
+
// See https://github.com/shaka-project/shaka-player/issues/4955
|
|
73
|
+
shaka.polyfill.MediaSource.rejectTsContent_();
|
|
69
74
|
} else if (shaka.util.Platform.isTizen2() ||
|
|
70
75
|
shaka.util.Platform.isTizen3() ||
|
|
71
76
|
shaka.util.Platform.isTizen4()) {
|
package/lib/text/cue.js
CHANGED
|
@@ -480,6 +480,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
480
480
|
wrapper = shaka.util.Dom.createHTMLElement('span');
|
|
481
481
|
wrapper.classList.add('shaka-text-wrapper');
|
|
482
482
|
wrapper.style.backgroundColor = cue.backgroundColor;
|
|
483
|
+
wrapper.style.lineHeight = 'normal';
|
|
483
484
|
cueElement.appendChild(wrapper);
|
|
484
485
|
}
|
|
485
486
|
|
|
@@ -529,6 +530,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
529
530
|
style.paddingRight =
|
|
530
531
|
shaka.text.UITextDisplayer.convertLengthValue_(
|
|
531
532
|
cue.linePadding, cue, this.videoContainer_);
|
|
533
|
+
style.textShadow = cue.textShadow;
|
|
532
534
|
|
|
533
535
|
if (cue.backgroundImage) {
|
|
534
536
|
style.backgroundImage = 'url(\'' + cue.backgroundImage + '\')';
|
|
@@ -622,12 +624,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
622
624
|
// TODO: Implement lineAlignment of 'CENTER'.
|
|
623
625
|
if (cue.line != null) {
|
|
624
626
|
if (cue.lineInterpretation == Cue.lineInterpretation.PERCENTAGE) {
|
|
625
|
-
// When setting absolute positioning, you need to set x/y/width/height
|
|
626
|
-
// so the element is positioned correctly. Set these as default and
|
|
627
|
-
// other settings will override them.
|
|
628
627
|
style.position = 'absolute';
|
|
629
|
-
style.left = '0';
|
|
630
|
-
style.top = '0';
|
|
631
628
|
if (cue.writingMode == Cue.writingMode.HORIZONTAL_TOP_TO_BOTTOM) {
|
|
632
629
|
style.width = '100%';
|
|
633
630
|
if (cue.lineAlign == Cue.lineAlign.START) {
|