shaka-player 4.5.0 → 4.6.1
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/AUTHORS +2 -0
- package/CHANGELOG.md +109 -0
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTORS +2 -0
- package/README.md +38 -32
- package/demo/common/asset.js +11 -17
- package/demo/common/assets.js +117 -11
- package/demo/config.js +28 -1
- package/demo/custom.js +52 -38
- package/demo/main.js +11 -3
- package/demo/search.js +7 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +133 -124
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +133 -124
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +20 -18
- package/dist/locales.js +34 -30
- package/dist/receiver.compiled.debug.js +58 -50
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +58 -50
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +440 -390
- package/dist/shaka-player.compiled.debug.d.ts +440 -390
- package/dist/shaka-player.compiled.debug.externs.js +162 -77
- package/dist/shaka-player.compiled.debug.js +789 -738
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +162 -77
- package/dist/shaka-player.compiled.js +1147 -1113
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +491 -437
- package/dist/shaka-player.ui.debug.d.ts +491 -437
- package/dist/shaka-player.ui.debug.externs.js +167 -77
- package/dist/shaka-player.ui.debug.js +857 -791
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +167 -77
- package/dist/shaka-player.ui.js +1359 -1314
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ad_monetization.md +54 -0
- package/docs/tutorials/basic-usage.md +2 -1
- package/docs/tutorials/errors.md +2 -1
- package/docs/tutorials/offline.md +10 -8
- package/docs/tutorials/plugins.md +5 -0
- package/docs/tutorials/ui-customization.md +13 -0
- package/docs/tutorials/ui.md +2 -1
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/managedmediasource.js +24 -0
- package/externs/shaka/abr_manager.js +6 -2
- package/externs/shaka/cea.js +7 -0
- package/externs/shaka/codecs.js +5 -3
- package/externs/shaka/manifest.js +21 -5
- package/externs/shaka/manifest_parser.js +17 -0
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/offline.js +9 -2
- package/externs/shaka/player.js +53 -7
- package/externs/shaka/text.js +3 -1
- package/externs/shaka/transmuxer.js +1 -1
- package/lib/abr/simple_abr_manager.js +25 -8
- package/lib/ads/media_tailor_ad_manager.js +14 -3
- package/lib/cast/cast_receiver.js +1 -1
- package/lib/cea/cea_decoder.js +28 -0
- package/lib/cea/dummy_caption_decoder.js +5 -0
- package/lib/dash/dash_parser.js +251 -84
- package/lib/dash/mpd_utils.js +52 -31
- package/lib/dash/segment_base.js +4 -5
- package/lib/dash/segment_list.js +5 -4
- package/lib/dash/segment_template.js +92 -29
- package/lib/hls/hls_classes.js +28 -43
- package/lib/hls/hls_parser.js +770 -652
- package/lib/hls/hls_utils.js +64 -5
- package/lib/hls/manifest_text_parser.js +7 -11
- package/lib/media/adaptation_set.js +20 -13
- package/lib/media/adaptation_set_criteria.js +70 -18
- package/lib/media/closed_caption_parser.js +13 -0
- package/lib/media/content_workarounds.js +6 -0
- package/lib/media/drm_engine.js +8 -13
- package/lib/media/manifest_parser.js +8 -113
- package/lib/media/media_source_capabilities.js +10 -3
- package/lib/media/media_source_engine.js +75 -21
- package/lib/media/play_rate_controller.js +8 -38
- package/lib/media/presentation_timeline.js +7 -1
- package/lib/media/quality_observer.js +1 -1
- package/lib/media/segment_index.js +5 -5
- package/lib/media/segment_prefetch.js +92 -24
- package/lib/media/segment_reference.js +67 -1
- package/lib/media/segment_utils.js +343 -0
- package/lib/media/stall_detector.js +0 -3
- package/lib/media/streaming_engine.js +72 -44
- package/lib/mss/mss_parser.js +18 -2
- package/lib/net/networking_engine.js +66 -12
- package/lib/net/networking_utils.js +95 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
- package/lib/offline/manifest_converter.js +2 -0
- package/lib/offline/offline_manifest_parser.js +10 -0
- package/lib/offline/storage.js +11 -7
- package/lib/player.js +998 -1503
- package/lib/polyfill/mediasource.js +22 -1
- package/lib/text/mp4_ttml_parser.js +2 -2
- package/lib/text/srt_text_parser.js +2 -2
- package/lib/text/stub_text_displayer.js +51 -0
- package/lib/text/text_engine.js +3 -2
- package/lib/text/ttml_text_parser.js +28 -5
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +7 -2
- package/lib/transmuxer/aac_transmuxer.js +1 -1
- package/lib/transmuxer/ac3_transmuxer.js +1 -1
- package/lib/transmuxer/ec3_transmuxer.js +1 -1
- package/lib/transmuxer/h264.js +5 -4
- package/lib/transmuxer/h265.js +5 -4
- package/lib/transmuxer/mp3_transmuxer.js +1 -1
- package/lib/transmuxer/mpeg_ts_transmuxer.js +1 -1
- package/lib/transmuxer/mss_transmuxer.js +1 -1
- package/lib/transmuxer/ts_transmuxer.js +33 -13
- package/lib/util/buffer_utils.js +26 -4
- package/lib/util/content_steering_manager.js +358 -0
- package/lib/util/error.js +2 -6
- package/lib/util/fairplay_utils.js +1 -1
- package/lib/util/fake_event.js +5 -1
- package/lib/util/id3_utils.js +50 -1
- package/lib/util/manifest_parser_utils.js +12 -8
- package/lib/util/mp4_generator.js +2 -4
- package/lib/util/mutex.js +59 -0
- package/lib/util/object_utils.js +1 -1
- package/lib/util/periods.js +154 -179
- package/lib/util/platform.js +4 -3
- package/lib/util/player_configuration.js +35 -6
- package/lib/util/stream_utils.js +105 -98
- package/lib/util/ts_parser.js +124 -73
- package/lib/util/uint8array_utils.js +5 -1
- package/lib/util/xml_utils.js +5 -0
- package/maintained-branches.md +2 -2
- package/package.json +1 -1
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +0 -1
- package/test/abr/simple_abr_manager_unit.js +33 -33
- package/test/ads/ad_manager_unit.js +3 -2
- package/test/cast/cast_receiver_integration.js +3 -4
- package/test/cast/cast_utils_unit.js +2 -0
- package/test/cea/cea_decoder_unit.js +7 -0
- package/test/codec_switching/codec_switching_integration.js +2 -1
- package/test/dash/dash_parser_integration.js +2 -1
- package/test/dash/dash_parser_live_unit.js +0 -19
- package/test/dash/dash_parser_manifest_unit.js +494 -2
- package/test/dash/mpd_utils_unit.js +61 -30
- package/test/hls/hls_live_unit.js +12 -3
- package/test/hls/hls_parser_unit.js +417 -27
- package/test/hls/manifest_text_parser_unit.js +32 -99
- package/test/media/adaptation_set_criteria_unit.js +172 -21
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/content_workarounds_unit.js +1 -1
- package/test/media/drm_engine_unit.js +3 -3
- package/test/media/media_source_engine_unit.js +1 -1
- package/test/media/play_rate_controller_unit.js +0 -48
- package/test/media/segment_index_unit.js +2 -1
- package/test/mss/mss_player_integration.js +3 -2
- package/test/net/networking_engine_unit.js +3 -3
- package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
- package/test/offline/manifest_convert_unit.js +9 -0
- package/test/offline/offline_integration.js +2 -1
- package/test/offline/storage_integration.js +21 -9
- package/test/player_external.js +4 -2
- package/test/player_integration.js +15 -4
- package/test/player_load_graph_integration.js +47 -151
- package/test/player_src_equals_external.js +1 -0
- package/test/player_src_equals_integration.js +71 -4
- package/test/player_unit.js +80 -27
- package/test/test/util/fake_media_source_engine.js +5 -0
- package/test/test/util/fake_networking_engine.js +9 -1
- package/test/test/util/fake_segment_prefetch.js +3 -0
- package/test/test/util/manifest_generator.js +4 -0
- package/test/test/util/manifest_parser_util.js +14 -2
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/simple_fakes.js +2 -2
- package/test/test/util/streaming_engine_util.js +3 -0
- package/test/test/util/test_scheme.js +6 -0
- package/test/test/util/ui_utils.js +4 -3
- package/test/text/mp4_ttml_parser_unit.js +4 -4
- package/test/text/srt_text_parser_unit.js +1 -1
- package/test/text/text_displayer_layout_unit.js +1 -1
- package/test/text/text_engine_unit.js +6 -0
- package/test/text/ttml_text_parser_unit.js +33 -2
- package/test/transmuxer/transmuxer_engine_integration.js +9 -0
- package/test/transmuxer/transmuxer_integration.js +33 -3
- package/test/ui/ad_ui_unit.js +2 -2
- package/test/ui/ui_customization_unit.js +17 -16
- package/test/ui/ui_integration.js +30 -20
- package/test/ui/ui_unit.js +25 -19
- package/test/util/buffer_utils_unit.js +1 -1
- package/test/util/content_steering_manager_unit.js +427 -0
- package/test/util/id3_utils_unit.js +52 -0
- package/test/util/stream_utils_unit.js +17 -113
- package/test/util/ts_parser_unit.js +3 -3
- package/third_party/closure-uri/uri.js +13 -1
- package/ui/audio_language_selection.js +9 -2
- package/ui/externs/ui.js +17 -2
- package/ui/language_utils.js +43 -8
- package/ui/less/range_elements.less +33 -0
- package/ui/locales/en.json +1 -0
- package/ui/locales/es-419.json +1 -0
- package/ui/locales/es.json +1 -0
- package/ui/locales/source.json +4 -0
- package/ui/localization.js +10 -0
- package/ui/remote_button.js +3 -1
- package/ui/resolution_selection.js +47 -10
- package/ui/seek_bar.js +296 -3
- package/ui/text_selection.js +2 -1
- package/ui/ui.js +6 -2
- package/lib/routing/node.js +0 -23
- package/lib/routing/payload.js +0 -47
- package/lib/routing/walker.js +0 -587
- package/test/routing/walker_unit.js +0 -505
package/lib/hls/hls_utils.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.hls.Utils');
|
|
8
8
|
|
|
9
|
+
goog.require('shaka.log');
|
|
10
|
+
goog.require('shaka.util.Error');
|
|
9
11
|
goog.require('shaka.util.ManifestParserUtils');
|
|
10
12
|
goog.requireType('shaka.hls.Tag');
|
|
11
13
|
|
|
@@ -68,17 +70,74 @@ shaka.hls.Utils = class {
|
|
|
68
70
|
return value;
|
|
69
71
|
}
|
|
70
72
|
|
|
73
|
+
/**
|
|
74
|
+
* @param {!Array.<string>} baseUris
|
|
75
|
+
* @param {?string} relativeUri
|
|
76
|
+
* @param {?Map.<string, string>=} variables
|
|
77
|
+
* @return {!Array.<string>}
|
|
78
|
+
*/
|
|
79
|
+
static constructSegmentUris(baseUris, relativeUri, variables) {
|
|
80
|
+
if (!relativeUri) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
return shaka.hls.Utils.constructUris(baseUris, [relativeUri], variables);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {!Array.<string>} baseUris
|
|
89
|
+
* @param {!Array.<string>} relativeUris
|
|
90
|
+
* @param {?Map.<string, string>=} variables
|
|
91
|
+
* @return {!Array.<string>}
|
|
92
|
+
*/
|
|
93
|
+
static constructUris(baseUris, relativeUris, variables) {
|
|
94
|
+
if (!relativeUris.length) {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
const resolvedUris = shaka.util.ManifestParserUtils.resolveUris(
|
|
98
|
+
baseUris, relativeUris);
|
|
99
|
+
|
|
100
|
+
const uris = [];
|
|
101
|
+
for (const uri of resolvedUris) {
|
|
102
|
+
uris.push(shaka.hls.Utils.variableSubstitution(uri, variables));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return uris;
|
|
106
|
+
}
|
|
71
107
|
|
|
72
108
|
/**
|
|
73
|
-
*
|
|
109
|
+
* Replaces the variables of a given URI.
|
|
110
|
+
*
|
|
74
111
|
* @param {string} uri
|
|
112
|
+
* @param {?Map.<string, string>=} variables
|
|
75
113
|
* @return {string}
|
|
76
114
|
*/
|
|
77
|
-
static
|
|
78
|
-
|
|
79
|
-
|
|
115
|
+
static variableSubstitution(uri, variables) {
|
|
116
|
+
if (!variables || !variables.size) {
|
|
117
|
+
return uri;
|
|
118
|
+
}
|
|
119
|
+
let newUri = String(uri).replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
80
120
|
|
|
81
|
-
|
|
121
|
+
const uriVariables = newUri.match(/{\$\w*}/g);
|
|
122
|
+
if (uriVariables) {
|
|
123
|
+
for (const variable of uriVariables) {
|
|
124
|
+
// Note: All variables have the structure {$...}
|
|
125
|
+
const variableName = variable.slice(2, variable.length - 1);
|
|
126
|
+
const replaceValue = variables.get(variableName);
|
|
127
|
+
if (replaceValue) {
|
|
128
|
+
newUri = newUri.replace(variable, replaceValue);
|
|
129
|
+
} else {
|
|
130
|
+
shaka.log.error('A variable has been found that is not declared',
|
|
131
|
+
variableName);
|
|
132
|
+
throw new shaka.util.Error(
|
|
133
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
134
|
+
shaka.util.Error.Category.MANIFEST,
|
|
135
|
+
shaka.util.Error.Code.HLS_VARIABLE_NOT_FOUND,
|
|
136
|
+
variableName);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return newUri;
|
|
82
141
|
}
|
|
83
142
|
|
|
84
143
|
|
|
@@ -29,10 +29,9 @@ shaka.hls.ManifestTextParser = class {
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* @param {BufferSource} data
|
|
32
|
-
* @param {string} absolutePlaylistUri An absolute, final URI after redirects.
|
|
33
32
|
* @return {!shaka.hls.Playlist}
|
|
34
33
|
*/
|
|
35
|
-
parsePlaylist(data
|
|
34
|
+
parsePlaylist(data) {
|
|
36
35
|
const MEDIA_PLAYLIST_TAGS =
|
|
37
36
|
shaka.hls.ManifestTextParser.MEDIA_PLAYLIST_TAGS;
|
|
38
37
|
const SEGMENT_TAGS = shaka.hls.ManifestTextParser.SEGMENT_TAGS;
|
|
@@ -101,10 +100,8 @@ shaka.hls.ManifestTextParser = class {
|
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
const segmentsData = lines.splice(i, lines.length - i);
|
|
104
|
-
const segments = this.parseSegments_(
|
|
105
|
-
|
|
106
|
-
return new shaka.hls.Playlist(
|
|
107
|
-
absolutePlaylistUri, playlistType, tags, segments);
|
|
103
|
+
const segments = this.parseSegments_(segmentsData, tags);
|
|
104
|
+
return new shaka.hls.Playlist(playlistType, tags, segments);
|
|
108
105
|
}
|
|
109
106
|
|
|
110
107
|
tags.push(tag);
|
|
@@ -118,19 +115,18 @@ shaka.hls.ManifestTextParser = class {
|
|
|
118
115
|
}
|
|
119
116
|
}
|
|
120
117
|
|
|
121
|
-
return new shaka.hls.Playlist(
|
|
118
|
+
return new shaka.hls.Playlist(playlistType, tags);
|
|
122
119
|
}
|
|
123
120
|
|
|
124
121
|
/**
|
|
125
122
|
* Parses an array of strings into an array of HLS Segment objects.
|
|
126
123
|
*
|
|
127
|
-
* @param {string} absoluteMediaPlaylistUri
|
|
128
124
|
* @param {!Array.<string>} lines
|
|
129
125
|
* @param {!Array.<!shaka.hls.Tag>} playlistTags
|
|
130
126
|
* @return {!Array.<shaka.hls.Segment>}
|
|
131
127
|
* @private
|
|
132
128
|
*/
|
|
133
|
-
parseSegments_(
|
|
129
|
+
parseSegments_(lines, playlistTags) {
|
|
134
130
|
/** @type {!Array.<shaka.hls.Segment>} */
|
|
135
131
|
const segments = [];
|
|
136
132
|
/** @type {!Array.<shaka.hls.Tag>} */
|
|
@@ -177,7 +173,7 @@ shaka.hls.ManifestTextParser = class {
|
|
|
177
173
|
segmentTags.push(currentMapTag);
|
|
178
174
|
}
|
|
179
175
|
// The URI appears after all of the tags describing the segment.
|
|
180
|
-
const segment = new shaka.hls.Segment(
|
|
176
|
+
const segment = new shaka.hls.Segment(
|
|
181
177
|
verbatimSegmentUri, segmentTags, partialSegmentTags);
|
|
182
178
|
segments.push(segment);
|
|
183
179
|
segmentTags = [];
|
|
@@ -193,7 +189,7 @@ shaka.hls.ManifestTextParser = class {
|
|
|
193
189
|
if (currentMapTag) {
|
|
194
190
|
segmentTags.push(currentMapTag);
|
|
195
191
|
}
|
|
196
|
-
const segment = new shaka.hls.Segment('',
|
|
192
|
+
const segment = new shaka.hls.Segment('', segmentTags,
|
|
197
193
|
partialSegmentTags);
|
|
198
194
|
segments.push(segment);
|
|
199
195
|
}
|
|
@@ -26,8 +26,11 @@ shaka.media.AdaptationSet = class {
|
|
|
26
26
|
* Variants that may be compatible with the root and should be added if
|
|
27
27
|
* compatible. If a candidate is not compatible, it will not end up in the
|
|
28
28
|
* adaptation set.
|
|
29
|
+
* @param {boolean=} compareCodecs
|
|
30
|
+
* @param {boolean=} enableAudioGroups
|
|
29
31
|
*/
|
|
30
|
-
constructor(root, candidates
|
|
32
|
+
constructor(root, candidates, compareCodecs = true,
|
|
33
|
+
enableAudioGroups = false) {
|
|
31
34
|
/** @private {shaka.extern.Variant} */
|
|
32
35
|
this.root_ = root;
|
|
33
36
|
/** @private {!Set.<shaka.extern.Variant>} */
|
|
@@ -37,17 +40,18 @@ shaka.media.AdaptationSet = class {
|
|
|
37
40
|
// are not compatible with the root, they will be rejected by |add|.
|
|
38
41
|
candidates = candidates || [];
|
|
39
42
|
for (const candidate of candidates) {
|
|
40
|
-
this.add(candidate);
|
|
43
|
+
this.add(candidate, compareCodecs, enableAudioGroups);
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
/**
|
|
45
48
|
* @param {shaka.extern.Variant} variant
|
|
46
|
-
* @param {boolean
|
|
49
|
+
* @param {boolean} compareCodecs
|
|
50
|
+
* @param {boolean} enableAudioGroups
|
|
47
51
|
* @return {boolean}
|
|
48
52
|
*/
|
|
49
|
-
add(variant, compareCodecs
|
|
50
|
-
if (this.canInclude(variant, compareCodecs)) {
|
|
53
|
+
add(variant, compareCodecs, enableAudioGroups) {
|
|
54
|
+
if (this.canInclude(variant, compareCodecs, enableAudioGroups)) {
|
|
51
55
|
this.variants_.add(variant);
|
|
52
56
|
return true;
|
|
53
57
|
}
|
|
@@ -64,20 +68,22 @@ shaka.media.AdaptationSet = class {
|
|
|
64
68
|
*
|
|
65
69
|
* @param {shaka.extern.Variant} variant
|
|
66
70
|
* @param {boolean=} compareCodecs
|
|
71
|
+
* @param {boolean=} enableAudioGroups
|
|
67
72
|
* @return {boolean}
|
|
68
73
|
*/
|
|
69
|
-
canInclude(variant, compareCodecs = true) {
|
|
74
|
+
canInclude(variant, compareCodecs = true, enableAudioGroups = false) {
|
|
70
75
|
return shaka.media.AdaptationSet
|
|
71
|
-
.areAdaptable(this.root_, variant, compareCodecs);
|
|
76
|
+
.areAdaptable(this.root_, variant, compareCodecs, enableAudioGroups);
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/**
|
|
75
80
|
* @param {shaka.extern.Variant} a
|
|
76
81
|
* @param {shaka.extern.Variant} b
|
|
77
|
-
* @param {boolean
|
|
82
|
+
* @param {boolean} compareCodecs
|
|
83
|
+
* @param {boolean} enableAudioGroups
|
|
78
84
|
* @return {boolean}
|
|
79
85
|
*/
|
|
80
|
-
static areAdaptable(a, b, compareCodecs
|
|
86
|
+
static areAdaptable(a, b, compareCodecs, enableAudioGroups) {
|
|
81
87
|
const AdaptationSet = shaka.media.AdaptationSet;
|
|
82
88
|
|
|
83
89
|
// All variants should have audio or should all not have audio.
|
|
@@ -98,8 +104,8 @@ shaka.media.AdaptationSet = class {
|
|
|
98
104
|
goog.asserts.assert(
|
|
99
105
|
!!a.audio == !!b.audio,
|
|
100
106
|
'Both should either have audio or not have audio.');
|
|
101
|
-
if (a.audio && b.audio &&
|
|
102
|
-
|
|
107
|
+
if (a.audio && b.audio && !AdaptationSet.areAudiosCompatible_(
|
|
108
|
+
a.audio, b.audio, compareCodecs, enableAudioGroups)) {
|
|
103
109
|
return false;
|
|
104
110
|
}
|
|
105
111
|
|
|
@@ -127,10 +133,11 @@ shaka.media.AdaptationSet = class {
|
|
|
127
133
|
* @param {shaka.extern.Stream} a
|
|
128
134
|
* @param {shaka.extern.Stream} b
|
|
129
135
|
* @param {boolean} compareCodecs
|
|
136
|
+
* @param {boolean} enableAudioGroups
|
|
130
137
|
* @return {boolean}
|
|
131
138
|
* @private
|
|
132
139
|
*/
|
|
133
|
-
static areAudiosCompatible_(a, b, compareCodecs) {
|
|
140
|
+
static areAudiosCompatible_(a, b, compareCodecs, enableAudioGroups) {
|
|
134
141
|
const AdaptationSet = shaka.media.AdaptationSet;
|
|
135
142
|
|
|
136
143
|
// Don't adapt between channel counts, which could annoy the user
|
|
@@ -154,7 +161,7 @@ shaka.media.AdaptationSet = class {
|
|
|
154
161
|
}
|
|
155
162
|
|
|
156
163
|
// We can only adapt between the same groupId.
|
|
157
|
-
if (a.groupId !== b.groupId) {
|
|
164
|
+
if (enableAudioGroups && a.groupId !== b.groupId) {
|
|
158
165
|
return false;
|
|
159
166
|
}
|
|
160
167
|
|
|
@@ -13,7 +13,6 @@ goog.require('shaka.log');
|
|
|
13
13
|
goog.require('shaka.media.AdaptationSet');
|
|
14
14
|
goog.require('shaka.media.Capabilities');
|
|
15
15
|
goog.require('shaka.util.LanguageUtils');
|
|
16
|
-
goog.require('shaka.util.StreamUtils');
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
/**
|
|
@@ -43,27 +42,33 @@ shaka.media.ExampleBasedCriteria = class {
|
|
|
43
42
|
/**
|
|
44
43
|
* @param {shaka.extern.Variant} example
|
|
45
44
|
* @param {shaka.config.CodecSwitchingStrategy=} codecSwitchingStrategy
|
|
45
|
+
* @param {boolean=} enableAudioGroups
|
|
46
46
|
*/
|
|
47
47
|
constructor(example,
|
|
48
|
-
codecSwitchingStrategy = shaka.config.CodecSwitchingStrategy.RELOAD
|
|
48
|
+
codecSwitchingStrategy = shaka.config.CodecSwitchingStrategy.RELOAD,
|
|
49
|
+
enableAudioGroups = false) {
|
|
49
50
|
/** @private {shaka.extern.Variant} */
|
|
50
51
|
this.example_ = example;
|
|
51
52
|
/** @private {shaka.config.CodecSwitchingStrategy} */
|
|
52
53
|
this.codecSwitchingStrategy_ = codecSwitchingStrategy;
|
|
54
|
+
/** @private {boolean} */
|
|
55
|
+
this.enableAudioGroups_ = enableAudioGroups;
|
|
56
|
+
|
|
53
57
|
|
|
54
58
|
// We can't know if role and label are really important, so we don't use
|
|
55
59
|
// role and label for this.
|
|
56
60
|
const role = '';
|
|
57
61
|
const label = '';
|
|
58
62
|
const hdrLevel = '';
|
|
63
|
+
const videoLayout = '';
|
|
59
64
|
const channelCount = example.audio && example.audio.channelsCount ?
|
|
60
65
|
example.audio.channelsCount :
|
|
61
66
|
0;
|
|
62
67
|
|
|
63
68
|
/** @private {!shaka.media.AdaptationSetCriteria} */
|
|
64
69
|
this.fallback_ = new shaka.media.PreferenceBasedCriteria(
|
|
65
|
-
example.language, role, channelCount, hdrLevel, label,
|
|
66
|
-
codecSwitchingStrategy);
|
|
70
|
+
example.language, role, channelCount, hdrLevel, videoLayout, label,
|
|
71
|
+
codecSwitchingStrategy, enableAudioGroups);
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
/** @override */
|
|
@@ -75,14 +80,15 @@ shaka.media.ExampleBasedCriteria = class {
|
|
|
75
80
|
// actually be from another period.
|
|
76
81
|
const shortList = variants.filter((variant) => {
|
|
77
82
|
return shaka.media.AdaptationSet.areAdaptable(this.example_, variant,
|
|
78
|
-
!supportsSmoothCodecTransitions);
|
|
83
|
+
!supportsSmoothCodecTransitions, this.enableAudioGroups_);
|
|
79
84
|
});
|
|
80
85
|
|
|
81
86
|
if (shortList.length) {
|
|
82
87
|
// Use the first item in the short list as the root. It should not matter
|
|
83
88
|
// which element we use as all items in the short list should already be
|
|
84
89
|
// compatible.
|
|
85
|
-
return new shaka.media.AdaptationSet(shortList[0], shortList
|
|
90
|
+
return new shaka.media.AdaptationSet(shortList[0], shortList,
|
|
91
|
+
!supportsSmoothCodecTransitions, this.enableAudioGroups_);
|
|
86
92
|
} else {
|
|
87
93
|
return this.fallback_.create(variants);
|
|
88
94
|
}
|
|
@@ -100,11 +106,14 @@ shaka.media.PreferenceBasedCriteria = class {
|
|
|
100
106
|
* @param {string} role
|
|
101
107
|
* @param {number} channelCount
|
|
102
108
|
* @param {string} hdrLevel
|
|
109
|
+
* @param {string} videoLayout
|
|
103
110
|
* @param {string=} label
|
|
104
111
|
* @param {shaka.config.CodecSwitchingStrategy=} codecSwitchingStrategy
|
|
112
|
+
* @param {boolean=} enableAudioGroups
|
|
105
113
|
*/
|
|
106
|
-
constructor(language, role, channelCount, hdrLevel, label = '',
|
|
107
|
-
codecSwitchingStrategy = shaka.config.CodecSwitchingStrategy.RELOAD
|
|
114
|
+
constructor(language, role, channelCount, hdrLevel, videoLayout, label = '',
|
|
115
|
+
codecSwitchingStrategy = shaka.config.CodecSwitchingStrategy.RELOAD,
|
|
116
|
+
enableAudioGroups = false) {
|
|
108
117
|
/** @private {string} */
|
|
109
118
|
this.language_ = language;
|
|
110
119
|
/** @private {string} */
|
|
@@ -114,15 +123,18 @@ shaka.media.PreferenceBasedCriteria = class {
|
|
|
114
123
|
/** @private {string} */
|
|
115
124
|
this.hdrLevel_ = hdrLevel;
|
|
116
125
|
/** @private {string} */
|
|
126
|
+
this.videoLayout_ = videoLayout;
|
|
127
|
+
/** @private {string} */
|
|
117
128
|
this.label_ = label;
|
|
118
129
|
/** @private {shaka.config.CodecSwitchingStrategy} */
|
|
119
130
|
this.codecSwitchingStrategy_ = codecSwitchingStrategy;
|
|
131
|
+
/** @private {boolean} */
|
|
132
|
+
this.enableAudioGroups_ = enableAudioGroups;
|
|
120
133
|
}
|
|
121
134
|
|
|
122
135
|
/** @override */
|
|
123
136
|
create(variants) {
|
|
124
137
|
const Class = shaka.media.PreferenceBasedCriteria;
|
|
125
|
-
const StreamUtils = shaka.util.StreamUtils;
|
|
126
138
|
|
|
127
139
|
let current = [];
|
|
128
140
|
|
|
@@ -146,6 +158,17 @@ shaka.media.PreferenceBasedCriteria = class {
|
|
|
146
158
|
shaka.log.warning('No exact match for variant role could be found.');
|
|
147
159
|
}
|
|
148
160
|
|
|
161
|
+
if (this.videoLayout_) {
|
|
162
|
+
const byVideoLayout = Class.filterVariantsByVideoLayout_(
|
|
163
|
+
current, this.videoLayout_);
|
|
164
|
+
if (byVideoLayout.length) {
|
|
165
|
+
current = byVideoLayout;
|
|
166
|
+
} else {
|
|
167
|
+
shaka.log.warning(
|
|
168
|
+
'No exact match for the video layout could be found.');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
149
172
|
if (this.hdrLevel_) {
|
|
150
173
|
const byHdrLevel = Class.filterVariantsByHDRLevel_(
|
|
151
174
|
current, this.hdrLevel_);
|
|
@@ -158,7 +181,7 @@ shaka.media.PreferenceBasedCriteria = class {
|
|
|
158
181
|
}
|
|
159
182
|
|
|
160
183
|
if (this.channelCount_) {
|
|
161
|
-
const byChannel =
|
|
184
|
+
const byChannel = Class.filterVariantsByAudioChannelCount_(
|
|
162
185
|
current, this.channelCount_);
|
|
163
186
|
if (byChannel.length) {
|
|
164
187
|
current = byChannel;
|
|
@@ -181,14 +204,8 @@ shaka.media.PreferenceBasedCriteria = class {
|
|
|
181
204
|
shaka.config.CodecSwitchingStrategy.SMOOTH &&
|
|
182
205
|
shaka.media.Capabilities.isChangeTypeSupported();
|
|
183
206
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
for (const variant of current) {
|
|
187
|
-
// `add` checks combatability by calling `canInclude` internally.
|
|
188
|
-
set.add(variant, !supportsSmoothCodecTransitions);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return set;
|
|
207
|
+
return new shaka.media.AdaptationSet(current[0], current,
|
|
208
|
+
!supportsSmoothCodecTransitions, this.enableAudioGroups_);
|
|
192
209
|
}
|
|
193
210
|
|
|
194
211
|
/**
|
|
@@ -261,6 +278,23 @@ shaka.media.PreferenceBasedCriteria = class {
|
|
|
261
278
|
});
|
|
262
279
|
}
|
|
263
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Filter Variants by channelCount.
|
|
283
|
+
*
|
|
284
|
+
* @param {!Array.<shaka.extern.Variant>} variants
|
|
285
|
+
* @param {number} channelCount
|
|
286
|
+
* @return {!Array.<shaka.extern.Variant>}
|
|
287
|
+
* @private
|
|
288
|
+
*/
|
|
289
|
+
static filterVariantsByAudioChannelCount_(variants, channelCount) {
|
|
290
|
+
return variants.filter((variant) => {
|
|
291
|
+
if (variant.audio && variant.audio.channelsCount &&
|
|
292
|
+
variant.audio.channelsCount != channelCount) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
264
298
|
|
|
265
299
|
/**
|
|
266
300
|
* Filters variants according to the given hdr level config.
|
|
@@ -285,4 +319,22 @@ shaka.media.PreferenceBasedCriteria = class {
|
|
|
285
319
|
return true;
|
|
286
320
|
});
|
|
287
321
|
}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Filters variants according to the given video layout config.
|
|
326
|
+
*
|
|
327
|
+
* @param {!Array.<shaka.extern.Variant>} variants
|
|
328
|
+
* @param {string} videoLayout
|
|
329
|
+
* @private
|
|
330
|
+
*/
|
|
331
|
+
static filterVariantsByVideoLayout_(variants, videoLayout) {
|
|
332
|
+
return variants.filter((variant) => {
|
|
333
|
+
if (variant.video && variant.video.videoLayout &&
|
|
334
|
+
variant.video.videoLayout != videoLayout) {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
return true;
|
|
338
|
+
});
|
|
339
|
+
}
|
|
288
340
|
};
|
|
@@ -42,6 +42,12 @@ shaka.media.IClosedCaptionParser = class {
|
|
|
42
42
|
* Resets the CaptionStream.
|
|
43
43
|
*/
|
|
44
44
|
reset() {}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns the streams that the CEA decoder found.
|
|
48
|
+
* @return {!Array.<string>}
|
|
49
|
+
*/
|
|
50
|
+
getStreams() {}
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
/**
|
|
@@ -112,6 +118,13 @@ shaka.media.ClosedCaptionParser = class {
|
|
|
112
118
|
this.ceaDecoder_.clear();
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
/**
|
|
122
|
+
* @override
|
|
123
|
+
*/
|
|
124
|
+
getStreams() {
|
|
125
|
+
return this.ceaDecoder_.getStreams();
|
|
126
|
+
}
|
|
127
|
+
|
|
115
128
|
/**
|
|
116
129
|
* @param {string} mimeType
|
|
117
130
|
* @param {!shaka.extern.CeaParserPlugin} plugin
|
|
@@ -105,6 +105,12 @@ shaka.media.ContentWorkarounds = class {
|
|
|
105
105
|
newType: ContentWorkarounds.BOX_TYPE_ENCA_,
|
|
106
106
|
});
|
|
107
107
|
})
|
|
108
|
+
.fullBox('ac-4', (box) => {
|
|
109
|
+
boxesToModify.push({
|
|
110
|
+
box,
|
|
111
|
+
newType: ContentWorkarounds.BOX_TYPE_ENCA_,
|
|
112
|
+
});
|
|
113
|
+
})
|
|
108
114
|
.fullBox('mp4a', (box) => {
|
|
109
115
|
boxesToModify.push({
|
|
110
116
|
box,
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -715,11 +715,8 @@ shaka.media.DrmEngine = class {
|
|
|
715
715
|
|
|
716
716
|
const metadatas = this.activeSessions_.values();
|
|
717
717
|
for (const metadata of metadatas) {
|
|
718
|
-
// Tizen 2015 and 2016 models will send multiple webkitneedkey events
|
|
719
|
-
// with the same init data. If the duplicates are supressed, playback
|
|
720
|
-
// will stall without errors.
|
|
721
718
|
if (shaka.util.BufferUtils.equal(initData, metadata.initData) &&
|
|
722
|
-
|
|
719
|
+
this.config_.ignoreDuplicateInitData) {
|
|
723
720
|
shaka.log.debug('Ignoring duplicate init data.');
|
|
724
721
|
return;
|
|
725
722
|
}
|
|
@@ -2045,15 +2042,13 @@ shaka.media.DrmEngine = class {
|
|
|
2045
2042
|
// audio adaptations, so we shouldn't have to worry about checking
|
|
2046
2043
|
// robustness.
|
|
2047
2044
|
if (drm1.keySystem == drm2.keySystem) {
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
});
|
|
2056
|
-
});
|
|
2045
|
+
const initDataMap = new Map();
|
|
2046
|
+
const bothInitDatas = (drm1.initData || [])
|
|
2047
|
+
.concat(drm2.initData || []);
|
|
2048
|
+
for (const d of bothInitDatas) {
|
|
2049
|
+
initDataMap.set(d.keyId, d);
|
|
2050
|
+
}
|
|
2051
|
+
const initData = Array.from(initDataMap.values());
|
|
2057
2052
|
|
|
2058
2053
|
const keyIds = drm1.keyIds && drm2.keyIds ?
|
|
2059
2054
|
new Set([...drm1.keyIds, ...drm2.keyIds]) :
|