shaka-player 3.1.4 → 3.3.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 (214) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  3. package/.github/ISSUE_TEMPLATE/question.md +1 -1
  4. package/AUTHORS +6 -5
  5. package/CHANGELOG.md +363 -0
  6. package/CONTRIBUTORS +4 -2
  7. package/README.md +4 -4
  8. package/build/types/core +3 -0
  9. package/build/types/offline +1 -0
  10. package/build/types/polyfill +2 -0
  11. package/build/types/ui +2 -0
  12. package/demo/common/asset.js +9 -7
  13. package/demo/common/assets.js +28 -1
  14. package/demo/common/message_ids.js +15 -2
  15. package/demo/config.js +35 -2
  16. package/demo/index.html +1 -1
  17. package/demo/locales/en.json +14 -1
  18. package/demo/locales/source.json +56 -4
  19. package/demo/main.js +2 -1
  20. package/dist/controls.css +26 -2
  21. package/dist/controls.css.map +1 -1
  22. package/dist/demo.compiled.debug.js +24 -21
  23. package/dist/demo.compiled.debug.map +3 -3
  24. package/dist/demo.compiled.js +24 -21
  25. package/dist/demo.compiled.map +3 -3
  26. package/dist/deps.js +33 -25
  27. package/dist/locales.js +31 -29
  28. package/dist/receiver.compiled.debug.js +14 -12
  29. package/dist/receiver.compiled.debug.map +3 -3
  30. package/dist/receiver.compiled.js +14 -12
  31. package/dist/receiver.compiled.map +3 -3
  32. package/dist/shaka-player.compiled.d.ts +258 -20
  33. package/dist/shaka-player.compiled.debug.d.ts +258 -20
  34. package/dist/shaka-player.compiled.debug.externs.js +1005 -695
  35. package/dist/shaka-player.compiled.debug.js +720 -640
  36. package/dist/shaka-player.compiled.debug.map +4 -4
  37. package/dist/shaka-player.compiled.externs.js +1005 -695
  38. package/dist/shaka-player.compiled.js +850 -817
  39. package/dist/shaka-player.compiled.map +4 -4
  40. package/dist/shaka-player.ui.d.ts +274 -21
  41. package/dist/shaka-player.ui.debug.d.ts +274 -21
  42. package/dist/shaka-player.ui.debug.externs.js +766 -429
  43. package/dist/shaka-player.ui.debug.js +863 -765
  44. package/dist/shaka-player.ui.debug.map +4 -4
  45. package/dist/shaka-player.ui.externs.js +766 -429
  46. package/dist/shaka-player.ui.js +1042 -996
  47. package/dist/shaka-player.ui.map +4 -4
  48. package/docs/design/bg-fetch-after.gv +29 -0
  49. package/docs/design/bg-fetch-after.gv.png +0 -0
  50. package/docs/design/bg-fetch-before.gv +18 -0
  51. package/docs/design/bg-fetch-before.gv.png +0 -0
  52. package/docs/design/bg-fetch.md +134 -0
  53. package/docs/tutorials/blob-url.md +15 -0
  54. package/docs/tutorials/index.json +1 -0
  55. package/docs/tutorials/ui-customization.md +66 -0
  56. package/docs/tutorials/ui.md +5 -5
  57. package/externs/aria.js +6 -0
  58. package/externs/ima.js +3 -0
  59. package/externs/shaka/ads.js +29 -1
  60. package/externs/shaka/manifest.js +18 -2
  61. package/externs/shaka/manifest_parser.js +10 -1
  62. package/externs/shaka/net.js +20 -4
  63. package/externs/shaka/offline.js +36 -2
  64. package/externs/shaka/player.js +182 -13
  65. package/externs/shaka/text.js +24 -10
  66. package/externs/texttrack.js +3 -0
  67. package/externs/webcrypto.js +18 -0
  68. package/lib/abr/ewma.js +14 -0
  69. package/lib/abr/ewma_bandwidth_estimator.js +16 -2
  70. package/lib/abr/simple_abr_manager.js +6 -0
  71. package/lib/ads/ad_manager.js +16 -15
  72. package/lib/ads/client_side_ad.js +8 -0
  73. package/lib/ads/client_side_ad_manager.js +14 -6
  74. package/lib/ads/server_side_ad.js +7 -0
  75. package/lib/ads/server_side_ad_manager.js +19 -2
  76. package/lib/cast/cast_proxy.js +8 -0
  77. package/lib/cast/cast_utils.js +7 -1
  78. package/lib/cea/cea608_data_channel.js +56 -56
  79. package/lib/cea/cea608_memory.js +33 -33
  80. package/lib/cea/cea708_service.js +43 -43
  81. package/lib/cea/cea708_window.js +38 -38
  82. package/lib/cea/cea_decoder.js +13 -14
  83. package/lib/cea/cea_utils.js +23 -23
  84. package/lib/cea/dtvcc_packet_builder.js +7 -7
  85. package/lib/cea/i_caption_decoder.js +2 -3
  86. package/lib/cea/i_cea_parser.js +2 -2
  87. package/lib/cea/mp4_cea_parser.js +6 -6
  88. package/lib/dash/dash_parser.js +53 -14
  89. package/lib/dash/segment_base.js +25 -1
  90. package/lib/dash/segment_list.js +18 -9
  91. package/lib/dash/segment_template.js +23 -10
  92. package/lib/hls/hls_parser.js +210 -30
  93. package/lib/media/closed_caption_parser.js +1 -2
  94. package/lib/media/drm_engine.js +162 -192
  95. package/lib/media/quality_observer.js +291 -0
  96. package/lib/media/segment_index.js +9 -1
  97. package/lib/media/segment_reference.js +37 -5
  98. package/lib/media/streaming_engine.js +48 -10
  99. package/lib/net/http_fetch_plugin.js +31 -11
  100. package/lib/net/http_plugin_utils.js +1 -0
  101. package/lib/net/http_xhr_plugin.js +40 -14
  102. package/lib/net/networking_engine.js +82 -18
  103. package/lib/offline/download_info.js +68 -0
  104. package/lib/offline/download_manager.js +14 -7
  105. package/lib/offline/indexeddb/base_storage_cell.js +35 -0
  106. package/lib/offline/indexeddb/storage_mechanism.js +1 -1
  107. package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
  108. package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
  109. package/lib/offline/indexeddb/v5_storage_cell.js +5 -0
  110. package/lib/offline/manifest_converter.js +3 -1
  111. package/lib/offline/storage.js +404 -297
  112. package/lib/offline/stored_content_utils.js +2 -0
  113. package/lib/player.js +622 -153
  114. package/lib/polyfill/aria.js +82 -0
  115. package/lib/polyfill/random_uuid.js +52 -0
  116. package/lib/routing/walker.js +2 -3
  117. package/lib/text/cue.js +12 -0
  118. package/lib/text/srt_text_parser.js +4 -4
  119. package/lib/text/text_engine.js +2 -2
  120. package/lib/text/ttml_text_parser.js +25 -2
  121. package/lib/text/ui_text_displayer.js +2 -2
  122. package/lib/text/vtt_text_parser.js +2 -2
  123. package/lib/text/web_vtt_generator.js +55 -12
  124. package/lib/util/cmcd_manager.js +826 -0
  125. package/lib/util/error.js +12 -0
  126. package/lib/util/language_utils.js +12 -0
  127. package/lib/util/manifest_parser_utils.js +1 -0
  128. package/lib/util/mp4_box_parsers.js +20 -20
  129. package/lib/util/multi_map.js +8 -0
  130. package/lib/util/mutex.js +52 -0
  131. package/lib/util/periods.js +98 -64
  132. package/lib/util/player_configuration.js +31 -1
  133. package/lib/util/stream_utils.js +140 -85
  134. package/lib/util/xml_utils.js +31 -12
  135. package/package.json +1 -1
  136. package/roadmap.md +24 -22
  137. package/shaka-player.uncompiled.js +4 -0
  138. package/test/cast/cast_utils_unit.js +1 -0
  139. package/test/cea/cea608_memory_unit.js +1 -1
  140. package/test/cea/cea708_service_unit.js +8 -8
  141. package/test/cea/cea708_window_unit.js +6 -6
  142. package/test/cea/cea_decoder_unit.js +1 -1
  143. package/test/cea/dtvcc_packet_builder_unit.js +2 -2
  144. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  145. package/test/dash/dash_parser_live_unit.js +101 -1
  146. package/test/dash/dash_parser_manifest_unit.js +78 -2
  147. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  148. package/test/dash/dash_parser_segment_list_unit.js +2 -1
  149. package/test/dash/dash_parser_segment_template_unit.js +2 -1
  150. package/test/hls/hls_live_unit.js +2 -0
  151. package/test/hls/hls_parser_unit.js +252 -0
  152. package/test/media/drm_engine_integration.js +86 -12
  153. package/test/media/drm_engine_unit.js +310 -450
  154. package/test/media/quality_observer_unit.js +139 -0
  155. package/test/media/segment_reference_unit.js +16 -1
  156. package/test/media/streaming_engine_integration.js +2 -1
  157. package/test/media/streaming_engine_unit.js +2 -0
  158. package/test/net/http_plugin_unit.js +20 -15
  159. package/test/offline/manifest_convert_unit.js +2 -0
  160. package/test/offline/storage_integration.js +117 -23
  161. package/test/player_integration.js +151 -0
  162. package/test/player_src_equals_integration.js +52 -0
  163. package/test/player_unit.js +11 -33
  164. package/test/test/assets/chapters.srt +11 -0
  165. package/test/test/assets/chapters.vtt +10 -0
  166. package/test/test/util/cea_utils.js +12 -12
  167. package/test/test/util/dash_parser_util.js +4 -0
  168. package/test/test/util/fake_ad.js +7 -0
  169. package/test/test/util/fake_ad_manager.js +7 -0
  170. package/test/test/util/fake_drm_engine.js +9 -2
  171. package/test/test/util/manifest_generator.js +5 -2
  172. package/test/test/util/manifest_parser_util.js +3 -1
  173. package/test/test/util/test_scheme.js +14 -1
  174. package/test/text/ttml_text_parser_unit.js +47 -0
  175. package/test/text/web_vtt_generator_unit.js +81 -7
  176. package/test/ui/ui_unit.js +250 -0
  177. package/test/util/cmcd_manager_unit.js +277 -0
  178. package/test/util/stream_utils_unit.js +118 -10
  179. package/ui/airplay_button.js +2 -1
  180. package/ui/audio_language_selection.js +9 -5
  181. package/ui/cast_button.js +5 -6
  182. package/ui/constants.js +0 -3
  183. package/ui/context_menu.js +109 -0
  184. package/ui/controls.js +41 -7
  185. package/ui/controls.less +1 -0
  186. package/ui/enums.js +4 -0
  187. package/ui/externs/ui.js +28 -1
  188. package/ui/fast_forward_button.js +16 -8
  189. package/ui/fullscreen_button.js +2 -3
  190. package/ui/language_utils.js +1 -1
  191. package/ui/less/buttons.less +0 -4
  192. package/ui/less/containers.less +74 -0
  193. package/ui/less/overflow_menu.less +0 -10
  194. package/ui/less/tooltip.less +97 -0
  195. package/ui/locales/en.json +1 -0
  196. package/ui/locales/source.json +4 -0
  197. package/ui/loop_button.js +6 -3
  198. package/ui/mute_button.js +3 -4
  199. package/ui/overflow_menu.js +7 -28
  200. package/ui/pip_button.js +10 -7
  201. package/ui/play_button.js +2 -2
  202. package/ui/playback_rate_selection.js +11 -15
  203. package/ui/presentation_time.js +1 -3
  204. package/ui/resolution_selection.js +11 -7
  205. package/ui/rewind_button.js +17 -9
  206. package/ui/seek_bar.js +6 -6
  207. package/ui/settings_menu.js +36 -4
  208. package/ui/small_play_button.js +1 -0
  209. package/ui/spacer.js +1 -1
  210. package/ui/statistics_button.js +253 -0
  211. package/ui/text_selection.js +19 -15
  212. package/ui/ui.js +30 -0
  213. package/ui/ui_utils.js +1 -1
  214. package/ui/volume_bar.js +2 -4
@@ -15,10 +15,10 @@ shaka.cea.CeaUtils = class {
15
15
  /**
16
16
  * Emits a closed caption based on the state of the buffer.
17
17
  * @param {!shaka.text.Cue} topLevelCue
18
- * @param {!string} stream
18
+ * @param {string} stream
19
19
  * @param {!Array<!Array<?shaka.cea.CeaUtils.StyledChar>>} memory
20
- * @param {!number} startTime Start time of the cue.
21
- * @param {!number} endTime End time of the cue.
20
+ * @param {number} startTime Start time of the cue.
21
+ * @param {number} endTime End time of the cue.
22
22
  * @return {?shaka.cea.ICaptionDecoder.ClosedCaption}
23
23
  */
24
24
  static getParsedCaption(topLevelCue, stream, memory, startTime, endTime) {
@@ -153,12 +153,12 @@ shaka.cea.CeaUtils = class {
153
153
  }
154
154
 
155
155
  /**
156
- * @param {!number} startTime
157
- * @param {!number} endTime
158
- * @param {!boolean} underline
159
- * @param {!boolean} italics
160
- * @param {!string} txtColor
161
- * @param {!string} bgColor
156
+ * @param {number} startTime
157
+ * @param {number} endTime
158
+ * @param {boolean} underline
159
+ * @param {boolean} italics
160
+ * @param {string} txtColor
161
+ * @param {string} bgColor
162
162
  * @return {!shaka.text.Cue}
163
163
  */
164
164
  static createStyledCue(startTime, endTime, underline,
@@ -176,8 +176,8 @@ shaka.cea.CeaUtils = class {
176
176
  }
177
177
 
178
178
  /**
179
- * @param {!number} startTime
180
- * @param {!number} endTime
179
+ * @param {number} startTime
180
+ * @param {number} endTime
181
181
  * @return {!shaka.text.Cue}
182
182
  */
183
183
  static createLineBreakCue(startTime, endTime) {
@@ -198,61 +198,61 @@ shaka.cea.CeaUtils.StyledChar = class {
198
198
  */
199
199
  constructor(character, underline, italics, backgroundColor, textColor) {
200
200
  /**
201
- * @private {!string}
201
+ * @private {string}
202
202
  */
203
203
  this.character_ = character;
204
204
 
205
205
  /**
206
- * @private {!boolean}
206
+ * @private {boolean}
207
207
  */
208
208
  this.underline_ = underline;
209
209
 
210
210
  /**
211
- * @private {!boolean}
211
+ * @private {boolean}
212
212
  */
213
213
  this.italics_ = italics;
214
214
 
215
215
  /**
216
- * @private {!string}
216
+ * @private {string}
217
217
  */
218
218
  this.backgroundColor_ = backgroundColor;
219
219
 
220
220
  /**
221
- * @private {!string}
221
+ * @private {string}
222
222
  */
223
223
  this.textColor_ = textColor;
224
224
  }
225
225
 
226
226
  /**
227
- * @return {!string}
227
+ * @return {string}
228
228
  */
229
229
  getChar() {
230
230
  return this.character_;
231
231
  }
232
232
 
233
233
  /**
234
- * @return {!boolean}
234
+ * @return {boolean}
235
235
  */
236
236
  isUnderlined() {
237
237
  return this.underline_;
238
238
  }
239
239
 
240
240
  /**
241
- * @return {!boolean}
241
+ * @return {boolean}
242
242
  */
243
243
  isItalicized() {
244
244
  return this.italics_;
245
245
  }
246
246
 
247
247
  /**
248
- * @return {!string}
248
+ * @return {string}
249
249
  */
250
250
  getBackgroundColor() {
251
251
  return this.backgroundColor_;
252
252
  }
253
253
 
254
254
  /**
255
- * @return {!string}
255
+ * @return {string}
256
256
  */
257
257
  getTextColor() {
258
258
  return this.textColor_;
@@ -261,12 +261,12 @@ shaka.cea.CeaUtils.StyledChar = class {
261
261
 
262
262
  /**
263
263
  * Default background color for text.
264
- * @const {!string}
264
+ * @const {string}
265
265
  */
266
266
  shaka.cea.CeaUtils.DEFAULT_BG_COLOR = 'black';
267
267
 
268
268
  /**
269
269
  * Default text color.
270
- * @const {!string}
270
+ * @const {string}
271
271
  */
272
272
  shaka.cea.CeaUtils.DEFAULT_TXT_COLOR = 'white';
@@ -35,7 +35,7 @@ shaka.cea.DtvccPacketBuilder = class {
35
35
 
36
36
  /**
37
37
  * Keeps track of the number of bytes left to add in the current packet.
38
- * @private {!number}
38
+ * @private {number}
39
39
  */
40
40
  this.bytesLeftToAddInCurrentPacket_ = 0;
41
41
  }
@@ -107,7 +107,7 @@ shaka.cea.DtvccPacket = class {
107
107
  constructor(packetData) {
108
108
  /**
109
109
  * Keeps track of the position to read the next byte from in the packet.
110
- * @private {!number}
110
+ * @private {number}
111
111
  */
112
112
  this.pos_ = 0;
113
113
 
@@ -119,14 +119,14 @@ shaka.cea.DtvccPacket = class {
119
119
  }
120
120
 
121
121
  /**
122
- * @return {!boolean}
122
+ * @return {boolean}
123
123
  */
124
124
  hasMoreData() {
125
125
  return this.pos_ < this.packetData_.length;
126
126
  }
127
127
 
128
128
  /**
129
- * @return {!number}
129
+ * @return {number}
130
130
  */
131
131
  getPosition() {
132
132
  return this.pos_;
@@ -149,7 +149,7 @@ shaka.cea.DtvccPacket = class {
149
149
 
150
150
  /**
151
151
  * Skips the provided number of blocks in the buffer.
152
- * @param {!number} numBlocks
152
+ * @param {number} numBlocks
153
153
  * @throws {!shaka.util.Error}
154
154
  */
155
155
  skip(numBlocks) {
@@ -164,11 +164,11 @@ shaka.cea.DtvccPacket = class {
164
164
  };
165
165
 
166
166
  /**
167
- * @const {!number}
167
+ * @const {number}
168
168
  */
169
169
  shaka.cea.DtvccPacketBuilder.DTVCC_PACKET_DATA = 2;
170
170
 
171
171
  /**
172
- * @const {!number}
172
+ * @const {number}
173
173
  */
174
174
  shaka.cea.DtvccPacketBuilder.DTVCC_PACKET_START = 3;
@@ -5,7 +5,6 @@
5
5
  */
6
6
 
7
7
  goog.provide('shaka.cea.ICaptionDecoder');
8
- goog.provide('shaka.cea.ICaptionDecoder.ClosedCaption');
9
8
 
10
9
  goog.require('shaka.text.Cue');
11
10
 
@@ -23,7 +22,7 @@ shaka.cea.ICaptionDecoder = class {
23
22
  * @param {!Uint8Array} userDataSeiMessage
24
23
  * This is a User Data registered by Rec.ITU-T T.35 SEI message.
25
24
  * It is described in sections D.1.6 and D.2.6 of Rec. ITU-T H.264 (06/2019).
26
- * @param {!number} pts PTS when this packet was received, in seconds.
25
+ * @param {number} pts PTS when this packet was received, in seconds.
27
26
  */
28
27
  extract(userDataSeiMessage, pts) {}
29
28
 
@@ -46,7 +45,7 @@ shaka.cea.ICaptionDecoder = class {
46
45
  * Parsed Cue.
47
46
  * @typedef {{
48
47
  * cue: !shaka.text.Cue,
49
- * stream: !string
48
+ * stream: string
50
49
  * }}
51
50
  */
52
51
  shaka.cea.ICaptionDecoder.ClosedCaption;
@@ -39,7 +39,7 @@ shaka.cea.ICeaParser.DEFAULT_TIMESCALE_VALUE = 90000;
39
39
  /**
40
40
  * @typedef {{
41
41
  * packet: !Uint8Array,
42
- * pts: !number
42
+ * pts: number
43
43
  * }}
44
44
  *
45
45
  * @description Parsed Caption Packet.
@@ -47,7 +47,7 @@ shaka.cea.ICeaParser.DEFAULT_TIMESCALE_VALUE = 90000;
47
47
  * Caption packet. More specifically, it contains a "User data
48
48
  * registered by Recommendation ITU-T T.35 SEI message", from section D.1.6
49
49
  * and section D.2.6 of Rec. ITU-T H.264 (06/2019).
50
- * @property {!number} pts
50
+ * @property {number} pts
51
51
  * The presentation timestamp (pts) at which the ITU-T T.35 data shows up.
52
52
  * in seconds.
53
53
  * @exportDoc
@@ -36,13 +36,13 @@ shaka.cea.Mp4CeaParser = class {
36
36
 
37
37
  /**
38
38
  * Default sample duration, as specified by the TREX box.
39
- * @private {!number}
39
+ * @private {number}
40
40
  */
41
41
  this.defaultSampleDuration_ = 0;
42
42
 
43
43
  /**
44
44
  * Default sample size, as specified by the TREX box.
45
- * @private {!number}
45
+ * @private {number}
46
46
  */
47
47
  this.defaultSampleSize_ = 0;
48
48
  }
@@ -195,10 +195,10 @@ shaka.cea.Mp4CeaParser = class {
195
195
  /**
196
196
  * Parse MDAT box.
197
197
  * @param {!shaka.util.DataViewReader} reader
198
- * @param {!number} time
199
- * @param {!number} timescale
200
- * @param {!number} defaultSampleDuration
201
- * @param {!number} defaultSampleSize
198
+ * @param {number} time
199
+ * @param {number} timescale
200
+ * @param {number} defaultSampleDuration
201
+ * @param {number} defaultSampleSize
202
202
  * @param {!Array<shaka.util.ParsedTRUNSample>} sampleData
203
203
  * @param {!Array<!shaka.cea.ICeaParser.CaptionPacket>} captionPackets
204
204
  * @private
@@ -19,6 +19,7 @@ goog.require('shaka.media.PresentationTimeline');
19
19
  goog.require('shaka.media.SegmentIndex');
20
20
  goog.require('shaka.net.NetworkingEngine');
21
21
  goog.require('shaka.text.TextEngine');
22
+ goog.require('shaka.util.CmcdManager');
22
23
  goog.require('shaka.util.Error');
23
24
  goog.require('shaka.util.Functional');
24
25
  goog.require('shaka.util.Iterables');
@@ -58,12 +59,12 @@ shaka.dash.DashParser = class {
58
59
  this.globalId_ = 1;
59
60
 
60
61
  /**
61
- * A map of IDs to SegmentIndex objects.
62
+ * A map of IDs to Stream objects.
62
63
  * ID: Period@id,AdaptationSet@id,@Representation@id
63
64
  * e.g.: '1,5,23'
64
- * @private {!Object.<string, !shaka.media.SegmentIndex>}
65
+ * @private {!Object.<string, !shaka.extern.Stream>}
65
66
  */
66
- this.segmentIndexMap_ = {};
67
+ this.streamMap_ = {};
67
68
 
68
69
  /**
69
70
  * A map of period ids to their durations
@@ -164,8 +165,10 @@ shaka.dash.DashParser = class {
164
165
  stop() {
165
166
  // When the parser stops, release all segment indexes, which stops their
166
167
  // timers, as well.
167
- for (const segmentIndex of Object.values(this.segmentIndexMap_)) {
168
- segmentIndex.release();
168
+ for (const stream of Object.values(this.streamMap_)) {
169
+ if (stream.segmentIndex) {
170
+ stream.segmentIndex.release();
171
+ }
169
172
  }
170
173
 
171
174
  if (this.periodCombiner_) {
@@ -176,7 +179,7 @@ shaka.dash.DashParser = class {
176
179
  this.config_ = null;
177
180
  this.manifestUris_ = [];
178
181
  this.manifest_ = null;
179
- this.segmentIndexMap_ = {};
182
+ this.streamMap_ = {};
180
183
  this.periodCombiner_ = null;
181
184
 
182
185
  if (this.updateTimer_ != null) {
@@ -224,6 +227,9 @@ shaka.dash.DashParser = class {
224
227
  this.manifestUris_, this.config_.retryParameters);
225
228
  const networkingEngine = this.playerInterface_.networkingEngine;
226
229
 
230
+ const format = shaka.util.CmcdManager.StreamingFormat.DASH;
231
+ this.playerInterface_.modifyManifestRequest(request, {format: format});
232
+
227
233
  const startTime = Date.now();
228
234
  const operation = networkingEngine.request(requestType, request);
229
235
  this.operationManager_.manage(operation);
@@ -301,6 +307,11 @@ shaka.dash.DashParser = class {
301
307
  const Functional = shaka.util.Functional;
302
308
  const XmlUtils = shaka.util.XmlUtils;
303
309
 
310
+ const manifestPreprocessor = this.config_.dash.manifestPreprocessor;
311
+ if (manifestPreprocessor) {
312
+ manifestPreprocessor(mpd);
313
+ }
314
+
304
315
  // Get any Location elements. This will update the manifest location and
305
316
  // the base URI.
306
317
  /** @type {!Array.<string>} */
@@ -373,8 +384,11 @@ shaka.dash.DashParser = class {
373
384
  // that the complex logic of multi-Period eviction and period-flattening
374
385
  // is correct. See also:
375
386
  // https://github.com/google/shaka-player/issues/3169#issuecomment-823580634
376
- for (const segmentIndex of Object.values(this.segmentIndexMap_)) {
377
- segmentIndex.evict(presentationTimeline.getSegmentAvailabilityStart());
387
+ for (const stream of Object.values(this.streamMap_)) {
388
+ if (stream.segmentIndex) {
389
+ stream.segmentIndex.evict(
390
+ presentationTimeline.getSegmentAvailabilityStart());
391
+ }
378
392
  }
379
393
  } else {
380
394
  // DASH IOP v3.0 suggests using a default delay between minBufferTime
@@ -1158,11 +1172,12 @@ shaka.dash.DashParser = class {
1158
1172
  context, requestInitSegment);
1159
1173
  } else if (context.representation.segmentList) {
1160
1174
  streamInfo = shaka.dash.SegmentList.createStreamInfo(
1161
- context, this.segmentIndexMap_);
1175
+ context, this.streamMap_);
1162
1176
  } else if (context.representation.segmentTemplate) {
1163
1177
  const hasManifest = !!this.manifest_;
1178
+
1164
1179
  streamInfo = shaka.dash.SegmentTemplate.createStreamInfo(
1165
- context, requestInitSegment, this.segmentIndexMap_, hasManifest,
1180
+ context, requestInitSegment, this.streamMap_, hasManifest,
1166
1181
  this.config_.dash.initialSegmentLimit, this.periodDurations_);
1167
1182
  } else {
1168
1183
  goog.asserts.assert(isText,
@@ -1215,8 +1230,10 @@ shaka.dash.DashParser = class {
1215
1230
 
1216
1231
  let forced = false;
1217
1232
  if (isText) {
1218
- // See: https://github.com/google/shaka-player/issues/2122
1219
- forced = roles.includes('forced_subtitle');
1233
+ // See: https://github.com/google/shaka-player/issues/2122 and
1234
+ // https://github.com/Dash-Industry-Forum/DASH-IF-IOP/issues/165
1235
+ forced = roles.includes('forced_subtitle') ||
1236
+ roles.includes('forced-subtitle');
1220
1237
  }
1221
1238
 
1222
1239
  let tilesLayout;
@@ -1249,13 +1266,29 @@ shaka.dash.DashParser = class {
1249
1266
  hdr = 'PQ';
1250
1267
  }
1251
1268
 
1269
+ const contextId = context.representation.id ?
1270
+ context.period.id + ',' + context.representation.id : '';
1271
+
1252
1272
  /** @type {shaka.extern.Stream} */
1253
1273
  const stream = {
1254
1274
  id: this.globalId_++,
1255
1275
  originalId: context.representation.id,
1256
1276
  createSegmentIndex: async () => {
1257
- if (!stream.segmentIndex) {
1258
- stream.segmentIndex = await streamInfo.generateSegmentIndex();
1277
+ // If we have a stream with the same context id stored in the map
1278
+ // that has no segmentIndex, we should set the segmentIndex for it.
1279
+ const storedInMap = contextId && context.dynamic &&
1280
+ this.streamMap_[contextId];
1281
+
1282
+ const currentStream = storedInMap ? this.streamMap_[contextId] : stream;
1283
+ if (!currentStream.segmentIndex) {
1284
+ currentStream.segmentIndex = await streamInfo.generateSegmentIndex();
1285
+ }
1286
+ },
1287
+
1288
+ closeSegmentIndex: () => {
1289
+ if (stream.segmentIndex) {
1290
+ stream.segmentIndex.release();
1291
+ stream.segmentIndex = null;
1259
1292
  }
1260
1293
  },
1261
1294
  segmentIndex: null,
@@ -1285,7 +1318,13 @@ shaka.dash.DashParser = class {
1285
1318
  closedCaptions,
1286
1319
  hdr,
1287
1320
  tilesLayout,
1321
+ matchedStreams: [],
1288
1322
  };
1323
+
1324
+ if (contextId && context.dynamic && !this.streamMap_[contextId]) {
1325
+ this.streamMap_[contextId] = stream;
1326
+ }
1327
+
1289
1328
  return stream;
1290
1329
  }
1291
1330
 
@@ -61,7 +61,9 @@ shaka.dash.SegmentBase = class {
61
61
  }
62
62
 
63
63
  const getUris = () => resolvedUris;
64
- return new shaka.media.InitSegmentReference(getUris, startByte, endByte);
64
+ const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
65
+ return new shaka.media.InitSegmentReference(
66
+ getUris, startByte, endByte, qualityInfo);
65
67
  }
66
68
 
67
69
  /**
@@ -346,4 +348,26 @@ shaka.dash.SegmentBase = class {
346
348
  indexRange.start, indexRange.end,
347
349
  scaledPresentationTimeOffset);
348
350
  }
351
+
352
+ /**
353
+ * Create a MediaQualityInfo object from a Context object.
354
+ *
355
+ * @param {!shaka.dash.DashParser.Context} context
356
+ * @return {!shaka.extern.MediaQualityInfo}
357
+ */
358
+ static createQualityInfo(context) {
359
+ const representation = context.representation;
360
+ return {
361
+ bandwidth: context.bandwidth,
362
+ audioSamplingRate: representation.audioSamplingRate,
363
+ codecs: representation.codecs,
364
+ contentType: representation.contentType,
365
+ frameRate: representation.frameRate || null,
366
+ height: representation.height || null,
367
+ mimeType: representation.mimeType,
368
+ channelsCount: representation.numChannels,
369
+ pixelAspectRatio: representation.pixelAspectRatio || null,
370
+ width: representation.width || null,
371
+ };
372
+ }
349
373
  };
@@ -30,10 +30,10 @@ shaka.dash.SegmentList = class {
30
30
  * Updates the existing SegmentIndex, if any.
31
31
  *
32
32
  * @param {shaka.dash.DashParser.Context} context
33
- * @param {!Object.<string, !shaka.media.SegmentIndex>} segmentIndexMap
33
+ * @param {!Object.<string, !shaka.extern.Stream>} streamMap
34
34
  * @return {shaka.dash.DashParser.StreamInfo}
35
35
  */
36
- static createStreamInfo(context, segmentIndexMap) {
36
+ static createStreamInfo(context, streamMap) {
37
37
  goog.asserts.assert(context.representation.segmentList,
38
38
  'Should only be called with SegmentList');
39
39
  const SegmentList = shaka.dash.SegmentList;
@@ -46,11 +46,14 @@ shaka.dash.SegmentList = class {
46
46
 
47
47
  /** @type {shaka.media.SegmentIndex} */
48
48
  let segmentIndex = null;
49
- let id = null;
49
+ let stream = null;
50
50
  if (context.period.id && context.representation.id) {
51
51
  // Only check/store the index if period and representation IDs are set.
52
- id = context.period.id + ',' + context.representation.id;
53
- segmentIndex = segmentIndexMap[id];
52
+ const id = context.period.id + ',' + context.representation.id;
53
+ stream = streamMap[id];
54
+ if (stream) {
55
+ segmentIndex = stream.segmentIndex;
56
+ }
54
57
  }
55
58
 
56
59
  const references = SegmentList.createSegmentReferences_(
@@ -64,9 +67,6 @@ shaka.dash.SegmentList = class {
64
67
  segmentIndex.mergeAndEvict(references, start);
65
68
  } else {
66
69
  segmentIndex = new shaka.media.SegmentIndex(references);
67
- if (id && context.dynamic) {
68
- segmentIndexMap[id] = segmentIndex;
69
- }
70
70
  }
71
71
  context.presentationTimeline.notifySegments(references);
72
72
 
@@ -77,8 +77,17 @@ shaka.dash.SegmentList = class {
77
77
  segmentIndex.fit(periodStart, periodEnd, isNew);
78
78
  }
79
79
 
80
+ if (stream) {
81
+ stream.segmentIndex = segmentIndex;
82
+ }
83
+
80
84
  return {
81
- generateSegmentIndex: () => Promise.resolve(segmentIndex),
85
+ generateSegmentIndex: () => {
86
+ if (!segmentIndex || segmentIndex.isEmpty()) {
87
+ segmentIndex.merge(references);
88
+ }
89
+ return Promise.resolve(segmentIndex);
90
+ },
82
91
  };
83
92
  }
84
93
 
@@ -31,7 +31,7 @@ shaka.dash.SegmentTemplate = class {
31
31
  * @param {shaka.dash.DashParser.Context} context
32
32
  * @param {shaka.dash.DashParser.RequestInitSegmentCallback}
33
33
  * requestInitSegment
34
- * @param {!Object.<string, !shaka.media.SegmentIndex>} segmentIndexMap
34
+ * @param {!Object.<string, !shaka.extern.Stream>} streamMap
35
35
  * @param {boolean} isUpdate True if the manifest is being updated.
36
36
  * @param {number} segmentLimit The maximum number of segments to generate for
37
37
  * a SegmentTemplate with fixed duration.
@@ -39,8 +39,8 @@ shaka.dash.SegmentTemplate = class {
39
39
  * @return {shaka.dash.DashParser.StreamInfo}
40
40
  */
41
41
  static createStreamInfo(
42
- context, requestInitSegment, segmentIndexMap, isUpdate,
43
- segmentLimit, periodDurationMap) {
42
+ context, requestInitSegment, streamMap, isUpdate, segmentLimit,
43
+ periodDurationMap) {
44
44
  goog.asserts.assert(context.representation.segmentTemplate,
45
45
  'Should only be called with SegmentTemplate');
46
46
  const SegmentTemplate = shaka.dash.SegmentTemplate;
@@ -86,10 +86,14 @@ shaka.dash.SegmentTemplate = class {
86
86
  /** @type {shaka.media.SegmentIndex} */
87
87
  let segmentIndex = null;
88
88
  let id = null;
89
+ let stream = null;
89
90
  if (context.period.id && context.representation.id) {
90
91
  // Only check/store the index if period and representation IDs are set.
91
92
  id = context.period.id + ',' + context.representation.id;
92
- segmentIndex = segmentIndexMap[id];
93
+ stream = streamMap[id];
94
+ if (stream) {
95
+ segmentIndex = stream.segmentIndex;
96
+ }
93
97
  }
94
98
 
95
99
  const references = SegmentTemplate.createFromTimeline_(
@@ -117,9 +121,6 @@ shaka.dash.SegmentTemplate = class {
117
121
  context.presentationTimeline.getSegmentAvailabilityStart());
118
122
  } else {
119
123
  segmentIndex = new shaka.media.SegmentIndex(references);
120
- if (id && context.dynamic) {
121
- segmentIndexMap[id] = segmentIndex;
122
- }
123
124
  }
124
125
  context.presentationTimeline.notifySegments(references);
125
126
 
@@ -127,8 +128,20 @@ shaka.dash.SegmentTemplate = class {
127
128
  segmentIndex.fit(periodStart, periodEnd);
128
129
  }
129
130
 
131
+ if (stream && context.dynamic) {
132
+ stream.segmentIndex = segmentIndex;
133
+ }
134
+
130
135
  return {
131
- generateSegmentIndex: () => Promise.resolve(segmentIndex),
136
+ generateSegmentIndex: () => {
137
+ // If segmentIndex is deleted, or segmentIndex's references are
138
+ // released by closeSegmentIndex(), we should set the value of
139
+ // segmentIndex again.
140
+ if (!segmentIndex || segmentIndex.isEmpty()) {
141
+ segmentIndex.merge(references);
142
+ }
143
+ return Promise.resolve(segmentIndex);
144
+ },
132
145
  };
133
146
  }
134
147
  }
@@ -569,8 +582,8 @@ shaka.dash.SegmentTemplate = class {
569
582
  baseUris, [filledTemplate]);
570
583
  return resolvedUris;
571
584
  };
572
-
573
- return new shaka.media.InitSegmentReference(getUris, 0, null);
585
+ const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
586
+ return new shaka.media.InitSegmentReference(getUris, 0, null, qualityInfo);
574
587
  }
575
588
  };
576
589