shaka-player 4.4.3 → 4.6.0
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/workflows/release-please.yaml +2 -27
- package/AUTHORS +2 -0
- package/CHANGELOG.md +156 -39
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTORS +2 -0
- package/README.md +54 -42
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +33 -22
- package/demo/common/assets.js +249 -60
- package/demo/config.js +219 -253
- package/demo/custom.js +88 -133
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +62 -126
- package/demo/search.js +29 -34
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +211 -228
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +211 -228
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +42 -37
- package/dist/locales.js +34 -30
- package/dist/receiver.compiled.debug.js +64 -77
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +64 -77
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +343 -151
- package/dist/shaka-player.compiled.debug.d.ts +343 -151
- package/dist/shaka-player.compiled.debug.externs.js +356 -117
- package/dist/shaka-player.compiled.debug.js +952 -811
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +356 -117
- package/dist/shaka-player.compiled.js +1165 -1078
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +359 -153
- package/dist/shaka-player.ui.debug.d.ts +359 -153
- package/dist/shaka-player.ui.debug.externs.js +382 -117
- package/dist/shaka-player.ui.debug.js +1084 -918
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +382 -117
- package/dist/shaka-player.ui.js +1377 -1274
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- 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/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/offline.md +10 -8
- package/docs/tutorials/plugins.md +5 -0
- package/docs/tutorials/ui-customization.md +17 -0
- package/docs/tutorials/ui.md +2 -1
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/managedmediasource.js +24 -0
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/abr_manager.js +6 -2
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/cea.js +7 -0
- package/externs/shaka/codecs.js +5 -3
- package/externs/shaka/manifest.js +31 -10
- package/externs/shaka/manifest_parser.js +24 -1
- package/externs/shaka/net.js +2 -2
- package/externs/shaka/offline.js +13 -2
- package/externs/shaka/player.js +65 -8
- package/externs/shaka/text.js +3 -1
- package/externs/shaka/transmuxer.js +1 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +66 -9
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +839 -0
- 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/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +322 -93
- package/lib/dash/mpd_utils.js +62 -37
- package/lib/dash/segment_base.js +17 -10
- package/lib/dash/segment_list.js +18 -9
- package/lib/dash/segment_template.js +122 -107
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_classes.js +28 -43
- package/lib/hls/hls_parser.js +798 -658
- package/lib/hls/hls_utils.js +64 -5
- package/lib/hls/manifest_text_parser.js +7 -11
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +32 -14
- package/lib/media/adaptation_set_criteria.js +86 -16
- 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 +286 -44
- 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 +6 -6
- package/lib/media/segment_prefetch.js +92 -24
- package/lib/media/segment_reference.js +73 -7
- package/lib/media/segment_utils.js +343 -0
- package/lib/media/stall_detector.js +0 -3
- package/lib/media/streaming_engine.js +73 -38
- package/lib/mss/mss_parser.js +19 -2
- package/lib/net/networking_engine.js +67 -12
- package/lib/net/networking_utils.js +95 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +3 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +3 -0
- package/lib/offline/manifest_converter.js +3 -0
- package/lib/offline/offline_manifest_parser.js +10 -0
- package/lib/offline/storage.js +14 -7
- package/lib/player.js +1098 -1537
- package/lib/polyfill/mediasource.js +22 -1
- package/lib/text/cue.js +15 -0
- 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 +45 -5
- package/lib/text/ui_text_displayer.js +8 -0
- package/lib/text/vtt_text_parser.js +40 -22
- 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 +863 -0
- package/lib/transmuxer/mp3_transmuxer.js +1 -1
- package/lib/transmuxer/mpeg_ts_transmuxer.js +4 -3
- package/lib/transmuxer/mss_transmuxer.js +1 -1
- package/lib/transmuxer/ts_transmuxer.js +187 -22
- package/lib/util/buffer_utils.js +26 -4
- package/lib/util/content_steering_manager.js +358 -0
- package/lib/util/error.js +30 -15
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fairplay_utils.js +1 -1
- package/lib/util/fake_event.js +8 -1
- package/lib/util/id3_utils.js +50 -1
- package/lib/util/manifest_parser_utils.js +12 -8
- package/lib/util/mp4_generator.js +6 -8
- package/lib/util/mutex.js +59 -0
- package/lib/util/object_utils.js +1 -1
- package/lib/util/periods.js +156 -179
- package/lib/util/platform.js +44 -3
- package/lib/util/player_configuration.js +43 -6
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +206 -283
- package/lib/util/ts_parser.js +335 -98
- package/lib/util/uint8array_utils.js +5 -1
- package/lib/util/xml_utils.js +5 -0
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +25 -5
- package/shaka-player.uncompiled.js +2 -2
- package/support.html +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 +50 -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 +182 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +74 -0
- package/test/dash/dash_parser_live_unit.js +2 -19
- package/test/dash/dash_parser_manifest_unit.js +536 -2
- package/test/dash/dash_parser_segment_base_unit.js +2 -0
- package/test/dash/dash_parser_segment_list_unit.js +2 -0
- package/test/dash/dash_parser_segment_template_unit.js +2 -0
- package/test/dash/mpd_utils_unit.js +61 -30
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +14 -3
- package/test/hls/hls_parser_unit.js +385 -33
- package/test/hls/manifest_text_parser_unit.js +32 -99
- package/test/media/adaptation_set_criteria_unit.js +284 -15
- package/test/media/adaptation_set_unit.js +2 -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 +166 -2
- package/test/media/play_rate_controller_unit.js +0 -48
- package/test/media/segment_index_unit.js +5 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- 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 +14 -0
- package/test/offline/offline_integration.js +2 -1
- package/test/offline/storage_integration.js +22 -13
- 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 +182 -158
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +4 -0
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +13 -2
- 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 +11 -3
- package/test/test/util/manifest_parser_util.js +14 -2
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +2 -0
- package/test/test/util/simple_fakes.js +2 -2
- package/test/test/util/streaming_engine_util.js +10 -4
- 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 +85 -2
- package/test/text/vtt_text_parser_unit.js +103 -31
- package/test/transmuxer/transmuxer_engine_integration.js +9 -0
- package/test/transmuxer/transmuxer_integration.js +150 -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 +28 -29
- 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 +207 -169
- 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/controls.js +125 -0
- package/ui/externs/ui.js +24 -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/pip_button.js +22 -120
- package/ui/remote_button.js +203 -0
- 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 +11 -4
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -288
- package/demo/locales/source.json +0 -1146
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/routing/node.js +0 -23
- package/lib/routing/payload.js +0 -43
- package/lib/routing/walker.js +0 -587
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/routing/walker_unit.js +0 -504
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
package/lib/util/stream_utils.js
CHANGED
|
@@ -31,110 +31,165 @@ shaka.util.StreamUtils = class {
|
|
|
31
31
|
* @param {!shaka.extern.Manifest} manifest
|
|
32
32
|
* @param {!Array.<string>} preferredVideoCodecs
|
|
33
33
|
* @param {!Array.<string>} preferredAudioCodecs
|
|
34
|
-
* @param {number} preferredAudioChannelCount
|
|
35
34
|
* @param {!Array.<string>} preferredDecodingAttributes
|
|
36
35
|
*/
|
|
37
36
|
static chooseCodecsAndFilterManifest(manifest, preferredVideoCodecs,
|
|
38
|
-
preferredAudioCodecs,
|
|
39
|
-
preferredDecodingAttributes) {
|
|
37
|
+
preferredAudioCodecs, preferredDecodingAttributes) {
|
|
40
38
|
const StreamUtils = shaka.util.StreamUtils;
|
|
39
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
41
40
|
|
|
42
41
|
let variants = manifest.variants;
|
|
43
|
-
|
|
44
42
|
// To start, choose the codecs based on configured preferences if available.
|
|
45
43
|
if (preferredVideoCodecs.length || preferredAudioCodecs.length) {
|
|
46
44
|
variants = StreamUtils.choosePreferredCodecs(variants,
|
|
47
45
|
preferredVideoCodecs, preferredAudioCodecs);
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
48
|
+
if (preferredDecodingAttributes.length) {
|
|
49
|
+
// group variants by resolution and choose preferred variants only
|
|
50
|
+
/** @type {!shaka.util.MultiMap.<shaka.extern.Variant>} */
|
|
51
|
+
const variantsByResolutionMap = new shaka.util.MultiMap();
|
|
52
|
+
for (const variant of variants) {
|
|
53
|
+
variantsByResolutionMap
|
|
54
|
+
.push(String(variant.video.width || 0), variant);
|
|
55
|
+
}
|
|
56
|
+
const bestVariants = [];
|
|
57
|
+
variantsByResolutionMap.forEach((width, variantsByResolution) => {
|
|
58
|
+
let highestMatch = 0;
|
|
59
|
+
let matchingVariants = [];
|
|
60
|
+
for (const variant of variantsByResolution) {
|
|
61
|
+
const matchCount = preferredDecodingAttributes.filter(
|
|
62
|
+
(attribute) => variant.decodingInfos[0][attribute],
|
|
63
|
+
).length;
|
|
64
|
+
if (matchCount > highestMatch) {
|
|
65
|
+
highestMatch = matchCount;
|
|
66
|
+
matchingVariants = [variant];
|
|
67
|
+
} else if (matchCount == highestMatch) {
|
|
68
|
+
matchingVariants.push(variant);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
bestVariants.push(...matchingVariants);
|
|
72
|
+
});
|
|
73
|
+
variants = bestVariants;
|
|
74
|
+
}
|
|
65
75
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
const audioStreamsSet = new Set();
|
|
77
|
+
const videoStreamsSet = new Set();
|
|
78
|
+
for (const variant of variants) {
|
|
79
|
+
if (variant.audio) {
|
|
80
|
+
audioStreamsSet.add(variant.audio);
|
|
81
|
+
}
|
|
82
|
+
if (variant.video) {
|
|
83
|
+
videoStreamsSet.add(variant.video);
|
|
72
84
|
}
|
|
85
|
+
}
|
|
73
86
|
|
|
74
|
-
|
|
75
|
-
return
|
|
87
|
+
const audioStreams = Array.from(audioStreamsSet).sort((v1, v2) => {
|
|
88
|
+
return v1.bandwidth - v2.bandwidth;
|
|
76
89
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
const validAudioIds = [];
|
|
91
|
+
const validAudioStreamsMap = new Map();
|
|
92
|
+
const getAudioId = (stream) => {
|
|
93
|
+
return stream.language + (stream.channelsCount || 0) +
|
|
94
|
+
(stream.audioSamplingRate || 0) + stream.roles.join(',') +
|
|
95
|
+
stream.label + stream.groupId + stream.fastSwitching;
|
|
96
|
+
};
|
|
97
|
+
for (const stream of audioStreams) {
|
|
98
|
+
const groupId = getAudioId(stream);
|
|
99
|
+
const validAudioStreams = validAudioStreamsMap.get(groupId) || [];
|
|
100
|
+
if (!validAudioStreams.length) {
|
|
101
|
+
validAudioStreams.push(stream);
|
|
102
|
+
validAudioIds.push(stream.id);
|
|
103
|
+
} else {
|
|
104
|
+
const previousStream = validAudioStreams[validAudioStreams.length - 1];
|
|
105
|
+
const previousCodec =
|
|
106
|
+
MimeUtils.getNormalizedCodec(previousStream.codecs);
|
|
107
|
+
const currentCodec =
|
|
108
|
+
MimeUtils.getNormalizedCodec(stream.codecs);
|
|
109
|
+
if (previousCodec == currentCodec) {
|
|
110
|
+
if (stream.bandwidth > previousStream.bandwidth) {
|
|
111
|
+
validAudioStreams.push(stream);
|
|
112
|
+
validAudioIds.push(stream.id);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
validAudioStreamsMap.set(groupId, validAudioStreams);
|
|
91
117
|
}
|
|
92
118
|
|
|
93
|
-
|
|
94
|
-
|
|
119
|
+
const videoStreams = Array.from(videoStreamsSet)
|
|
120
|
+
.sort((v1, v2) => {
|
|
121
|
+
if (!v1.bandwidth || !v2.bandwidth) {
|
|
122
|
+
return v1.width - v2.width;
|
|
123
|
+
}
|
|
124
|
+
return v1.bandwidth - v2.bandwidth;
|
|
125
|
+
});
|
|
95
126
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
* Get variants by codecs map with the max density where all codecs are
|
|
99
|
-
* present.
|
|
100
|
-
*
|
|
101
|
-
* @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
|
|
102
|
-
* @return {!shaka.util.MultiMap.<shaka.extern.Variant>}
|
|
103
|
-
* @private
|
|
104
|
-
*/
|
|
105
|
-
static filterVariantsByDensity_(variantsByCodecs) {
|
|
106
|
-
let maxDensity = 0;
|
|
107
|
-
const codecGroupsByDensity = new Map();
|
|
108
|
-
const countCodecs = variantsByCodecs.size();
|
|
109
|
-
|
|
110
|
-
variantsByCodecs.forEach((codecs, variants) => {
|
|
111
|
-
for (const variant of variants) {
|
|
112
|
-
const video = variant.video;
|
|
113
|
-
if (!video || !video.width || !video.height) {
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
127
|
+
const isChangeTypeSupported =
|
|
128
|
+
shaka.media.Capabilities.isChangeTypeSupported();
|
|
116
129
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
const validVideoIds = [];
|
|
131
|
+
const validVideoStreamsMap = new Map();
|
|
132
|
+
const getVideoGroupId = (stream) => {
|
|
133
|
+
return Math.round(stream.frameRate || 0) + (stream.hdr || '') +
|
|
134
|
+
stream.fastSwitching;
|
|
135
|
+
};
|
|
136
|
+
for (const stream of videoStreams) {
|
|
137
|
+
const groupId = getVideoGroupId(stream);
|
|
138
|
+
const validVideoStreams = validVideoStreamsMap.get(groupId) || [];
|
|
139
|
+
if (!validVideoStreams.length) {
|
|
140
|
+
validVideoStreams.push(stream);
|
|
141
|
+
validVideoIds.push(stream.id);
|
|
142
|
+
} else {
|
|
143
|
+
const previousStream = validVideoStreams[validVideoStreams.length - 1];
|
|
144
|
+
if (!isChangeTypeSupported) {
|
|
145
|
+
const previousCodec =
|
|
146
|
+
MimeUtils.getNormalizedCodec(previousStream.codecs);
|
|
147
|
+
const currentCodec =
|
|
148
|
+
MimeUtils.getNormalizedCodec(stream.codecs);
|
|
149
|
+
if (previousCodec !== currentCodec) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (stream.width > previousStream.width ||
|
|
154
|
+
stream.height > previousStream.height) {
|
|
155
|
+
validVideoStreams.push(stream);
|
|
156
|
+
validVideoIds.push(stream.id);
|
|
157
|
+
} else if (stream.width == previousStream.width &&
|
|
158
|
+
stream.height == previousStream.height) {
|
|
159
|
+
const previousCodec =
|
|
160
|
+
MimeUtils.getNormalizedCodec(previousStream.codecs);
|
|
161
|
+
const currentCodec =
|
|
162
|
+
MimeUtils.getNormalizedCodec(stream.codecs);
|
|
163
|
+
if (previousCodec == currentCodec) {
|
|
164
|
+
if (stream.bandwidth < previousStream.bandwidth) {
|
|
165
|
+
validVideoStreams.push(stream);
|
|
166
|
+
validVideoIds.push(stream.id);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
120
169
|
}
|
|
170
|
+
}
|
|
171
|
+
validVideoStreamsMap.set(groupId, validVideoStreams);
|
|
172
|
+
}
|
|
121
173
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
if (group.size() === countCodecs) {
|
|
132
|
-
maxDensity = Math.max(maxDensity, density);
|
|
174
|
+
// Filter out any variants that don't match, forcing AbrManager to choose
|
|
175
|
+
// from a single video codec and a single audio codec possible.
|
|
176
|
+
manifest.variants = manifest.variants.filter((variant) => {
|
|
177
|
+
const audio = variant.audio;
|
|
178
|
+
const video = variant.video;
|
|
179
|
+
if (audio) {
|
|
180
|
+
if (!validAudioIds.includes(audio.id)) {
|
|
181
|
+
shaka.log.debug('Dropping Variant (better codec available)', variant);
|
|
182
|
+
return false;
|
|
133
183
|
}
|
|
134
184
|
}
|
|
185
|
+
if (video) {
|
|
186
|
+
if (!validVideoIds.includes(video.id)) {
|
|
187
|
+
shaka.log.debug('Dropping Variant (better codec available)', variant);
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return true;
|
|
135
192
|
});
|
|
136
|
-
|
|
137
|
-
return maxDensity ? codecGroupsByDensity.get(maxDensity) : variantsByCodecs;
|
|
138
193
|
}
|
|
139
194
|
|
|
140
195
|
/**
|
|
@@ -170,135 +225,6 @@ shaka.util.StreamUtils = class {
|
|
|
170
225
|
return subset;
|
|
171
226
|
}
|
|
172
227
|
|
|
173
|
-
/**
|
|
174
|
-
* Choose the codecs by configured preferred decoding attributes.
|
|
175
|
-
*
|
|
176
|
-
* @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
|
|
177
|
-
* @param {!Array.<string>} attributes
|
|
178
|
-
* @return {string}
|
|
179
|
-
* @private
|
|
180
|
-
*/
|
|
181
|
-
static chooseCodecsByDecodingAttributes_(variantsByCodecs, attributes) {
|
|
182
|
-
const StreamUtils = shaka.util.StreamUtils;
|
|
183
|
-
|
|
184
|
-
for (const attribute of attributes) {
|
|
185
|
-
if (attribute == StreamUtils.DecodingAttributes.SMOOTH ||
|
|
186
|
-
attribute == StreamUtils.DecodingAttributes.POWER) {
|
|
187
|
-
variantsByCodecs = StreamUtils.chooseCodecsByMediaCapabilitiesInfo_(
|
|
188
|
-
variantsByCodecs, attribute);
|
|
189
|
-
// If we only have one smooth or powerEfficient codecs, choose it as the
|
|
190
|
-
// best codecs.
|
|
191
|
-
if (variantsByCodecs.size() == 1) {
|
|
192
|
-
return variantsByCodecs.keys()[0];
|
|
193
|
-
}
|
|
194
|
-
} else if (attribute == StreamUtils.DecodingAttributes.BANDWIDTH) {
|
|
195
|
-
return StreamUtils.findCodecsByLowestBandwidth_(variantsByCodecs);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
// If there's no configured decoding preferences, or we have multiple codecs
|
|
199
|
-
// that meets the configured decoding preferences, choose the one with
|
|
200
|
-
// the lowest bandwidth.
|
|
201
|
-
return StreamUtils.findCodecsByLowestBandwidth_(variantsByCodecs);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Choose the best codecs by configured preferred MediaCapabilitiesInfo
|
|
206
|
-
* attributes.
|
|
207
|
-
*
|
|
208
|
-
* @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
|
|
209
|
-
* @param {string} attribute
|
|
210
|
-
* @return {!shaka.util.MultiMap.<shaka.extern.Variant>}
|
|
211
|
-
* @private
|
|
212
|
-
*/
|
|
213
|
-
static chooseCodecsByMediaCapabilitiesInfo_(variantsByCodecs, attribute) {
|
|
214
|
-
let highestScore = 0;
|
|
215
|
-
const bestVariantsByCodecs = new shaka.util.MultiMap();
|
|
216
|
-
variantsByCodecs.forEach((codecs, variants) => {
|
|
217
|
-
let sum = 0;
|
|
218
|
-
let num = 0;
|
|
219
|
-
|
|
220
|
-
for (const variant of variants) {
|
|
221
|
-
if (variant.decodingInfos.length) {
|
|
222
|
-
sum += variant.decodingInfos[0][attribute] ? 1 : 0;
|
|
223
|
-
num++;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const averageScore = sum / num;
|
|
228
|
-
shaka.log.debug('codecs', codecs, 'avg', attribute, averageScore);
|
|
229
|
-
|
|
230
|
-
if (averageScore > highestScore) {
|
|
231
|
-
bestVariantsByCodecs.clear();
|
|
232
|
-
bestVariantsByCodecs.push(codecs, variants);
|
|
233
|
-
highestScore = averageScore;
|
|
234
|
-
} else if (averageScore == highestScore) {
|
|
235
|
-
bestVariantsByCodecs.push(codecs, variants);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
return bestVariantsByCodecs;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Find the lowest-bandwidth (best) codecs.
|
|
243
|
-
* Compute the average bandwidth for each group of variants.
|
|
244
|
-
*
|
|
245
|
-
* @param {!shaka.util.MultiMap.<shaka.extern.Variant>} variantsByCodecs
|
|
246
|
-
* @return {string}
|
|
247
|
-
* @private
|
|
248
|
-
*/
|
|
249
|
-
static findCodecsByLowestBandwidth_(variantsByCodecs) {
|
|
250
|
-
let bestCodecs = '';
|
|
251
|
-
let lowestAverageBandwidth = Infinity;
|
|
252
|
-
|
|
253
|
-
variantsByCodecs.forEach((codecs, variants) => {
|
|
254
|
-
let sum = 0;
|
|
255
|
-
let num = 0;
|
|
256
|
-
for (const variant of variants) {
|
|
257
|
-
sum += variant.bandwidth || 0;
|
|
258
|
-
++num;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const averageBandwidth = sum / num;
|
|
262
|
-
shaka.log.debug('codecs', codecs, 'avg bandwidth', averageBandwidth);
|
|
263
|
-
|
|
264
|
-
if (averageBandwidth < lowestAverageBandwidth) {
|
|
265
|
-
bestCodecs = codecs;
|
|
266
|
-
lowestAverageBandwidth = averageBandwidth;
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
goog.asserts.assert(bestCodecs !== '', 'Should have chosen codecs!');
|
|
271
|
-
goog.asserts.assert(!isNaN(lowestAverageBandwidth),
|
|
272
|
-
'Bandwidth should be a number!');
|
|
273
|
-
|
|
274
|
-
return bestCodecs;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Get a string representing all codecs used in a variant.
|
|
279
|
-
*
|
|
280
|
-
* @param {!shaka.extern.Variant} variant
|
|
281
|
-
* @return {string}
|
|
282
|
-
* @private
|
|
283
|
-
*/
|
|
284
|
-
static getVariantCodecs_(variant) {
|
|
285
|
-
// Only consider the base of the codec string. For example, these should
|
|
286
|
-
// both be considered the same codec: avc1.42c01e, avc1.4d401f
|
|
287
|
-
let baseVideoCodec = '';
|
|
288
|
-
if (variant.video) {
|
|
289
|
-
baseVideoCodec =
|
|
290
|
-
shaka.util.MimeUtils.getNormalizedCodec(variant.video.codecs);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
let baseAudioCodec = '';
|
|
294
|
-
if (variant.audio) {
|
|
295
|
-
baseAudioCodec =
|
|
296
|
-
shaka.util.MimeUtils.getNormalizedCodec(variant.audio.codecs);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return baseVideoCodec + '-' + baseAudioCodec;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
228
|
/**
|
|
303
229
|
* Filter the variants in |manifest| to only include the variants that meet
|
|
304
230
|
* the given restrictions.
|
|
@@ -402,14 +328,11 @@ shaka.util.StreamUtils = class {
|
|
|
402
328
|
* Alters the given Manifest to filter out any unplayable streams.
|
|
403
329
|
*
|
|
404
330
|
* @param {shaka.media.DrmEngine} drmEngine
|
|
405
|
-
* @param {?shaka.extern.Variant} currentVariant
|
|
406
331
|
* @param {shaka.extern.Manifest} manifest
|
|
407
332
|
*/
|
|
408
|
-
static async filterManifest(drmEngine,
|
|
409
|
-
await shaka.util.StreamUtils.filterManifestByMediaCapabilities(
|
|
410
|
-
manifest.offlineSessionIds.length > 0);
|
|
411
|
-
shaka.util.StreamUtils.filterManifestByCurrentVariant(
|
|
412
|
-
currentVariant, manifest);
|
|
333
|
+
static async filterManifest(drmEngine, manifest) {
|
|
334
|
+
await shaka.util.StreamUtils.filterManifestByMediaCapabilities(
|
|
335
|
+
drmEngine, manifest, manifest.offlineSessionIds.length > 0);
|
|
413
336
|
shaka.util.StreamUtils.filterTextStreams_(manifest);
|
|
414
337
|
await shaka.util.StreamUtils.filterImageStreams_(manifest);
|
|
415
338
|
}
|
|
@@ -419,30 +342,53 @@ shaka.util.StreamUtils = class {
|
|
|
419
342
|
* Alters the given Manifest to filter out any streams unsupported by the
|
|
420
343
|
* platform via MediaCapabilities.decodingInfo() API.
|
|
421
344
|
*
|
|
345
|
+
* @param {shaka.media.DrmEngine} drmEngine
|
|
422
346
|
* @param {shaka.extern.Manifest} manifest
|
|
423
347
|
* @param {boolean} usePersistentLicenses
|
|
424
348
|
*/
|
|
425
349
|
static async filterManifestByMediaCapabilities(
|
|
426
|
-
manifest, usePersistentLicenses) {
|
|
350
|
+
drmEngine, manifest, usePersistentLicenses) {
|
|
427
351
|
goog.asserts.assert(navigator.mediaCapabilities,
|
|
428
352
|
'MediaCapabilities should be valid.');
|
|
429
353
|
|
|
430
354
|
await shaka.util.StreamUtils.getDecodingInfosForVariants(
|
|
431
355
|
manifest.variants, usePersistentLicenses, /* srcEquals= */ false,
|
|
432
356
|
/** preferredKeySystems= */ []);
|
|
357
|
+
|
|
358
|
+
let keySystem = null;
|
|
359
|
+
if (drmEngine) {
|
|
360
|
+
const drmInfo = drmEngine.getDrmInfo();
|
|
361
|
+
if (drmInfo) {
|
|
362
|
+
keySystem = drmInfo.keySystem;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
367
|
+
const Capabilities = shaka.media.Capabilities;
|
|
368
|
+
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
369
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
370
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
371
|
+
const isXboxOne = shaka.util.Platform.isXboxOne();
|
|
372
|
+
|
|
433
373
|
manifest.variants = manifest.variants.filter((variant) => {
|
|
434
374
|
// See: https://github.com/shaka-project/shaka-player/issues/3860
|
|
435
375
|
const video = variant.video;
|
|
376
|
+
const videoWidth = (video && video.width) || 0;
|
|
377
|
+
const videoHeight = (video && video.height) || 0;
|
|
436
378
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
379
|
+
// See: https://github.com/shaka-project/shaka-player/issues/3380
|
|
380
|
+
// Note: it makes sense to drop early
|
|
381
|
+
if (isXboxOne && video &&
|
|
382
|
+
(videoWidth > 1920 || videoHeight > 1080) &&
|
|
383
|
+
(video.codecs.includes('avc1.') || video.codecs.includes('avc3.'))
|
|
384
|
+
) {
|
|
385
|
+
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
386
|
+
StreamUtils.getVariantSummaryString_(variant));
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
442
389
|
|
|
443
390
|
if (video) {
|
|
444
391
|
let videoCodecs = StreamUtils.getCorrectVideoCodecs_(video.codecs);
|
|
445
|
-
|
|
446
392
|
// For multiplexed streams. Here we must check the audio of the
|
|
447
393
|
// stream to see if it is compatible.
|
|
448
394
|
if (video.codecs.includes(',')) {
|
|
@@ -451,7 +397,6 @@ shaka.util.StreamUtils = class {
|
|
|
451
397
|
videoCodecs = ManifestParserUtils.guessCodecs(
|
|
452
398
|
ContentType.VIDEO, allCodecs);
|
|
453
399
|
videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
454
|
-
|
|
455
400
|
let audioCodecs = ManifestParserUtils.guessCodecs(
|
|
456
401
|
ContentType.AUDIO, allCodecs);
|
|
457
402
|
audioCodecs = StreamUtils.getCorrectAudioCodecs_(audioCodecs);
|
|
@@ -493,19 +438,19 @@ shaka.util.StreamUtils = class {
|
|
|
493
438
|
audio.codecs = codecs;
|
|
494
439
|
}
|
|
495
440
|
|
|
496
|
-
// See: https://github.com/shaka-project/shaka-player/issues/3380
|
|
497
|
-
if (shaka.util.Platform.isXboxOne() && video &&
|
|
498
|
-
((video.width && video.width > 1920) ||
|
|
499
|
-
(video.height && video.height > 1080)) &&
|
|
500
|
-
(video.codecs.includes('avc1.') ||
|
|
501
|
-
video.codecs.includes('avc3.'))) {
|
|
502
|
-
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
503
|
-
StreamUtils.getVariantSummaryString_(variant));
|
|
504
|
-
return false;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
441
|
const supported = variant.decodingInfos.some((decodingInfo) => {
|
|
508
|
-
|
|
442
|
+
if (!decodingInfo.supported) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
if (keySystem) {
|
|
446
|
+
const keySystemAccess = decodingInfo.keySystemAccess;
|
|
447
|
+
if (keySystemAccess) {
|
|
448
|
+
if (keySystemAccess.keySystem != keySystem) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return true;
|
|
509
454
|
});
|
|
510
455
|
// Filter out all unsupported variants.
|
|
511
456
|
if (!supported) {
|
|
@@ -1013,7 +958,10 @@ shaka.util.StreamUtils = class {
|
|
|
1013
958
|
static async filterImageStreams_(manifest) {
|
|
1014
959
|
const imageStreams = [];
|
|
1015
960
|
for (const stream of manifest.imageStreams) {
|
|
1016
|
-
|
|
961
|
+
let mimeType = stream.mimeType;
|
|
962
|
+
if (mimeType == 'application/mp4' && stream.codecs == 'mjpg') {
|
|
963
|
+
mimeType = 'image/jpg';
|
|
964
|
+
}
|
|
1017
965
|
if (!shaka.util.StreamUtils.supportedImageMimeTypes_.has(mimeType)) {
|
|
1018
966
|
const minImage = shaka.util.StreamUtils.minImage_.get(mimeType);
|
|
1019
967
|
if (minImage) {
|
|
@@ -1163,6 +1111,7 @@ shaka.util.StreamUtils = class {
|
|
|
1163
1111
|
frameRate: null,
|
|
1164
1112
|
pixelAspectRatio: null,
|
|
1165
1113
|
hdr: null,
|
|
1114
|
+
videoLayout: null,
|
|
1166
1115
|
mimeType: mimeType,
|
|
1167
1116
|
audioMimeType: audioMimeType,
|
|
1168
1117
|
videoMimeType: videoMimeType,
|
|
@@ -1198,6 +1147,7 @@ shaka.util.StreamUtils = class {
|
|
|
1198
1147
|
track.pixelAspectRatio = video.pixelAspectRatio || null;
|
|
1199
1148
|
track.videoBandwidth = video.bandwidth || null;
|
|
1200
1149
|
track.hdr = video.hdr || null;
|
|
1150
|
+
track.videoLayout = video.videoLayout || null;
|
|
1201
1151
|
}
|
|
1202
1152
|
|
|
1203
1153
|
if (audio) {
|
|
@@ -1238,6 +1188,7 @@ shaka.util.StreamUtils = class {
|
|
|
1238
1188
|
frameRate: null,
|
|
1239
1189
|
pixelAspectRatio: null,
|
|
1240
1190
|
hdr: null,
|
|
1191
|
+
videoLayout: null,
|
|
1241
1192
|
mimeType: stream.mimeType,
|
|
1242
1193
|
audioMimeType: null,
|
|
1243
1194
|
videoMimeType: null,
|
|
@@ -1314,10 +1265,11 @@ shaka.util.StreamUtils = class {
|
|
|
1314
1265
|
frameRate: null,
|
|
1315
1266
|
pixelAspectRatio: null,
|
|
1316
1267
|
hdr: null,
|
|
1268
|
+
videoLayout: null,
|
|
1317
1269
|
mimeType: stream.mimeType,
|
|
1318
1270
|
audioMimeType: null,
|
|
1319
1271
|
videoMimeType: null,
|
|
1320
|
-
codecs: null,
|
|
1272
|
+
codecs: stream.codecs || null,
|
|
1321
1273
|
audioCodec: null,
|
|
1322
1274
|
videoCodec: null,
|
|
1323
1275
|
primary: false,
|
|
@@ -1441,6 +1393,7 @@ shaka.util.StreamUtils = class {
|
|
|
1441
1393
|
frameRate: null,
|
|
1442
1394
|
pixelAspectRatio: null,
|
|
1443
1395
|
hdr: null,
|
|
1396
|
+
videoLayout: null,
|
|
1444
1397
|
mimeType: null,
|
|
1445
1398
|
audioMimeType: null,
|
|
1446
1399
|
videoMimeType: null,
|
|
@@ -1495,52 +1448,6 @@ shaka.util.StreamUtils = class {
|
|
|
1495
1448
|
}
|
|
1496
1449
|
|
|
1497
1450
|
|
|
1498
|
-
/**
|
|
1499
|
-
* Filters variants according to the given audio channel count config.
|
|
1500
|
-
*
|
|
1501
|
-
* @param {!Array.<shaka.extern.Variant>} variants
|
|
1502
|
-
* @param {number} preferredAudioChannelCount
|
|
1503
|
-
* @return {!Array.<!shaka.extern.Variant>}
|
|
1504
|
-
*/
|
|
1505
|
-
static filterVariantsByAudioChannelCount(
|
|
1506
|
-
variants, preferredAudioChannelCount) {
|
|
1507
|
-
// Group variants by their audio channel counts.
|
|
1508
|
-
const variantsWithChannelCounts =
|
|
1509
|
-
variants.filter((v) => v.audio && v.audio.channelsCount);
|
|
1510
|
-
|
|
1511
|
-
/** @type {!Map.<number, !Array.<shaka.extern.Variant>>} */
|
|
1512
|
-
const variantsByChannelCount = new Map();
|
|
1513
|
-
for (const variant of variantsWithChannelCounts) {
|
|
1514
|
-
const count = variant.audio.channelsCount;
|
|
1515
|
-
goog.asserts.assert(count != null, 'Must have count after filtering!');
|
|
1516
|
-
if (!variantsByChannelCount.has(count)) {
|
|
1517
|
-
variantsByChannelCount.set(count, []);
|
|
1518
|
-
}
|
|
1519
|
-
variantsByChannelCount.get(count).push(variant);
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
/** @type {!Array.<number>} */
|
|
1523
|
-
const channelCounts = Array.from(variantsByChannelCount.keys());
|
|
1524
|
-
|
|
1525
|
-
// If no variant has audio channel count info, return the original variants.
|
|
1526
|
-
if (channelCounts.length == 0) {
|
|
1527
|
-
return variants;
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
// Choose the variants with the largest number of audio channels less than
|
|
1531
|
-
// or equal to the configured number of audio channels.
|
|
1532
|
-
const countLessThanOrEqualtoConfig =
|
|
1533
|
-
channelCounts.filter((count) => count <= preferredAudioChannelCount);
|
|
1534
|
-
if (countLessThanOrEqualtoConfig.length) {
|
|
1535
|
-
return variantsByChannelCount.get(
|
|
1536
|
-
Math.max(...countLessThanOrEqualtoConfig));
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
// If all variants have more audio channels than the config, choose the
|
|
1540
|
-
// variants with the fewest audio channels.
|
|
1541
|
-
return variantsByChannelCount.get(Math.min(...channelCounts));
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
1451
|
/**
|
|
1545
1452
|
* Chooses streams according to the given config.
|
|
1546
1453
|
* Works both for Stream and Track types due to their similarities.
|
|
@@ -1691,6 +1598,23 @@ shaka.util.StreamUtils = class {
|
|
|
1691
1598
|
}
|
|
1692
1599
|
|
|
1693
1600
|
|
|
1601
|
+
/**
|
|
1602
|
+
* Indicates if some of the variant's streams are fastSwitching.
|
|
1603
|
+
*
|
|
1604
|
+
* @param {shaka.extern.Variant} variant
|
|
1605
|
+
* @return {boolean}
|
|
1606
|
+
*/
|
|
1607
|
+
static isFastSwitching(variant) {
|
|
1608
|
+
if (variant.audio && variant.audio.fastSwitching) {
|
|
1609
|
+
return true;
|
|
1610
|
+
}
|
|
1611
|
+
if (variant.video && variant.video.fastSwitching) {
|
|
1612
|
+
return true;
|
|
1613
|
+
}
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
|
|
1694
1618
|
/**
|
|
1695
1619
|
* Returns a string of a variant, with the attribute values of its audio
|
|
1696
1620
|
* and/or video streams for log printing.
|
|
@@ -1762,7 +1686,6 @@ shaka.util.StreamUtils.nextTrackId_ = 0;
|
|
|
1762
1686
|
shaka.util.StreamUtils.DecodingAttributes = {
|
|
1763
1687
|
SMOOTH: 'smooth',
|
|
1764
1688
|
POWER: 'powerEfficient',
|
|
1765
|
-
BANDWIDTH: 'bandwidth',
|
|
1766
1689
|
};
|
|
1767
1690
|
|
|
1768
1691
|
/**
|