shaka-player 4.4.3 → 4.5.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.
Files changed (198) hide show
  1. package/.github/workflows/release-please.yaml +2 -27
  2. package/CHANGELOG.md +64 -45
  3. package/README.md +16 -10
  4. package/demo/asset_card.js +18 -21
  5. package/demo/cast_receiver/index.html +0 -1
  6. package/demo/close_button.js +0 -3
  7. package/demo/common/asset.js +22 -5
  8. package/demo/common/assets.js +132 -49
  9. package/demo/config.js +192 -253
  10. package/demo/custom.js +39 -98
  11. package/demo/front.js +7 -10
  12. package/demo/index.html +19 -22
  13. package/demo/input.js +6 -11
  14. package/demo/input_container.js +8 -9
  15. package/demo/main.js +51 -123
  16. package/demo/search.js +22 -34
  17. package/demo/service_worker.js +0 -3
  18. package/demo/tooltip.js +3 -5
  19. package/demo/visualizer.js +3 -5
  20. package/demo/visualizer_button.js +1 -20
  21. package/dist/demo.compiled.debug.js +152 -178
  22. package/dist/demo.compiled.debug.map +4 -4
  23. package/dist/demo.compiled.js +152 -178
  24. package/dist/demo.compiled.map +4 -4
  25. package/dist/deps.js +27 -24
  26. package/dist/locales.js +31 -31
  27. package/dist/receiver.compiled.debug.js +22 -43
  28. package/dist/receiver.compiled.debug.map +4 -4
  29. package/dist/receiver.compiled.js +22 -43
  30. package/dist/receiver.compiled.map +4 -4
  31. package/dist/shaka-player.compiled.d.ts +507 -365
  32. package/dist/shaka-player.compiled.debug.d.ts +507 -365
  33. package/dist/shaka-player.compiled.debug.externs.js +205 -51
  34. package/dist/shaka-player.compiled.debug.js +541 -450
  35. package/dist/shaka-player.compiled.debug.map +4 -4
  36. package/dist/shaka-player.compiled.externs.js +205 -51
  37. package/dist/shaka-player.compiled.js +1120 -1066
  38. package/dist/shaka-player.compiled.map +4 -4
  39. package/dist/shaka-player.ui.d.ts +562 -410
  40. package/dist/shaka-player.ui.debug.d.ts +562 -410
  41. package/dist/shaka-player.ui.debug.externs.js +226 -51
  42. package/dist/shaka-player.ui.debug.js +606 -506
  43. package/dist/shaka-player.ui.debug.map +4 -4
  44. package/dist/shaka-player.ui.externs.js +226 -51
  45. package/dist/shaka-player.ui.js +1266 -1207
  46. package/dist/shaka-player.ui.map +4 -4
  47. package/docs/design/lcevc-integration.md +14 -14
  48. package/docs/tutorials/faq.md +27 -55
  49. package/docs/tutorials/index.json +2 -1
  50. package/docs/tutorials/lcevc.md +118 -0
  51. package/docs/tutorials/ui-customization.md +4 -0
  52. package/externs/css_style_declaration.js +19 -0
  53. package/externs/lcevc.js +37 -13
  54. package/externs/media_remote.js +68 -0
  55. package/externs/mediatailor.js +193 -0
  56. package/externs/pictureinpicture.js +11 -0
  57. package/externs/shaka/ads.js +27 -0
  58. package/externs/shaka/manifest.js +10 -5
  59. package/externs/shaka/manifest_parser.js +7 -1
  60. package/externs/shaka/offline.js +4 -0
  61. package/externs/shaka/player.js +12 -1
  62. package/karma.conf.js +7 -3
  63. package/lib/abr/simple_abr_manager.js +43 -3
  64. package/lib/ads/ad_manager.js +104 -50
  65. package/lib/ads/media_tailor_ad.js +297 -0
  66. package/lib/ads/media_tailor_ad_manager.js +828 -0
  67. package/lib/cea/ts_cea_parser.js +15 -2
  68. package/lib/config/codec_switching_strategy.js +24 -0
  69. package/lib/dash/content_protection.js +120 -2
  70. package/lib/dash/dash_parser.js +75 -12
  71. package/lib/dash/mpd_utils.js +10 -6
  72. package/lib/dash/segment_base.js +13 -5
  73. package/lib/dash/segment_list.js +13 -5
  74. package/lib/dash/segment_template.js +43 -85
  75. package/lib/dependencies/all.js +8 -7
  76. package/lib/hls/hls_parser.js +44 -16
  77. package/lib/lcevc/lcevc_dec.js +220 -0
  78. package/lib/media/adaptation_set.js +22 -11
  79. package/lib/media/adaptation_set_criteria.js +25 -7
  80. package/lib/media/media_source_engine.js +215 -27
  81. package/lib/media/segment_index.js +1 -1
  82. package/lib/media/segment_reference.js +7 -7
  83. package/lib/media/streaming_engine.js +33 -18
  84. package/lib/mss/mss_parser.js +1 -0
  85. package/lib/net/networking_engine.js +1 -0
  86. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  87. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  88. package/lib/offline/manifest_converter.js +1 -0
  89. package/lib/offline/storage.js +3 -0
  90. package/lib/player.js +142 -72
  91. package/lib/routing/payload.js +5 -1
  92. package/lib/text/cue.js +15 -0
  93. package/lib/text/ttml_text_parser.js +17 -0
  94. package/lib/text/ui_text_displayer.js +4 -0
  95. package/lib/text/vtt_text_parser.js +33 -20
  96. package/lib/transmuxer/h265.js +862 -0
  97. package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
  98. package/lib/transmuxer/ts_transmuxer.js +160 -15
  99. package/lib/util/error.js +28 -9
  100. package/lib/util/exp_golomb.js +30 -2
  101. package/lib/util/fake_event.js +3 -0
  102. package/lib/util/mp4_generator.js +4 -4
  103. package/lib/util/periods.js +2 -0
  104. package/lib/util/platform.js +40 -0
  105. package/lib/util/player_configuration.js +8 -0
  106. package/lib/util/state_history.js +6 -2
  107. package/lib/util/stream_utils.js +133 -217
  108. package/lib/util/ts_parser.js +226 -40
  109. package/maintained-branches.md +3 -2
  110. package/package.json +4 -6
  111. package/roadmap.md +15 -5
  112. package/shaka-player.uncompiled.js +2 -1
  113. package/support.html +0 -1
  114. package/test/cast/cast_receiver_integration.js +47 -0
  115. package/test/codec_switching/codec_switching_integration.js +181 -0
  116. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  117. package/test/dash/dash_parser_integration.js +73 -0
  118. package/test/dash/dash_parser_live_unit.js +2 -0
  119. package/test/dash/dash_parser_manifest_unit.js +42 -0
  120. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  121. package/test/dash/dash_parser_segment_list_unit.js +2 -0
  122. package/test/dash/dash_parser_segment_template_unit.js +2 -0
  123. package/test/demo/demo_unit.js +0 -16
  124. package/test/hls/hls_live_unit.js +2 -0
  125. package/test/hls/hls_parser_unit.js +8 -6
  126. package/test/media/adaptation_set_criteria_unit.js +118 -0
  127. package/test/media/adaptation_set_unit.js +1 -0
  128. package/test/media/media_source_engine_unit.js +165 -1
  129. package/test/media/segment_index_unit.js +4 -4
  130. package/test/media/segment_prefetch_unit.js +1 -1
  131. package/test/media/streaming_engine_unit.js +17 -17
  132. package/test/mss/mss_parser_unit.js +2 -0
  133. package/test/offline/manifest_convert_unit.js +5 -0
  134. package/test/offline/storage_integration.js +1 -4
  135. package/test/player_unit.js +102 -131
  136. package/test/routing/walker_unit.js +1 -0
  137. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  138. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  139. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  140. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  141. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  142. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  143. package/test/test/assets/dash-aes-128/license +1 -0
  144. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  145. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  146. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  147. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  148. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  149. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  150. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  151. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  152. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  153. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  154. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  155. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  156. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  157. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  158. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  159. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  160. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  161. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  162. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  163. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  164. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  165. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  166. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  167. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  168. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  169. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  170. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  171. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  172. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  173. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  174. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  175. package/test/test/util/dash_parser_util.js +4 -0
  176. package/test/test/util/fake_ad_manager.js +20 -0
  177. package/test/test/util/fake_media_source_engine.js +8 -2
  178. package/test/test/util/manifest_generator.js +7 -3
  179. package/test/test/util/mss_parser_util.js +4 -0
  180. package/test/test/util/offline_utils.js +1 -0
  181. package/test/test/util/streaming_engine_util.js +7 -4
  182. package/test/text/ttml_text_parser_unit.js +52 -0
  183. package/test/text/vtt_text_parser_unit.js +103 -31
  184. package/test/transmuxer/transmuxer_integration.js +117 -0
  185. package/test/ui/ui_unit.js +3 -10
  186. package/test/util/stream_utils_unit.js +208 -74
  187. package/ui/controls.js +125 -0
  188. package/ui/externs/ui.js +8 -1
  189. package/ui/pip_button.js +22 -120
  190. package/ui/remote_button.js +201 -0
  191. package/ui/ui.js +5 -2
  192. package/demo/common/message_ids.js +0 -309
  193. package/demo/locales/en.json +0 -288
  194. package/demo/locales/source.json +0 -1146
  195. package/externs/mux.js +0 -69
  196. package/lib/lcevc/lcevc_dil.js +0 -152
  197. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  198. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -7,6 +7,7 @@
7
7
  goog.provide('shaka.util.StreamUtils');
8
8
 
9
9
  goog.require('goog.asserts');
10
+ goog.require('shaka.config.CodecSwitchingStrategy');
10
11
  goog.require('shaka.log');
11
12
  goog.require('shaka.media.Capabilities');
12
13
  goog.require('shaka.text.TextEngine');
@@ -38,103 +39,148 @@ shaka.util.StreamUtils = class {
38
39
  preferredAudioCodecs, preferredAudioChannelCount,
39
40
  preferredDecodingAttributes) {
40
41
  const StreamUtils = shaka.util.StreamUtils;
42
+ const MimeUtils = shaka.util.MimeUtils;
41
43
 
42
44
  let variants = manifest.variants;
43
-
44
45
  // To start, choose the codecs based on configured preferences if available.
45
46
  if (preferredVideoCodecs.length || preferredAudioCodecs.length) {
46
47
  variants = StreamUtils.choosePreferredCodecs(variants,
47
48
  preferredVideoCodecs, preferredAudioCodecs);
48
49
  }
49
50
 
50
- // Consider a subset of variants based on audio channel
51
- // preferences.
52
- // For some content (#1013), surround-sound variants will use a different
53
- // codec than stereo variants, so it is important to choose codecs **after**
54
- // considering the audio channel config.
55
- variants = StreamUtils.filterVariantsByAudioChannelCount(
56
- variants, preferredAudioChannelCount);
57
-
58
- // Now organize variants into buckets by codecs.
59
- /** @type {!shaka.util.MultiMap.<shaka.extern.Variant>} */
60
- let variantsByCodecs = StreamUtils.getVariantsByCodecs_(variants);
61
- variantsByCodecs = StreamUtils.filterVariantsByDensity_(variantsByCodecs);
51
+ if (preferredDecodingAttributes.length) {
52
+ // group variants by resolution and choose preferred variants only
53
+ /** @type {!shaka.util.MultiMap.<shaka.extern.Variant>} */
54
+ const variantsByResolutionMap = new shaka.util.MultiMap();
55
+ for (const variant of variants) {
56
+ variantsByResolutionMap
57
+ .push(String(variant.video.width || 0), variant);
58
+ }
59
+ const bestVariants = [];
60
+ variantsByResolutionMap.forEach((width, variantsByResolution) => {
61
+ let highestMatch = 0;
62
+ let matchingVariants = [];
63
+ for (const variant of variantsByResolution) {
64
+ const matchCount = preferredDecodingAttributes.filter(
65
+ (attribute) => variant.decodingInfos[0][attribute],
66
+ ).length;
67
+ if (matchCount > highestMatch) {
68
+ highestMatch = matchCount;
69
+ matchingVariants = [variant];
70
+ } else if (matchCount == highestMatch) {
71
+ matchingVariants.push(variant);
72
+ }
73
+ }
74
+ bestVariants.push(...matchingVariants);
75
+ });
76
+ variants = bestVariants;
77
+ }
62
78
 
63
- const bestCodecs = StreamUtils.chooseCodecsByDecodingAttributes_(
64
- variantsByCodecs, preferredDecodingAttributes);
79
+ if (preferredAudioChannelCount) {
80
+ variants = StreamUtils.filterVariantsByAudioChannelCount(
81
+ variants, preferredAudioChannelCount);
82
+ }
65
83
 
66
- // Filter out any variants that don't match, forcing AbrManager to choose
67
- // from a single video codec and a single audio codec possible.
68
- manifest.variants = manifest.variants.filter((variant) => {
69
- const codecs = StreamUtils.getVariantCodecs_(variant);
70
- if (codecs == bestCodecs) {
71
- return true;
84
+ const audioStreamsSet = new Set();
85
+ const videoStreamsSet = new Set();
86
+ for (const variant of variants) {
87
+ if (variant.audio) {
88
+ audioStreamsSet.add(variant.audio);
89
+ }
90
+ if (variant.video) {
91
+ videoStreamsSet.add(variant.video);
72
92
  }
93
+ }
73
94
 
74
- shaka.log.debug('Dropping Variant (better codec available)', variant);
75
- return false;
95
+ const audioStreams = Array.from(audioStreamsSet).sort((v1, v2) => {
96
+ return v1.bandwidth - v2.bandwidth;
76
97
  });
77
- }
78
-
79
- /**
80
- * Get variants by codecs.
81
- *
82
- * @param {!Array<shaka.extern.Variant>} variants
83
- * @return {!shaka.util.MultiMap.<shaka.extern.Variant>}
84
- * @private
85
- */
86
- static getVariantsByCodecs_(variants) {
87
- const variantsByCodecs = new shaka.util.MultiMap();
88
- for (const variant of variants) {
89
- const variantCodecs = shaka.util.StreamUtils.getVariantCodecs_(variant);
90
- variantsByCodecs.push(variantCodecs, variant);
98
+ const audioStreamsMap = new Map();
99
+ const getAudioId = (stream) => {
100
+ return stream.language + (stream.channelsCount || 0) +
101
+ stream.roles.join(',') + stream.label;
102
+ };
103
+ for (const stream of audioStreams) {
104
+ const id = getAudioId(stream);
105
+ if (!audioStreamsMap.has(id)) {
106
+ audioStreamsMap.set(id, stream);
107
+ } else {
108
+ const includedStream = audioStreamsMap.get(id);
109
+ if (includedStream.bandwidth > stream.bandwidth) {
110
+ audioStreamsMap.set(id, stream);
111
+ }
112
+ }
91
113
  }
114
+ const validAudioStreams = [...audioStreamsMap.values()];
92
115
 
93
- return variantsByCodecs;
94
- }
116
+ const videoStreams = Array.from(videoStreamsSet)
117
+ .sort((v1, v2) => {
118
+ if (!v1.bandwidth || !v2.bandwidth) {
119
+ return v1.width - v2.width;
120
+ }
121
+ return v1.bandwidth - v2.bandwidth;
122
+ });
95
123
 
96
- /**
97
- * Filters variants by density.
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
- }
124
+ const isChangeTypeSupported =
125
+ shaka.media.Capabilities.isChangeTypeSupported();
116
126
 
117
- const density = video.width * video.height * (video.frameRate || 1);
118
- if (!codecGroupsByDensity.has(density)) {
119
- codecGroupsByDensity.set(density, new shaka.util.MultiMap());
127
+ const validVideoStreams = [];
128
+ for (const stream of videoStreams) {
129
+ if (!validVideoStreams.length) {
130
+ validVideoStreams.push(stream);
131
+ } else {
132
+ const previousStream = validVideoStreams[validVideoStreams.length - 1];
133
+ if (!isChangeTypeSupported) {
134
+ const previousCodec =
135
+ MimeUtils.getNormalizedCodec(previousStream.codecs);
136
+ const currentCodec =
137
+ MimeUtils.getNormalizedCodec(stream.codecs);
138
+ if (previousCodec !== currentCodec) {
139
+ continue;
140
+ }
141
+ }
142
+ if (stream.width > previousStream.width ||
143
+ stream.height > previousStream.height) {
144
+ validVideoStreams.push(stream);
145
+ } else if (stream.width == previousStream.width &&
146
+ stream.height == previousStream.height) {
147
+ const previousCodec =
148
+ MimeUtils.getNormalizedCodec(previousStream.codecs);
149
+ const currentCodec =
150
+ MimeUtils.getNormalizedCodec(stream.codecs);
151
+ if (previousCodec == currentCodec) {
152
+ if (stream.bandwidth < previousStream.bandwidth) {
153
+ validVideoStreams.push(stream);
154
+ }
155
+ }
120
156
  }
157
+ }
158
+ }
121
159
 
122
- /** @type {!shaka.util.MultiMap.<shaka.extern.Variant>} */
123
- const group = codecGroupsByDensity.get(density);
124
- group.push(codecs, variant);
125
-
126
- // We want to look at the groups in which all codecs are present.
127
- // Take the max density from those groups where all codecs are present.
128
- // Later, we will compare bandwidth numbers only within this group.
129
- // Effectively, only the bandwidth differences in the highest-res and
130
- // highest-framerate content will matter in choosing a codec.
131
- if (group.size() === countCodecs) {
132
- maxDensity = Math.max(maxDensity, density);
160
+ const validAudioIds =
161
+ validAudioStreams.map((audioStream) => audioStream.id);
162
+ const validVideoIds =
163
+ validVideoStreams.map((videoStream) => videoStream.id);
164
+
165
+ // Filter out any variants that don't match, forcing AbrManager to choose
166
+ // from a single video codec and a single audio codec possible.
167
+ manifest.variants = manifest.variants.filter((variant) => {
168
+ const audio = variant.audio;
169
+ const video = variant.video;
170
+ if (audio) {
171
+ if (!validAudioIds.includes(audio.id)) {
172
+ shaka.log.debug('Dropping Variant (better codec available)', variant);
173
+ return false;
174
+ }
175
+ }
176
+ if (video) {
177
+ if (!validVideoIds.includes(video.id)) {
178
+ shaka.log.debug('Dropping Variant (better codec available)', variant);
179
+ return false;
133
180
  }
134
181
  }
182
+ return true;
135
183
  });
136
-
137
- return maxDensity ? codecGroupsByDensity.get(maxDensity) : variantsByCodecs;
138
184
  }
139
185
 
140
186
  /**
@@ -170,135 +216,6 @@ shaka.util.StreamUtils = class {
170
216
  return subset;
171
217
  }
172
218
 
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
219
  /**
303
220
  * Filter the variants in |manifest| to only include the variants that meet
304
221
  * the given restrictions.
@@ -404,12 +321,12 @@ shaka.util.StreamUtils = class {
404
321
  * @param {shaka.media.DrmEngine} drmEngine
405
322
  * @param {?shaka.extern.Variant} currentVariant
406
323
  * @param {shaka.extern.Manifest} manifest
324
+ * @param {shaka.config.CodecSwitchingStrategy=} codecSwitchingStrategy
407
325
  */
408
- static async filterManifest(drmEngine, currentVariant, manifest) {
326
+ static async filterManifest(drmEngine, currentVariant, manifest,
327
+ codecSwitchingStrategy=shaka.config.CodecSwitchingStrategy.RELOAD) {
409
328
  await shaka.util.StreamUtils.filterManifestByMediaCapabilities(manifest,
410
329
  manifest.offlineSessionIds.length > 0);
411
- shaka.util.StreamUtils.filterManifestByCurrentVariant(
412
- currentVariant, manifest);
413
330
  shaka.util.StreamUtils.filterTextStreams_(manifest);
414
331
  await shaka.util.StreamUtils.filterImageStreams_(manifest);
415
332
  }
@@ -1510,6 +1427,7 @@ shaka.util.StreamUtils = class {
1510
1427
 
1511
1428
  /** @type {!Map.<number, !Array.<shaka.extern.Variant>>} */
1512
1429
  const variantsByChannelCount = new Map();
1430
+ const capableVariants = [];
1513
1431
  for (const variant of variantsWithChannelCounts) {
1514
1432
  const count = variant.audio.channelsCount;
1515
1433
  goog.asserts.assert(count != null, 'Must have count after filtering!');
@@ -1517,6 +1435,14 @@ shaka.util.StreamUtils = class {
1517
1435
  variantsByChannelCount.set(count, []);
1518
1436
  }
1519
1437
  variantsByChannelCount.get(count).push(variant);
1438
+ if (count <= preferredAudioChannelCount) {
1439
+ capableVariants.push(variant);
1440
+ }
1441
+ }
1442
+
1443
+ // return all capable channelcounts
1444
+ if (capableVariants.length) {
1445
+ return capableVariants;
1520
1446
  }
1521
1447
 
1522
1448
  /** @type {!Array.<number>} */
@@ -1527,15 +1453,6 @@ shaka.util.StreamUtils = class {
1527
1453
  return variants;
1528
1454
  }
1529
1455
 
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
1456
  // If all variants have more audio channels than the config, choose the
1540
1457
  // variants with the fewest audio channels.
1541
1458
  return variantsByChannelCount.get(Math.min(...channelCounts));
@@ -1762,7 +1679,6 @@ shaka.util.StreamUtils.nextTrackId_ = 0;
1762
1679
  shaka.util.StreamUtils.DecodingAttributes = {
1763
1680
  SMOOTH: 'smooth',
1764
1681
  POWER: 'powerEfficient',
1765
- BANDWIDTH: 'bandwidth',
1766
1682
  };
1767
1683
 
1768
1684
  /**