shaka-player 4.3.7 → 4.3.9
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 +11 -0
- package/.github/workflows/appspot.yaml +39 -0
- package/.github/workflows/build-and-test.yaml +8 -0
- package/.github/workflows/selenium-lab-tests.yaml +3 -2
- package/.github/workflows/update-issues.yaml +1 -0
- package/CHANGELOG.md +44 -0
- package/CONTRIBUTORS +1 -0
- package/demo/custom.js +1 -1
- package/dist/demo.compiled.debug.js +2 -2
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +2 -2
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +2 -2
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +24 -2
- package/dist/shaka-player.compiled.debug.d.ts +24 -2
- package/dist/shaka-player.compiled.debug.js +251 -247
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +796 -793
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +24 -2
- package/dist/shaka-player.ui.debug.d.ts +24 -2
- package/dist/shaka-player.ui.debug.js +289 -286
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +831 -827
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/drm-config.md +9 -6
- package/docs/tutorials/selenium-grid-config.md +60 -8
- package/externs/ima.js +34 -0
- package/externs/shaka/manifest.js +5 -1
- package/externs/shaka/offline.js +5 -1
- package/karma.conf.js +50 -7
- package/lib/abr/simple_abr_manager.js +6 -6
- package/lib/cea/mp4_cea_parser.js +24 -18
- package/lib/dash/dash_parser.js +19 -3
- package/lib/hls/hls_parser.js +24 -4
- package/lib/media/drm_engine.js +14 -8
- package/lib/media/gap_jumping_controller.js +24 -2
- package/lib/media/media_source_engine.js +11 -8
- package/lib/media/playhead.js +11 -0
- package/lib/media/region_observer.js +19 -1
- package/lib/media/streaming_engine.js +41 -21
- package/lib/media/video_wrapper.js +6 -1
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +20 -9
- package/lib/polyfill/abort_controller.js +7 -0
- package/lib/polyfill/orientation.js +34 -7
- package/lib/text/vtt_text_parser.js +3 -1
- package/lib/util/manifest_parser_utils.js +5 -3
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +14 -0
- package/lib/util/stream_utils.js +70 -26
- package/package.json +2 -2
- package/test/cast/cast_utils_unit.js +4 -1
- package/test/cea/mp4_cea_parser_unit.js +28 -5
- package/test/dash/dash_parser_manifest_unit.js +120 -0
- package/test/hls/hls_parser_unit.js +216 -0
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/drm_engine_integration.js +2 -2
- package/test/media/media_source_engine_unit.js +1 -1
- package/test/media/region_observer_unit.js +2 -1
- package/test/media/segment_index_unit.js +3 -3
- package/test/media/streaming_engine_integration.js +14 -11
- package/test/media/streaming_engine_unit.js +26 -2
- package/test/offline/manifest_convert_unit.js +5 -0
- package/test/offline/offline_integration.js +6 -3
- package/test/player_external.js +19 -16
- package/test/player_integration.js +35 -48
- package/test/player_src_equals_integration.js +9 -5
- package/test/test/assets/multiple-trun-init.mp4 +0 -0
- package/test/test/assets/multiple-trun-segment.mp4 +0 -0
- package/test/test/util/fake_demo_main.js +7 -3
- package/test/test/util/layout_tests.js +2 -2
- package/test/test/util/manifest_generator.js +2 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +3 -0
- package/test/test/util/ui_utils.js +9 -2
- package/test/test/util/util.js +6 -27
- package/test/test/util/waiter.js +73 -3
- package/test/ui/ad_ui_unit.js +9 -9
- package/test/util/stream_utils_unit.js +46 -0
- package/ui/range_element.js +5 -0
- package/ui/resolution_selection.js +7 -1
|
@@ -59,15 +59,18 @@ If this is the only `<ContentProtection>` element in the manifest, Shaka will
|
|
|
59
59
|
try all key systems it knows. (Based on keySystemsByURI in
|
|
60
60
|
{@linksource shaka.extern.DashManifestConfiguration}.)
|
|
61
61
|
|
|
62
|
-
Through `player.configure()`, you can
|
|
62
|
+
Through `player.configure()`, you can update the dash key systems mapping by
|
|
63
63
|
scheme URI:
|
|
64
|
+
|
|
64
65
|
```js
|
|
65
66
|
player.configure({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
manifest: {
|
|
68
|
+
dash: {
|
|
69
|
+
keySystemsByURI: {
|
|
70
|
+
'urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95': 'com.microsoft.playready.recommendation',
|
|
71
|
+
'urn:uuid:79f0049a-4098-8642-ab92-e65be0885f95': 'com.microsoft.playready.recommendation',
|
|
72
|
+
}
|
|
73
|
+
}
|
|
71
74
|
}
|
|
72
75
|
});
|
|
73
76
|
```
|
|
@@ -47,17 +47,20 @@ vars:
|
|
|
47
47
|
FirefoxMac:
|
|
48
48
|
browser: firefox
|
|
49
49
|
os: Mac
|
|
50
|
-
|
|
50
|
+
extra_configs:
|
|
51
|
+
- *firefox_config
|
|
51
52
|
|
|
52
53
|
FirefoxWindows:
|
|
53
54
|
browser: firefox
|
|
54
55
|
os: Windows
|
|
55
|
-
|
|
56
|
+
extra_configs:
|
|
57
|
+
- *firefox_config
|
|
56
58
|
|
|
57
59
|
FirefoxLinux:
|
|
58
60
|
browser: firefox
|
|
59
61
|
os: Linux
|
|
60
|
-
|
|
62
|
+
extra_configs:
|
|
63
|
+
- *firefox_config
|
|
61
64
|
```
|
|
62
65
|
|
|
63
66
|
### Browsers
|
|
@@ -75,8 +78,8 @@ browser made available to Karma. Within each of those keys are the following:
|
|
|
75
78
|
and must match the string and case used in the Selenium node config.
|
|
76
79
|
- `disabled` (optional): If true, this browser is disabled and will not be
|
|
77
80
|
used unless explicitly requested.
|
|
78
|
-
- `
|
|
79
|
-
merged with the WebDriver launcher config in Karma.
|
|
81
|
+
- `extra_configs` (optional): An array of dictionaries of extra configs which
|
|
82
|
+
will be merged with the WebDriver launcher config in Karma.
|
|
80
83
|
|
|
81
84
|
Examples of basic desktop browsers definitions:
|
|
82
85
|
|
|
@@ -96,9 +99,9 @@ Safari:
|
|
|
96
99
|
SafariTP:
|
|
97
100
|
browser: safari
|
|
98
101
|
os: Mac
|
|
99
|
-
|
|
100
|
-
safari.options:
|
|
101
|
-
|
|
102
|
+
extra_configs:
|
|
103
|
+
- safari.options:
|
|
104
|
+
technologyPreview: true
|
|
102
105
|
|
|
103
106
|
ChromeWindows:
|
|
104
107
|
browser: chrome
|
|
@@ -120,3 +123,52 @@ FirefoxLinux:
|
|
|
120
123
|
browser: firefox
|
|
121
124
|
os: Linux
|
|
122
125
|
```
|
|
126
|
+
|
|
127
|
+
### Composing configs
|
|
128
|
+
|
|
129
|
+
You can define variables for browser configs that can be composed together in
|
|
130
|
+
`extra_configs`. For example, below you will see some basic definitions for
|
|
131
|
+
Chrome arguments and parameters, and then an additional config with an argument
|
|
132
|
+
that is only needed for some platforms. `karma.conf.js` will merge those
|
|
133
|
+
argument lists intelligently when it loads the YAML config.
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
vars:
|
|
137
|
+
basic_chrome_config: &basic_chrome_config
|
|
138
|
+
goog:chromeOptions:
|
|
139
|
+
args:
|
|
140
|
+
# Normally, Chrome disallows autoplaying videos in many cases. Enable
|
|
141
|
+
# it for testing.
|
|
142
|
+
- "--autoplay-policy=no-user-gesture-required"
|
|
143
|
+
|
|
144
|
+
# Instruct chromedriver not to disable component updater.
|
|
145
|
+
excludeSwitches:
|
|
146
|
+
- "disable-component-update"
|
|
147
|
+
|
|
148
|
+
headless_chrome_config: &headless_chrome_config
|
|
149
|
+
goog:chromeOptions:
|
|
150
|
+
args:
|
|
151
|
+
# Run in headless mode.
|
|
152
|
+
- "--headless"
|
|
153
|
+
|
|
154
|
+
ChromeLinux:
|
|
155
|
+
browser: chrome
|
|
156
|
+
os: Mac
|
|
157
|
+
extra_configs:
|
|
158
|
+
- *basic_chrome_config
|
|
159
|
+
|
|
160
|
+
ChromeWindows:
|
|
161
|
+
browser: chrome
|
|
162
|
+
os: Mac
|
|
163
|
+
extra_configs:
|
|
164
|
+
- *basic_chrome_config
|
|
165
|
+
|
|
166
|
+
ChromeMac:
|
|
167
|
+
browser: chrome
|
|
168
|
+
os: Mac
|
|
169
|
+
# Take the parameters and arguments for basic_chrome_config, then append the
|
|
170
|
+
# arguments for headless_chrome_config.
|
|
171
|
+
extra_configs:
|
|
172
|
+
- *basic_chrome_config
|
|
173
|
+
- *headless_chrome_config
|
|
174
|
+
```
|
package/externs/ima.js
CHANGED
|
@@ -513,6 +513,14 @@ google.ima.dai.api.StreamRequest.prototype.streamActivityMonitorId;
|
|
|
513
513
|
google.ima.dai.api.StreamRequest.prototype.format;
|
|
514
514
|
|
|
515
515
|
|
|
516
|
+
/**
|
|
517
|
+
* @type {Object.<
|
|
518
|
+
* google.ima.dai.api.OmidVerificationVendor,
|
|
519
|
+
* (google.ima.dai.api.OmidAccessMode | undefined)>}
|
|
520
|
+
*/
|
|
521
|
+
google.ima.dai.api.StreamRequest.prototype.omidAccessModeRules;
|
|
522
|
+
|
|
523
|
+
|
|
516
524
|
/**
|
|
517
525
|
* @enum {string}
|
|
518
526
|
*/
|
|
@@ -599,3 +607,29 @@ google.ima.dai.api.StreamEvent.Type = {
|
|
|
599
607
|
SKIPPED: 'skip',
|
|
600
608
|
VIDEO_CLICKED: 'videoClicked',
|
|
601
609
|
};
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* @enum {number}
|
|
614
|
+
*/
|
|
615
|
+
google.ima.dai.api.OmidVerificationVendor = {
|
|
616
|
+
OTHER: 1,
|
|
617
|
+
MOAT: 2,
|
|
618
|
+
DOUBLEVERIFY: 3,
|
|
619
|
+
INTEGRAL_AD_SCIENCE: 4,
|
|
620
|
+
PIXELATE: 5,
|
|
621
|
+
NIELSEN: 6,
|
|
622
|
+
COMSCORE: 7,
|
|
623
|
+
MEETRICS: 8,
|
|
624
|
+
GOOGLE: 9,
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* @enum {string}
|
|
630
|
+
*/
|
|
631
|
+
google.ima.dai.api.OmidAccessMode = {
|
|
632
|
+
FULL: 'full',
|
|
633
|
+
DOMAIN: 'domain',
|
|
634
|
+
LIMITED: 'limited',
|
|
635
|
+
};
|
|
@@ -321,7 +321,8 @@ shaka.extern.FetchCryptoKeysFunction;
|
|
|
321
321
|
* tilesLayout: (string|undefined),
|
|
322
322
|
* matchedStreams:
|
|
323
323
|
* (!Array.<shaka.extern.Stream>|!Array.<shaka.extern.StreamDB>|
|
|
324
|
-
* undefined)
|
|
324
|
+
* undefined),
|
|
325
|
+
* external: boolean
|
|
325
326
|
* }}
|
|
326
327
|
*
|
|
327
328
|
* @description
|
|
@@ -434,6 +435,9 @@ shaka.extern.FetchCryptoKeysFunction;
|
|
|
434
435
|
* @property {(!Array.<shaka.extern.Stream>|!Array.<shaka.extern.StreamDB>|
|
|
435
436
|
* undefined)} matchedStreams
|
|
436
437
|
* The streams in all periods which match the stream. Used for Dash.
|
|
438
|
+
* @property {boolean} external
|
|
439
|
+
* Indicate if the stream was added externally.
|
|
440
|
+
* Eg: external text tracks.
|
|
437
441
|
*
|
|
438
442
|
* @exportDoc
|
|
439
443
|
*/
|
package/externs/shaka/offline.js
CHANGED
|
@@ -132,7 +132,8 @@ shaka.extern.ManifestDB;
|
|
|
132
132
|
* audioSamplingRate: ?number,
|
|
133
133
|
* spatialAudio: boolean,
|
|
134
134
|
* closedCaptions: Map.<string, string>,
|
|
135
|
-
* tilesLayout: (string|undefined)
|
|
135
|
+
* tilesLayout: (string|undefined),
|
|
136
|
+
* external: boolean
|
|
136
137
|
* }}
|
|
137
138
|
*
|
|
138
139
|
* @property {number} id
|
|
@@ -193,6 +194,9 @@ shaka.extern.ManifestDB;
|
|
|
193
194
|
* The value is a grid-item-dimension consisting of two positive decimal
|
|
194
195
|
* integers in the format: column-x-row ('4x3'). It describes the arrangement
|
|
195
196
|
* of Images in a Grid. The minimum valid LAYOUT is '1x1'.
|
|
197
|
+
* @property {boolean} external
|
|
198
|
+
* Indicate if the stream was added externally.
|
|
199
|
+
* Eg: external text tracks.
|
|
196
200
|
*/
|
|
197
201
|
shaka.extern.StreamDB;
|
|
198
202
|
|
package/karma.conf.js
CHANGED
|
@@ -7,9 +7,11 @@
|
|
|
7
7
|
// Karma configuration
|
|
8
8
|
// Install required modules by running "npm install"
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// lodash is an indirect dependency, depended on by Karma
|
|
11
|
+
const _ = require('lodash');
|
|
11
12
|
const fs = require('fs');
|
|
12
13
|
const glob = require('glob');
|
|
14
|
+
const Jimp = require('jimp');
|
|
13
15
|
const path = require('path');
|
|
14
16
|
const rimraf = require('rimraf');
|
|
15
17
|
const {ssim} = require('ssim.js');
|
|
@@ -17,6 +19,32 @@ const util = require('karma/common/util');
|
|
|
17
19
|
const which = require('which');
|
|
18
20
|
const yaml = require('js-yaml');
|
|
19
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Like Object.assign, but recursive and doesn't clobber objects and arrays.
|
|
24
|
+
* If two arrays are merged, they are concatenated.
|
|
25
|
+
* Ex:
|
|
26
|
+
* mergeConfigs({ foo: 'bar', args: [1, 2, 3] },
|
|
27
|
+
* { baz: 'blah', args: [4, 5, 6] })
|
|
28
|
+
* => { foo: 'bar', baz: 'blah', args: [1, 2, 3, 4, 5, 6] }
|
|
29
|
+
*
|
|
30
|
+
* @param {Object} first
|
|
31
|
+
* @param {Object} second
|
|
32
|
+
* @return {Object}
|
|
33
|
+
*/
|
|
34
|
+
function mergeConfigs(first, second) {
|
|
35
|
+
return _.mergeWith(
|
|
36
|
+
first,
|
|
37
|
+
second,
|
|
38
|
+
(firstValue, secondValue) => {
|
|
39
|
+
// Merge arrays by concatenation.
|
|
40
|
+
if (Array.isArray(firstValue)) {
|
|
41
|
+
return firstValue.concat(secondValue);
|
|
42
|
+
}
|
|
43
|
+
// Use lodash's default merge behavior for everything else.
|
|
44
|
+
return undefined;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
20
48
|
/**
|
|
21
49
|
* @param {Object} config
|
|
22
50
|
*/
|
|
@@ -78,7 +106,7 @@ module.exports = (config) => {
|
|
|
78
106
|
}
|
|
79
107
|
|
|
80
108
|
// Add standard WebDriver configs.
|
|
81
|
-
|
|
109
|
+
mergeConfigs(launcher, {
|
|
82
110
|
base: 'WebDriver',
|
|
83
111
|
config: {hostname: gridHostname, port: gridPort},
|
|
84
112
|
pseudoActivityInterval: 20000,
|
|
@@ -87,8 +115,10 @@ module.exports = (config) => {
|
|
|
87
115
|
version: metadata.version,
|
|
88
116
|
});
|
|
89
117
|
|
|
90
|
-
if (metadata.
|
|
91
|
-
|
|
118
|
+
if (metadata.extra_configs) {
|
|
119
|
+
for (const config of metadata.extra_configs) {
|
|
120
|
+
mergeConfigs(launcher, config);
|
|
121
|
+
}
|
|
92
122
|
}
|
|
93
123
|
}
|
|
94
124
|
|
|
@@ -603,15 +633,27 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
|
|
|
603
633
|
}
|
|
604
634
|
|
|
605
635
|
/**
|
|
636
|
+
* @param {karma.Launcher.Browser.spec} spec
|
|
606
637
|
* @param {wd.remote} webDriverClient A WebDriver client, an object from the
|
|
607
638
|
* "wd" package, created by "wd.remote()".
|
|
608
639
|
* @return {!Promise.<!Buffer>} A Buffer containing a PNG screenshot
|
|
609
640
|
*/
|
|
610
|
-
function getScreenshot(webDriverClient) {
|
|
641
|
+
function getScreenshot(spec, webDriverClient) {
|
|
611
642
|
return new Promise((resolve, reject) => {
|
|
612
643
|
webDriverClient.takeScreenshot((error, pngBase64) => {
|
|
613
644
|
if (error) {
|
|
614
645
|
reject(error);
|
|
646
|
+
} else if (pngBase64.error) {
|
|
647
|
+
// In some failure cases, pngBase64 is an object with "error",
|
|
648
|
+
// "message", and "stacktrace" fields. This happens, for example,
|
|
649
|
+
// with a timeout from the screenshot command. This is not an
|
|
650
|
+
// expected situation, so log it. The extra newlines keep this from
|
|
651
|
+
// being overwritten on the terminal when running tests against many
|
|
652
|
+
// browsers at once.
|
|
653
|
+
console.log('\n\nUnexpected screenshot failure:\n' +
|
|
654
|
+
` Error: ${JSON.stringify(pngBase64)}\n` +
|
|
655
|
+
` WebDriver spec: ${JSON.stringify(spec)}\n\n\n`);
|
|
656
|
+
reject(pngBase64);
|
|
615
657
|
} else {
|
|
616
658
|
// Convert the screenshot to a binary buffer.
|
|
617
659
|
resolve(Buffer.from(pngBase64, 'base64'));
|
|
@@ -635,7 +677,8 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
|
|
|
635
677
|
}
|
|
636
678
|
|
|
637
679
|
/** @type {!Buffer} */
|
|
638
|
-
const fullPageScreenshotData =
|
|
680
|
+
const fullPageScreenshotData =
|
|
681
|
+
await getScreenshot(browser.spec, webDriverClient);
|
|
639
682
|
|
|
640
683
|
// Crop the screenshot to the dimensions specified in the test.
|
|
641
684
|
// Jimp is picky about types, so convert these strings to numbers.
|
|
@@ -754,7 +797,7 @@ function WebDriverScreenshotMiddlewareFactory(launcher) {
|
|
|
754
797
|
// The result is cached for the sake of performance.
|
|
755
798
|
if (webDriverClient.canTakeScreenshot === undefined) {
|
|
756
799
|
try {
|
|
757
|
-
await getScreenshot(webDriverClient);
|
|
800
|
+
await getScreenshot(browser.spec, webDriverClient);
|
|
758
801
|
webDriverClient.canTakeScreenshot = true;
|
|
759
802
|
} catch (error) {
|
|
760
803
|
webDriverClient.canTakeScreenshot = false;
|
|
@@ -48,13 +48,16 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
48
48
|
/** @private {shaka.abr.EwmaBandwidthEstimator} */
|
|
49
49
|
this.bandwidthEstimator_ = new shaka.abr.EwmaBandwidthEstimator();
|
|
50
50
|
|
|
51
|
+
/** @private {?function():void} */
|
|
52
|
+
this.onNetworkInformationChange_ = null;
|
|
53
|
+
|
|
51
54
|
// Some browsers implement the Network Information API, which allows
|
|
52
55
|
// retrieving information about a user's network connection. We listen
|
|
53
56
|
// to the change event to be able to make quick changes in case the type
|
|
54
57
|
// of connectivity changes.
|
|
55
58
|
if (navigator.connection && navigator.connection.addEventListener) {
|
|
56
59
|
this.onNetworkInformationChange_ = () => {
|
|
57
|
-
if (this.
|
|
60
|
+
if (this.enabled_ && this.config_.useNetworkInformation) {
|
|
58
61
|
this.bandwidthEstimator_ = new shaka.abr.EwmaBandwidthEstimator();
|
|
59
62
|
if (this.config_) {
|
|
60
63
|
this.bandwidthEstimator_.configure(this.config_.advanced);
|
|
@@ -98,9 +101,6 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
98
101
|
/** @private {ResizeObserver} */
|
|
99
102
|
this.resizeObserver_ = null;
|
|
100
103
|
|
|
101
|
-
/** @private {?function():void} */
|
|
102
|
-
this.onNetworkInformationChange_ = null;
|
|
103
|
-
|
|
104
104
|
/** @private {shaka.util.Timer} */
|
|
105
105
|
this.resizeObserverTimer_ = new shaka.util.Timer(() => {
|
|
106
106
|
if (this.config_.restrictToElementSize) {
|
|
@@ -182,8 +182,8 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
182
182
|
if (this.resizeObserver_ && this.config_.restrictToElementSize) {
|
|
183
183
|
const devicePixelRatio =
|
|
184
184
|
this.config_.ignoreDevicePixelRatio ? 1 : window.devicePixelRatio;
|
|
185
|
-
maxHeight = this.mediaElement_.
|
|
186
|
-
maxWidth = this.mediaElement_.
|
|
185
|
+
maxHeight = this.mediaElement_.clientHeight * devicePixelRatio;
|
|
186
|
+
maxWidth = this.mediaElement_.clientWidth * devicePixelRatio;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// Get sorted Variants.
|
|
@@ -163,15 +163,17 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
163
163
|
// Fields that are found in MOOF boxes
|
|
164
164
|
let defaultSampleDuration = this.defaultSampleDuration_;
|
|
165
165
|
let defaultSampleSize = this.defaultSampleSize_;
|
|
166
|
-
let
|
|
167
|
-
|
|
168
|
-
let
|
|
166
|
+
let moofOffset = 0;
|
|
167
|
+
/** @type {!Array<shaka.util.ParsedTRUNBox>} */
|
|
168
|
+
let parsedTRUNs = [];
|
|
169
169
|
let baseMediaDecodeTime = null;
|
|
170
170
|
let timescale = shaka.cea.ICeaParser.DEFAULT_TIMESCALE_VALUE;
|
|
171
171
|
|
|
172
172
|
new Mp4Parser()
|
|
173
173
|
.box('moof', (box) => {
|
|
174
174
|
moofOffset = box.start;
|
|
175
|
+
// trun box parsing is reset on each moof.
|
|
176
|
+
parsedTRUNs = [];
|
|
175
177
|
Mp4Parser.children(box);
|
|
176
178
|
})
|
|
177
179
|
.box('traf', Mp4Parser.children)
|
|
@@ -182,11 +184,8 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
182
184
|
|
|
183
185
|
const parsedTRUN = shaka.util.Mp4BoxParsers.parseTRUN(
|
|
184
186
|
box.reader, box.version, box.flags);
|
|
185
|
-
|
|
186
|
-
sampleData = parsedTRUN.sampleData;
|
|
187
|
-
trunOffset = parsedTRUN.dataOffset;
|
|
187
|
+
parsedTRUNs.push(parsedTRUN);
|
|
188
188
|
})
|
|
189
|
-
|
|
190
189
|
.fullBox('tfhd', (box) => {
|
|
191
190
|
goog.asserts.assert(
|
|
192
191
|
box.flags != null,
|
|
@@ -210,7 +209,6 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
210
209
|
timescale = this.trackIdToTimescale_.get(trackId);
|
|
211
210
|
}
|
|
212
211
|
})
|
|
213
|
-
|
|
214
212
|
.fullBox('tfdt', (box) => {
|
|
215
213
|
goog.asserts.assert(
|
|
216
214
|
box.version != null,
|
|
@@ -223,16 +221,19 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
223
221
|
})
|
|
224
222
|
.box('mdat', (box) => {
|
|
225
223
|
if (baseMediaDecodeTime === null) {
|
|
226
|
-
// This field should have been populated by
|
|
227
|
-
//
|
|
224
|
+
// This field should have been populated by the Base Media Decode
|
|
225
|
+
// Time in the tfdt box.
|
|
226
|
+
shaka.log.alwaysWarn(
|
|
227
|
+
'Unable to find base media decode time for CEA captions!');
|
|
228
228
|
throw new shaka.util.Error(
|
|
229
229
|
shaka.util.Error.Severity.CRITICAL,
|
|
230
230
|
shaka.util.Error.Category.TEXT,
|
|
231
231
|
shaka.util.Error.Code.INVALID_MP4_CEA);
|
|
232
232
|
}
|
|
233
|
-
|
|
233
|
+
|
|
234
|
+
const offset = moofOffset - box.start - 8;
|
|
234
235
|
this.parseMdat_(box.reader, baseMediaDecodeTime, timescale,
|
|
235
|
-
defaultSampleDuration, defaultSampleSize, offset,
|
|
236
|
+
defaultSampleDuration, defaultSampleSize, offset, parsedTRUNs,
|
|
236
237
|
captionPackets);
|
|
237
238
|
})
|
|
238
239
|
.parse(mediaSegment, /* partialOkay= */ false);
|
|
@@ -248,12 +249,12 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
248
249
|
* @param {number} defaultSampleDuration
|
|
249
250
|
* @param {number} defaultSampleSize
|
|
250
251
|
* @param {number} offset
|
|
251
|
-
* @param {!Array<shaka.util.
|
|
252
|
+
* @param {!Array<shaka.util.ParsedTRUNBox>} parsedTRUNs
|
|
252
253
|
* @param {!Array<!shaka.cea.ICeaParser.CaptionPacket>} captionPackets
|
|
253
254
|
* @private
|
|
254
255
|
*/
|
|
255
256
|
parseMdat_(reader, time, timescale, defaultSampleDuration,
|
|
256
|
-
defaultSampleSize, offset,
|
|
257
|
+
defaultSampleSize, offset, parsedTRUNs, captionPackets) {
|
|
257
258
|
const BitstreamFormat = shaka.cea.Mp4CeaParser.BitstreamFormat;
|
|
258
259
|
const ICeaParser = shaka.cea.ICeaParser;
|
|
259
260
|
let sampleIndex = 0;
|
|
@@ -264,11 +265,16 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
264
265
|
// composition time offset, we default to 0.
|
|
265
266
|
let sampleSize = defaultSampleSize;
|
|
266
267
|
|
|
268
|
+
// Combine all sample data. This assumes that the samples described across
|
|
269
|
+
// multiple trun boxes are still continuous in the mdat box.
|
|
270
|
+
const sampleDatas = parsedTRUNs.map((t) => t.sampleData);
|
|
271
|
+
const sampleData = [].concat(...sampleDatas);
|
|
272
|
+
|
|
267
273
|
if (sampleData.length) {
|
|
268
274
|
sampleSize = sampleData[0].sampleSize || defaultSampleSize;
|
|
269
275
|
}
|
|
270
276
|
|
|
271
|
-
reader.skip(offset);
|
|
277
|
+
reader.skip(offset + parsedTRUNs[0].dataOffset);
|
|
272
278
|
|
|
273
279
|
while (reader.hasMoreData()) {
|
|
274
280
|
const naluSize = reader.readUint32();
|
|
@@ -301,7 +307,7 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
301
307
|
if (isSeiMessage) {
|
|
302
308
|
let timeOffset = 0;
|
|
303
309
|
|
|
304
|
-
if (sampleData.length
|
|
310
|
+
if (sampleIndex < sampleData.length) {
|
|
305
311
|
timeOffset = sampleData[sampleIndex].sampleCompositionTimeOffset || 0;
|
|
306
312
|
}
|
|
307
313
|
|
|
@@ -324,7 +330,7 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
324
330
|
}
|
|
325
331
|
sampleSize -= (naluSize + 4);
|
|
326
332
|
if (sampleSize == 0) {
|
|
327
|
-
if (sampleData.length
|
|
333
|
+
if (sampleIndex < sampleData.length) {
|
|
328
334
|
time += sampleData[sampleIndex].sampleDuration ||
|
|
329
335
|
defaultSampleDuration;
|
|
330
336
|
} else {
|
|
@@ -333,7 +339,7 @@ shaka.cea.Mp4CeaParser = class {
|
|
|
333
339
|
|
|
334
340
|
sampleIndex++;
|
|
335
341
|
|
|
336
|
-
if (sampleData.length
|
|
342
|
+
if (sampleIndex < sampleData.length) {
|
|
337
343
|
sampleSize = sampleData[sampleIndex].sampleSize || defaultSampleSize;
|
|
338
344
|
} else {
|
|
339
345
|
sampleSize = defaultSampleSize;
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -886,7 +886,19 @@ shaka.dash.DashParser = class {
|
|
|
886
886
|
|
|
887
887
|
// Parallel for HLS VIDEO-RANGE as defined in DASH-IF IOP v4.3 6.2.5.1.
|
|
888
888
|
let videoRange;
|
|
889
|
-
|
|
889
|
+
|
|
890
|
+
// Ref. https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf
|
|
891
|
+
// If signaled, a Supplemental or Essential Property descriptor
|
|
892
|
+
// shall be used, with the schemeIdUri set to
|
|
893
|
+
// urn:mpeg:mpegB:cicp:<Parameter> as defined in
|
|
894
|
+
// ISO/IEC 23001-8 [49] and <Parameter> one of the
|
|
895
|
+
// following: ColourPrimaries, TransferCharacteristics,
|
|
896
|
+
// or MatrixCoefficients.
|
|
897
|
+
const scheme = 'urn:mpeg:mpegB:cicp';
|
|
898
|
+
const transferCharacteristicsScheme = `${scheme}:TransferCharacteristics`;
|
|
899
|
+
const colourPrimariesScheme = `${scheme}:ColourPrimaries`;
|
|
900
|
+
const matrixCoefficientsScheme = `${scheme}:MatrixCoefficients`;
|
|
901
|
+
|
|
890
902
|
const getVideoRangeFromTransferCharacteristicCICP = (cicp) => {
|
|
891
903
|
switch (cicp) {
|
|
892
904
|
case 1:
|
|
@@ -912,10 +924,13 @@ shaka.dash.DashParser = class {
|
|
|
912
924
|
const schemeId = prop.getAttribute('schemeIdUri');
|
|
913
925
|
if (schemeId == 'http://dashif.org/guidelines/trickmode') {
|
|
914
926
|
trickModeFor = prop.getAttribute('value');
|
|
915
|
-
} else if (schemeId ==
|
|
927
|
+
} else if (schemeId == transferCharacteristicsScheme) {
|
|
916
928
|
videoRange = getVideoRangeFromTransferCharacteristicCICP(
|
|
917
929
|
parseInt(prop.getAttribute('value'), 10),
|
|
918
930
|
);
|
|
931
|
+
} else if (schemeId == colourPrimariesScheme ||
|
|
932
|
+
schemeId == matrixCoefficientsScheme) {
|
|
933
|
+
continue;
|
|
919
934
|
} else {
|
|
920
935
|
unrecognizedEssentialProperty = true;
|
|
921
936
|
}
|
|
@@ -925,7 +940,7 @@ shaka.dash.DashParser = class {
|
|
|
925
940
|
XmlUtils.findChildren(elem, 'SupplementalProperty');
|
|
926
941
|
for (const prop of supplementalProperties) {
|
|
927
942
|
const schemeId = prop.getAttribute('schemeIdUri');
|
|
928
|
-
if (schemeId ==
|
|
943
|
+
if (schemeId == transferCharacteristicsScheme) {
|
|
929
944
|
videoRange = getVideoRangeFromTransferCharacteristicCICP(
|
|
930
945
|
parseInt(prop.getAttribute('value'), 10),
|
|
931
946
|
);
|
|
@@ -1322,6 +1337,7 @@ shaka.dash.DashParser = class {
|
|
|
1322
1337
|
hdr,
|
|
1323
1338
|
tilesLayout,
|
|
1324
1339
|
matchedStreams: [],
|
|
1340
|
+
external: false,
|
|
1325
1341
|
};
|
|
1326
1342
|
}
|
|
1327
1343
|
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -2066,6 +2066,22 @@ shaka.hls.HlsParser = class {
|
|
|
2066
2066
|
// stream is lazy-loaded.
|
|
2067
2067
|
const mimeType = this.guessMimeTypeBeforeLoading_(type, codecs) ||
|
|
2068
2068
|
this.guessMimeTypeFallback_(type);
|
|
2069
|
+
const roles = [];
|
|
2070
|
+
if (characteristics) {
|
|
2071
|
+
for (const characteristic of characteristics.split(',')) {
|
|
2072
|
+
roles.push(characteristic);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
const kind = (type == shaka.util.ManifestParserUtils.ContentType.TEXT) ?
|
|
2077
|
+
shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE : undefined;
|
|
2078
|
+
|
|
2079
|
+
// If there are no roles, and we have defaulted to the subtitle "kind" for
|
|
2080
|
+
// this track, add the implied subtitle role.
|
|
2081
|
+
if (!roles.length &&
|
|
2082
|
+
kind === shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE) {
|
|
2083
|
+
roles.push(shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE);
|
|
2084
|
+
}
|
|
2069
2085
|
|
|
2070
2086
|
return {
|
|
2071
2087
|
id: this.globalId_++,
|
|
@@ -2074,8 +2090,7 @@ shaka.hls.HlsParser = class {
|
|
|
2074
2090
|
segmentIndex: null,
|
|
2075
2091
|
mimeType,
|
|
2076
2092
|
codecs,
|
|
2077
|
-
kind
|
|
2078
|
-
shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE : undefined,
|
|
2093
|
+
kind,
|
|
2079
2094
|
encrypted: false,
|
|
2080
2095
|
drmInfos: [],
|
|
2081
2096
|
keyIds: new Set(),
|
|
@@ -2091,7 +2106,7 @@ shaka.hls.HlsParser = class {
|
|
|
2091
2106
|
width: undefined,
|
|
2092
2107
|
height: undefined,
|
|
2093
2108
|
bandwidth: undefined,
|
|
2094
|
-
roles
|
|
2109
|
+
roles,
|
|
2095
2110
|
forced,
|
|
2096
2111
|
channelsCount,
|
|
2097
2112
|
audioSamplingRate: null,
|
|
@@ -2099,6 +2114,7 @@ shaka.hls.HlsParser = class {
|
|
|
2099
2114
|
closedCaptions,
|
|
2100
2115
|
hdr: undefined,
|
|
2101
2116
|
tilesLayout: undefined,
|
|
2117
|
+
external: false,
|
|
2102
2118
|
};
|
|
2103
2119
|
}
|
|
2104
2120
|
|
|
@@ -2549,6 +2565,10 @@ shaka.hls.HlsParser = class {
|
|
|
2549
2565
|
// We're interested in the duration part.
|
|
2550
2566
|
const extinfValues = extinfTag.value.split(',');
|
|
2551
2567
|
const duration = Number(extinfValues[0]);
|
|
2568
|
+
// Skip segments without duration
|
|
2569
|
+
if (duration == 0) {
|
|
2570
|
+
return null;
|
|
2571
|
+
}
|
|
2552
2572
|
endTime = startTime + duration;
|
|
2553
2573
|
} else {
|
|
2554
2574
|
endTime = partialSegmentRefs[partialSegmentRefs.length - 1].endTime;
|
|
@@ -2729,9 +2749,9 @@ shaka.hls.HlsParser = class {
|
|
|
2729
2749
|
type,
|
|
2730
2750
|
lastDiscontinuityStartTime,
|
|
2731
2751
|
hlsAes128Key);
|
|
2732
|
-
previousReference = reference;
|
|
2733
2752
|
|
|
2734
2753
|
if (reference) {
|
|
2754
|
+
previousReference = reference;
|
|
2735
2755
|
reference.discontinuitySequence = discontinuitySequence;
|
|
2736
2756
|
|
|
2737
2757
|
if (this.config_.hls.ignoreManifestProgramDateTime &&
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -354,18 +354,24 @@ shaka.media.DrmEngine = class {
|
|
|
354
354
|
shaka.media.DrmEngine.replaceDrmInfo_(variants, servers);
|
|
355
355
|
}
|
|
356
356
|
|
|
357
|
-
|
|
357
|
+
/** @type {!Set<shaka.extern.DrmInfo>} */
|
|
358
|
+
const drmInfos = new Set();
|
|
358
359
|
for (const variant of variants) {
|
|
359
|
-
const
|
|
360
|
-
for (const info of
|
|
361
|
-
|
|
362
|
-
info,
|
|
363
|
-
shaka.util.MapUtils.asMap(this.config_.servers),
|
|
364
|
-
shaka.util.MapUtils.asMap(this.config_.advanced || {}),
|
|
365
|
-
this.config_.keySystemsMapping);
|
|
360
|
+
const variantDrmInfos = this.getVariantDrmInfos_(variant);
|
|
361
|
+
for (const info of variantDrmInfos) {
|
|
362
|
+
drmInfos.add(info);
|
|
366
363
|
}
|
|
367
364
|
}
|
|
368
365
|
|
|
366
|
+
for (const info of drmInfos) {
|
|
367
|
+
shaka.media.DrmEngine.fillInDrmInfoDefaults_(
|
|
368
|
+
info,
|
|
369
|
+
shaka.util.MapUtils.asMap(this.config_.servers),
|
|
370
|
+
shaka.util.MapUtils.asMap(this.config_.advanced || {}),
|
|
371
|
+
this.config_.keySystemsMapping);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
|
|
369
375
|
/** @type {!Map.<string, MediaKeySystemConfiguration>} */
|
|
370
376
|
let configsByKeySystem;
|
|
371
377
|
|