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.
Files changed (307) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  2. package/.github/workflows/release-please.yaml +2 -27
  3. package/AUTHORS +2 -0
  4. package/CHANGELOG.md +156 -39
  5. package/CODE_OF_CONDUCT.md +1 -1
  6. package/CONTRIBUTORS +2 -0
  7. package/README.md +54 -42
  8. package/demo/asset_card.js +18 -21
  9. package/demo/cast_receiver/index.html +0 -1
  10. package/demo/close_button.js +0 -3
  11. package/demo/common/asset.js +33 -22
  12. package/demo/common/assets.js +249 -60
  13. package/demo/config.js +219 -253
  14. package/demo/custom.js +88 -133
  15. package/demo/front.js +7 -10
  16. package/demo/index.html +19 -22
  17. package/demo/input.js +6 -11
  18. package/demo/input_container.js +8 -9
  19. package/demo/main.js +62 -126
  20. package/demo/search.js +29 -34
  21. package/demo/service_worker.js +0 -3
  22. package/demo/tooltip.js +3 -5
  23. package/demo/visualizer.js +3 -5
  24. package/demo/visualizer_button.js +1 -20
  25. package/dist/controls.css +1 -1
  26. package/dist/controls.css.map +1 -1
  27. package/dist/demo.compiled.debug.js +211 -228
  28. package/dist/demo.compiled.debug.map +4 -4
  29. package/dist/demo.compiled.js +211 -228
  30. package/dist/demo.compiled.map +4 -4
  31. package/dist/deps.js +42 -37
  32. package/dist/locales.js +34 -30
  33. package/dist/receiver.compiled.debug.js +64 -77
  34. package/dist/receiver.compiled.debug.map +4 -4
  35. package/dist/receiver.compiled.js +64 -77
  36. package/dist/receiver.compiled.map +4 -4
  37. package/dist/shaka-player.compiled.d.ts +343 -151
  38. package/dist/shaka-player.compiled.debug.d.ts +343 -151
  39. package/dist/shaka-player.compiled.debug.externs.js +356 -117
  40. package/dist/shaka-player.compiled.debug.js +952 -811
  41. package/dist/shaka-player.compiled.debug.map +4 -4
  42. package/dist/shaka-player.compiled.externs.js +356 -117
  43. package/dist/shaka-player.compiled.js +1165 -1078
  44. package/dist/shaka-player.compiled.map +4 -4
  45. package/dist/shaka-player.ui.d.ts +359 -153
  46. package/dist/shaka-player.ui.debug.d.ts +359 -153
  47. package/dist/shaka-player.ui.debug.externs.js +382 -117
  48. package/dist/shaka-player.ui.debug.js +1084 -918
  49. package/dist/shaka-player.ui.debug.map +4 -4
  50. package/dist/shaka-player.ui.externs.js +382 -117
  51. package/dist/shaka-player.ui.js +1377 -1274
  52. package/dist/shaka-player.ui.map +4 -4
  53. package/docs/design/lcevc-integration.md +14 -14
  54. package/docs/tutorials/ad_monetization.md +54 -0
  55. package/docs/tutorials/basic-usage.md +2 -1
  56. package/docs/tutorials/errors.md +2 -1
  57. package/docs/tutorials/faq.md +27 -55
  58. package/docs/tutorials/index.json +2 -1
  59. package/docs/tutorials/lcevc.md +118 -0
  60. package/docs/tutorials/offline.md +10 -8
  61. package/docs/tutorials/plugins.md +5 -0
  62. package/docs/tutorials/ui-customization.md +17 -0
  63. package/docs/tutorials/ui.md +2 -1
  64. package/docs/tutorials/upgrade.md +3 -0
  65. package/externs/css_style_declaration.js +19 -0
  66. package/externs/lcevc.js +37 -13
  67. package/externs/managedmediasource.js +24 -0
  68. package/externs/media_remote.js +68 -0
  69. package/externs/mediatailor.js +193 -0
  70. package/externs/pictureinpicture.js +11 -0
  71. package/externs/shaka/abr_manager.js +6 -2
  72. package/externs/shaka/ads.js +27 -0
  73. package/externs/shaka/cea.js +7 -0
  74. package/externs/shaka/codecs.js +5 -3
  75. package/externs/shaka/manifest.js +31 -10
  76. package/externs/shaka/manifest_parser.js +24 -1
  77. package/externs/shaka/net.js +2 -2
  78. package/externs/shaka/offline.js +13 -2
  79. package/externs/shaka/player.js +65 -8
  80. package/externs/shaka/text.js +3 -1
  81. package/externs/shaka/transmuxer.js +1 -1
  82. package/karma.conf.js +7 -3
  83. package/lib/abr/simple_abr_manager.js +66 -9
  84. package/lib/ads/ad_manager.js +104 -50
  85. package/lib/ads/media_tailor_ad.js +297 -0
  86. package/lib/ads/media_tailor_ad_manager.js +839 -0
  87. package/lib/cast/cast_receiver.js +1 -1
  88. package/lib/cea/cea_decoder.js +28 -0
  89. package/lib/cea/dummy_caption_decoder.js +5 -0
  90. package/lib/cea/ts_cea_parser.js +15 -2
  91. package/lib/config/codec_switching_strategy.js +24 -0
  92. package/lib/dash/content_protection.js +120 -2
  93. package/lib/dash/dash_parser.js +322 -93
  94. package/lib/dash/mpd_utils.js +62 -37
  95. package/lib/dash/segment_base.js +17 -10
  96. package/lib/dash/segment_list.js +18 -9
  97. package/lib/dash/segment_template.js +122 -107
  98. package/lib/dependencies/all.js +8 -7
  99. package/lib/hls/hls_classes.js +28 -43
  100. package/lib/hls/hls_parser.js +798 -658
  101. package/lib/hls/hls_utils.js +64 -5
  102. package/lib/hls/manifest_text_parser.js +7 -11
  103. package/lib/lcevc/lcevc_dec.js +220 -0
  104. package/lib/media/adaptation_set.js +32 -14
  105. package/lib/media/adaptation_set_criteria.js +86 -16
  106. package/lib/media/closed_caption_parser.js +13 -0
  107. package/lib/media/content_workarounds.js +6 -0
  108. package/lib/media/drm_engine.js +8 -13
  109. package/lib/media/manifest_parser.js +8 -113
  110. package/lib/media/media_source_capabilities.js +10 -3
  111. package/lib/media/media_source_engine.js +286 -44
  112. package/lib/media/play_rate_controller.js +8 -38
  113. package/lib/media/presentation_timeline.js +7 -1
  114. package/lib/media/quality_observer.js +1 -1
  115. package/lib/media/segment_index.js +6 -6
  116. package/lib/media/segment_prefetch.js +92 -24
  117. package/lib/media/segment_reference.js +73 -7
  118. package/lib/media/segment_utils.js +343 -0
  119. package/lib/media/stall_detector.js +0 -3
  120. package/lib/media/streaming_engine.js +73 -38
  121. package/lib/mss/mss_parser.js +19 -2
  122. package/lib/net/networking_engine.js +67 -12
  123. package/lib/net/networking_utils.js +95 -0
  124. package/lib/offline/indexeddb/v1_storage_cell.js +3 -0
  125. package/lib/offline/indexeddb/v2_storage_cell.js +3 -0
  126. package/lib/offline/manifest_converter.js +3 -0
  127. package/lib/offline/offline_manifest_parser.js +10 -0
  128. package/lib/offline/storage.js +14 -7
  129. package/lib/player.js +1098 -1537
  130. package/lib/polyfill/mediasource.js +22 -1
  131. package/lib/text/cue.js +15 -0
  132. package/lib/text/mp4_ttml_parser.js +2 -2
  133. package/lib/text/srt_text_parser.js +2 -2
  134. package/lib/text/stub_text_displayer.js +51 -0
  135. package/lib/text/text_engine.js +3 -2
  136. package/lib/text/ttml_text_parser.js +45 -5
  137. package/lib/text/ui_text_displayer.js +8 -0
  138. package/lib/text/vtt_text_parser.js +40 -22
  139. package/lib/transmuxer/aac_transmuxer.js +1 -1
  140. package/lib/transmuxer/ac3_transmuxer.js +1 -1
  141. package/lib/transmuxer/ec3_transmuxer.js +1 -1
  142. package/lib/transmuxer/h264.js +5 -4
  143. package/lib/transmuxer/h265.js +863 -0
  144. package/lib/transmuxer/mp3_transmuxer.js +1 -1
  145. package/lib/transmuxer/mpeg_ts_transmuxer.js +4 -3
  146. package/lib/transmuxer/mss_transmuxer.js +1 -1
  147. package/lib/transmuxer/ts_transmuxer.js +187 -22
  148. package/lib/util/buffer_utils.js +26 -4
  149. package/lib/util/content_steering_manager.js +358 -0
  150. package/lib/util/error.js +30 -15
  151. package/lib/util/exp_golomb.js +30 -2
  152. package/lib/util/fairplay_utils.js +1 -1
  153. package/lib/util/fake_event.js +8 -1
  154. package/lib/util/id3_utils.js +50 -1
  155. package/lib/util/manifest_parser_utils.js +12 -8
  156. package/lib/util/mp4_generator.js +6 -8
  157. package/lib/util/mutex.js +59 -0
  158. package/lib/util/object_utils.js +1 -1
  159. package/lib/util/periods.js +156 -179
  160. package/lib/util/platform.js +44 -3
  161. package/lib/util/player_configuration.js +43 -6
  162. package/lib/util/state_history.js +6 -2
  163. package/lib/util/stream_utils.js +206 -283
  164. package/lib/util/ts_parser.js +335 -98
  165. package/lib/util/uint8array_utils.js +5 -1
  166. package/lib/util/xml_utils.js +5 -0
  167. package/maintained-branches.md +3 -2
  168. package/package.json +4 -6
  169. package/roadmap.md +25 -5
  170. package/shaka-player.uncompiled.js +2 -2
  171. package/support.html +0 -1
  172. package/test/abr/simple_abr_manager_unit.js +33 -33
  173. package/test/ads/ad_manager_unit.js +3 -2
  174. package/test/cast/cast_receiver_integration.js +50 -4
  175. package/test/cast/cast_utils_unit.js +2 -0
  176. package/test/cea/cea_decoder_unit.js +7 -0
  177. package/test/codec_switching/codec_switching_integration.js +182 -0
  178. package/test/dash/dash_parser_content_protection_unit.js +2 -0
  179. package/test/dash/dash_parser_integration.js +74 -0
  180. package/test/dash/dash_parser_live_unit.js +2 -19
  181. package/test/dash/dash_parser_manifest_unit.js +536 -2
  182. package/test/dash/dash_parser_segment_base_unit.js +2 -0
  183. package/test/dash/dash_parser_segment_list_unit.js +2 -0
  184. package/test/dash/dash_parser_segment_template_unit.js +2 -0
  185. package/test/dash/mpd_utils_unit.js +61 -30
  186. package/test/demo/demo_unit.js +0 -16
  187. package/test/hls/hls_live_unit.js +14 -3
  188. package/test/hls/hls_parser_unit.js +385 -33
  189. package/test/hls/manifest_text_parser_unit.js +32 -99
  190. package/test/media/adaptation_set_criteria_unit.js +284 -15
  191. package/test/media/adaptation_set_unit.js +2 -0
  192. package/test/media/content_workarounds_unit.js +1 -1
  193. package/test/media/drm_engine_unit.js +3 -3
  194. package/test/media/media_source_engine_unit.js +166 -2
  195. package/test/media/play_rate_controller_unit.js +0 -48
  196. package/test/media/segment_index_unit.js +5 -4
  197. package/test/media/segment_prefetch_unit.js +1 -1
  198. package/test/media/streaming_engine_unit.js +17 -17
  199. package/test/mss/mss_parser_unit.js +2 -0
  200. package/test/mss/mss_player_integration.js +3 -2
  201. package/test/net/networking_engine_unit.js +3 -3
  202. package/test/{media/manifest_parser_unit.js → net/networking_utils_unit.js} +2 -2
  203. package/test/offline/manifest_convert_unit.js +14 -0
  204. package/test/offline/offline_integration.js +2 -1
  205. package/test/offline/storage_integration.js +22 -13
  206. package/test/player_external.js +4 -2
  207. package/test/player_integration.js +15 -4
  208. package/test/player_load_graph_integration.js +47 -151
  209. package/test/player_src_equals_external.js +1 -0
  210. package/test/player_src_equals_integration.js +71 -4
  211. package/test/player_unit.js +182 -158
  212. package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
  213. package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
  214. package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
  215. package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
  216. package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
  217. package/test/test/assets/dash-aes-128/dash.mpd +18 -0
  218. package/test/test/assets/dash-aes-128/license +1 -0
  219. package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
  220. package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
  221. package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
  222. package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
  223. package/test/test/assets/hls-ts-h265/0.ts +0 -0
  224. package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
  225. package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
  226. package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
  227. package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
  228. package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
  229. package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
  230. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
  231. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
  232. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
  233. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
  234. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
  235. package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
  236. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
  237. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
  238. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
  239. package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
  240. package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
  241. package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
  242. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
  243. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
  244. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
  245. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
  246. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
  247. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
  248. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
  249. package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
  250. package/test/test/util/dash_parser_util.js +4 -0
  251. package/test/test/util/fake_ad_manager.js +20 -0
  252. package/test/test/util/fake_media_source_engine.js +13 -2
  253. package/test/test/util/fake_networking_engine.js +9 -1
  254. package/test/test/util/fake_segment_prefetch.js +3 -0
  255. package/test/test/util/manifest_generator.js +11 -3
  256. package/test/test/util/manifest_parser_util.js +14 -2
  257. package/test/test/util/mss_parser_util.js +4 -0
  258. package/test/test/util/offline_utils.js +2 -0
  259. package/test/test/util/simple_fakes.js +2 -2
  260. package/test/test/util/streaming_engine_util.js +10 -4
  261. package/test/test/util/test_scheme.js +6 -0
  262. package/test/test/util/ui_utils.js +4 -3
  263. package/test/text/mp4_ttml_parser_unit.js +4 -4
  264. package/test/text/srt_text_parser_unit.js +1 -1
  265. package/test/text/text_displayer_layout_unit.js +1 -1
  266. package/test/text/text_engine_unit.js +6 -0
  267. package/test/text/ttml_text_parser_unit.js +85 -2
  268. package/test/text/vtt_text_parser_unit.js +103 -31
  269. package/test/transmuxer/transmuxer_engine_integration.js +9 -0
  270. package/test/transmuxer/transmuxer_integration.js +150 -3
  271. package/test/ui/ad_ui_unit.js +2 -2
  272. package/test/ui/ui_customization_unit.js +17 -16
  273. package/test/ui/ui_integration.js +30 -20
  274. package/test/ui/ui_unit.js +28 -29
  275. package/test/util/buffer_utils_unit.js +1 -1
  276. package/test/util/content_steering_manager_unit.js +427 -0
  277. package/test/util/id3_utils_unit.js +52 -0
  278. package/test/util/stream_utils_unit.js +207 -169
  279. package/test/util/ts_parser_unit.js +3 -3
  280. package/third_party/closure-uri/uri.js +13 -1
  281. package/ui/audio_language_selection.js +9 -2
  282. package/ui/controls.js +125 -0
  283. package/ui/externs/ui.js +24 -2
  284. package/ui/language_utils.js +43 -8
  285. package/ui/less/range_elements.less +33 -0
  286. package/ui/locales/en.json +1 -0
  287. package/ui/locales/es-419.json +1 -0
  288. package/ui/locales/es.json +1 -0
  289. package/ui/locales/source.json +4 -0
  290. package/ui/localization.js +10 -0
  291. package/ui/pip_button.js +22 -120
  292. package/ui/remote_button.js +203 -0
  293. package/ui/resolution_selection.js +47 -10
  294. package/ui/seek_bar.js +296 -3
  295. package/ui/text_selection.js +2 -1
  296. package/ui/ui.js +11 -4
  297. package/demo/common/message_ids.js +0 -309
  298. package/demo/locales/en.json +0 -288
  299. package/demo/locales/source.json +0 -1146
  300. package/externs/mux.js +0 -69
  301. package/lib/lcevc/lcevc_dil.js +0 -152
  302. package/lib/routing/node.js +0 -23
  303. package/lib/routing/payload.js +0 -43
  304. package/lib/routing/walker.js +0 -587
  305. package/lib/transmuxer/muxjs_transmuxer.js +0 -242
  306. package/test/routing/walker_unit.js +0 -504
  307. package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
@@ -0,0 +1,343 @@
1
+ /*! @license
2
+ * Shaka Player
3
+ * Copyright 2016 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ goog.provide('shaka.media.SegmentUtils');
8
+
9
+ goog.require('goog.asserts');
10
+ goog.require('shaka.log');
11
+ goog.require('shaka.media.ClosedCaptionParser');
12
+ goog.require('shaka.util.BufferUtils');
13
+ goog.require('shaka.util.MimeUtils');
14
+ goog.require('shaka.util.Mp4BoxParsers');
15
+ goog.require('shaka.util.Mp4Parser');
16
+ goog.require('shaka.util.TsParser');
17
+
18
+
19
+ /**
20
+ * @summary Utility functions for segment parsing.
21
+ */
22
+ shaka.media.SegmentUtils = class {
23
+ /**
24
+ * @param {string} mimeType
25
+ * @return {shaka.media.SegmentUtils.BasicInfo}
26
+ */
27
+ static getBasicInfoFromMimeType(mimeType) {
28
+ const baseMimeType = shaka.util.MimeUtils.getBasicType(mimeType);
29
+ const type = baseMimeType.split('/')[0];
30
+ const codecs = shaka.util.MimeUtils.getCodecs(mimeType);
31
+ return {
32
+ type: type,
33
+ mimeType: baseMimeType,
34
+ codecs: codecs,
35
+ language: null,
36
+ height: null,
37
+ width: null,
38
+ channelCount: null,
39
+ sampleRate: null,
40
+ closedCaptions: new Map(),
41
+ };
42
+ }
43
+
44
+ /**
45
+ * @param {!BufferSource} data
46
+ * @return {?shaka.media.SegmentUtils.BasicInfo}
47
+ */
48
+ static getBasicInfoFromTs(data) {
49
+ const uint8ArrayData = shaka.util.BufferUtils.toUint8(data);
50
+ const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
51
+ const tsCodecs = tsParser.getCodecs();
52
+ const videoInfo = tsParser.getVideoInfo();
53
+ const codecs = [];
54
+ let hasAudio = false;
55
+ let hasVideo = false;
56
+ switch (tsCodecs.audio) {
57
+ case 'aac':
58
+ codecs.push('mp4a.40.2');
59
+ hasAudio = true;
60
+ break;
61
+ case 'mp3':
62
+ codecs.push('mp4a.40.34');
63
+ hasAudio = true;
64
+ break;
65
+ case 'ac3':
66
+ codecs.push('ac-3');
67
+ hasAudio = true;
68
+ break;
69
+ case 'ec3':
70
+ codecs.push('ec-3');
71
+ hasAudio = true;
72
+ break;
73
+ }
74
+ switch (tsCodecs.video) {
75
+ case 'avc':
76
+ if (videoInfo.codec) {
77
+ codecs.push(videoInfo.codec);
78
+ } else {
79
+ codecs.push('avc1.42E01E');
80
+ }
81
+ hasVideo = true;
82
+ break;
83
+ case 'hvc':
84
+ if (videoInfo.codec) {
85
+ codecs.push(videoInfo.codec);
86
+ } else {
87
+ codecs.push('hvc1.1.6.L93.90');
88
+ }
89
+ hasVideo = true;
90
+ break;
91
+ }
92
+ if (!codecs.length) {
93
+ return null;
94
+ }
95
+ const onlyAudio = hasAudio && !hasVideo;
96
+ const closedCaptions = new Map();
97
+ if (hasVideo) {
98
+ const captionParser = new shaka.media.ClosedCaptionParser('video/mp2t');
99
+ captionParser.parseFrom(data);
100
+ for (const stream of captionParser.getStreams()) {
101
+ closedCaptions.set(stream, stream);
102
+ }
103
+ captionParser.reset();
104
+ }
105
+ return {
106
+ type: onlyAudio ? 'audio' : 'video',
107
+ mimeType: 'video/mp2t',
108
+ codecs: codecs.join(', '),
109
+ language: null,
110
+ height: videoInfo.height,
111
+ width: videoInfo.width,
112
+ channelCount: null,
113
+ sampleRate: null,
114
+ closedCaptions: closedCaptions,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * @param {?BufferSource} initData
120
+ * @param {!BufferSource} data
121
+ * @return {?shaka.media.SegmentUtils.BasicInfo}
122
+ */
123
+ static getBasicInfoFromMp4(initData, data) {
124
+ const Mp4Parser = shaka.util.Mp4Parser;
125
+ const SegmentUtils = shaka.media.SegmentUtils;
126
+
127
+ const codecs = [];
128
+
129
+ let hasAudio = false;
130
+ let hasVideo = false;
131
+
132
+ const addCodec = (codec) => {
133
+ const codecLC = codec.toLowerCase();
134
+ switch (codecLC) {
135
+ case 'avc1':
136
+ case 'avc3':
137
+ codecs.push(codecLC + '.42E01E');
138
+ hasVideo = true;
139
+ break;
140
+ case 'hev1':
141
+ case 'hvc1':
142
+ codecs.push(codecLC + '.1.6.L93.90');
143
+ hasVideo = true;
144
+ break;
145
+ case 'dvh1':
146
+ case 'dvhe':
147
+ codecs.push(codecLC + '.05.04');
148
+ hasVideo = true;
149
+ break;
150
+ case 'vp09':
151
+ codecs.push(codecLC + '.00.10.08');
152
+ hasVideo = true;
153
+ break;
154
+ case 'av01':
155
+ codecs.push(codecLC + '.0.01M.08');
156
+ hasVideo = true;
157
+ break;
158
+ case 'mp4a':
159
+ // We assume AAC, but this can be wrong since mp4a supports
160
+ // others codecs
161
+ codecs.push('mp4a.40.2');
162
+ hasAudio = true;
163
+ break;
164
+ case 'ac-3':
165
+ case 'ec-3':
166
+ case 'opus':
167
+ case 'flac':
168
+ codecs.push(codecLC);
169
+ hasAudio = true;
170
+ break;
171
+ }
172
+ };
173
+
174
+ const codecBoxParser = (box) => addCodec(box.name);
175
+
176
+ /** @type {?string} */
177
+ let language = null;
178
+ /** @type {?string} */
179
+ let height = null;
180
+ /** @type {?string} */
181
+ let width = null;
182
+ /** @type {?number} */
183
+ let channelCount = null;
184
+ /** @type {?number} */
185
+ let sampleRate = null;
186
+
187
+ new Mp4Parser()
188
+ .box('moov', Mp4Parser.children)
189
+ .box('trak', Mp4Parser.children)
190
+ .fullBox('tkhd', (box) => {
191
+ goog.asserts.assert(
192
+ box.version != null,
193
+ 'TKHD is a full box and should have a valid version.');
194
+ const parsedTKHDBox = shaka.util.Mp4BoxParsers.parseTKHD(
195
+ box.reader, box.version);
196
+ height = String(parsedTKHDBox.height);
197
+ width = String(parsedTKHDBox.width);
198
+ })
199
+ .box('mdia', Mp4Parser.children)
200
+ .fullBox('mdhd', (box) => {
201
+ goog.asserts.assert(
202
+ box.version != null,
203
+ 'MDHD is a full box and should have a valid version.');
204
+ const parsedMDHDBox = shaka.util.Mp4BoxParsers.parseMDHD(
205
+ box.reader, box.version);
206
+ language = parsedMDHDBox.language;
207
+ })
208
+ .box('minf', Mp4Parser.children)
209
+ .box('stbl', Mp4Parser.children)
210
+ .fullBox('stsd', Mp4Parser.sampleDescription)
211
+
212
+ // AUDIO
213
+ // These are the various boxes that signal a codec.
214
+ .box('mp4a', (box) => {
215
+ const parsedMP4ABox = shaka.util.Mp4BoxParsers.parseMP4A(box.reader);
216
+ channelCount = parsedMP4ABox.channelCount;
217
+ sampleRate = parsedMP4ABox.sampleRate;
218
+ if (box.reader.hasMoreData()) {
219
+ Mp4Parser.children(box);
220
+ } else {
221
+ codecBoxParser(box);
222
+ }
223
+ })
224
+ .box('esds', (box) => {
225
+ const parsedESDSBox = shaka.util.Mp4BoxParsers.parseESDS(box.reader);
226
+ codecs.push(parsedESDSBox.codec);
227
+ hasAudio = true;
228
+ })
229
+ .box('ac-3', codecBoxParser)
230
+ .box('ec-3', codecBoxParser)
231
+ .box('opus', codecBoxParser)
232
+ .box('Opus', codecBoxParser)
233
+ .box('fLaC', codecBoxParser)
234
+
235
+ // VIDEO
236
+ // These are the various boxes that signal a codec.
237
+ .box('avc1', (box) => {
238
+ const parsedAVCBox =
239
+ shaka.util.Mp4BoxParsers.parseAVC(box.reader, box.name);
240
+ codecs.push(parsedAVCBox.codec);
241
+ hasVideo = true;
242
+ })
243
+ .box('avc3', (box) => {
244
+ const parsedAVCBox =
245
+ shaka.util.Mp4BoxParsers.parseAVC(box.reader, box.name);
246
+ codecs.push(parsedAVCBox.codec);
247
+ hasVideo = true;
248
+ })
249
+ .box('hev1', codecBoxParser)
250
+ .box('hvc1', codecBoxParser)
251
+ .box('dvh1', codecBoxParser)
252
+ .box('dvhe', codecBoxParser)
253
+ .box('vp09', codecBoxParser)
254
+ .box('av01', codecBoxParser)
255
+
256
+ // This signals an encrypted sample, which we can go inside of to
257
+ // find the codec used.
258
+ // Note: If encrypted, you can only have audio or video, not both.
259
+ .box('enca', Mp4Parser.visualSampleEntry)
260
+ .box('encv', Mp4Parser.visualSampleEntry)
261
+ .box('sinf', Mp4Parser.children)
262
+ .box('frma', (box) => {
263
+ const {codec} = shaka.util.Mp4BoxParsers.parseFRMA(box.reader);
264
+ addCodec(codec);
265
+ })
266
+
267
+ .parse(initData || data, /* partialOkay= */ true);
268
+ if (!codecs.length) {
269
+ return null;
270
+ }
271
+ const onlyAudio = hasAudio && !hasVideo;
272
+ const closedCaptions = new Map();
273
+ if (hasVideo) {
274
+ const captionParser = new shaka.media.ClosedCaptionParser('video/mp4');
275
+ if (initData) {
276
+ captionParser.init(initData);
277
+ }
278
+ captionParser.parseFrom(data);
279
+ for (const stream of captionParser.getStreams()) {
280
+ closedCaptions.set(stream, stream);
281
+ }
282
+ captionParser.reset();
283
+ }
284
+ return {
285
+ type: onlyAudio ? 'audio' : 'video',
286
+ mimeType: onlyAudio ? 'audio/mp4' : 'video/mp4',
287
+ codecs: SegmentUtils.filterDuplicateCodecs_(codecs).join(', '),
288
+ language: language,
289
+ height: height,
290
+ width: width,
291
+ channelCount: channelCount,
292
+ sampleRate: sampleRate,
293
+ closedCaptions: closedCaptions,
294
+ };
295
+ }
296
+
297
+ /**
298
+ * @param {!Array.<string>} codecs
299
+ * @return {!Array.<string>} codecs
300
+ * @private
301
+ */
302
+ static filterDuplicateCodecs_(codecs) {
303
+ // Filter out duplicate codecs.
304
+ const seen = new Set();
305
+ const ret = [];
306
+ for (const codec of codecs) {
307
+ const shortCodec = shaka.util.MimeUtils.getCodecBase(codec);
308
+ if (!seen.has(shortCodec)) {
309
+ ret.push(codec);
310
+ seen.add(shortCodec);
311
+ } else {
312
+ shaka.log.debug('Ignoring duplicate codec');
313
+ }
314
+ }
315
+ return ret;
316
+ }
317
+ };
318
+
319
+
320
+ /**
321
+ * @typedef {{
322
+ * type: string,
323
+ * mimeType: string,
324
+ * codecs: string,
325
+ * language: ?string,
326
+ * height: ?string,
327
+ * width: ?string,
328
+ * channelCount: ?number,
329
+ * sampleRate: ?number,
330
+ * closedCaptions: Map.<string, string>
331
+ * }}
332
+ *
333
+ * @property {string} type
334
+ * @property {string} mimeType
335
+ * @property {string} codecs
336
+ * @property {?string} language
337
+ * @property {?string} height
338
+ * @property {?string} width
339
+ * @property {?number} channelCount
340
+ * @property {?number} sampleRate
341
+ * @property {Map.<string, string>} closedCaptions
342
+ */
343
+ shaka.media.SegmentUtils.BasicInfo;
@@ -174,9 +174,6 @@ shaka.media.StallDetector.MediaElementImplementation = class {
174
174
  if (this.mediaElement_.paused) {
175
175
  return false;
176
176
  }
177
- if (this.mediaElement_.playbackRate == 0) {
178
- return false;
179
- }
180
177
 
181
178
  // If we have don't have enough content, we are not stalled, we are
182
179
  // buffering.
@@ -1054,6 +1054,14 @@ shaka.media.StreamingEngine = class {
1054
1054
  this.playerInterface_.mediaSourceEngine.clearSelectedClosedCaptionId();
1055
1055
  }
1056
1056
 
1057
+ if (!this.playerInterface_.mediaSourceEngine.isStreamingAllowed() &&
1058
+ mediaState.type != ContentType.TEXT) {
1059
+ // It is not allowed to add segments yet, so we schedule an update to
1060
+ // check again later. So any prediction we make now could be terribly
1061
+ // invalid soon.
1062
+ return this.config_.updateIntervalSeconds / 2;
1063
+ }
1064
+
1057
1065
  const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState);
1058
1066
 
1059
1067
  // Compute how far we've buffered ahead of the playhead.
@@ -1163,6 +1171,12 @@ shaka.media.StreamingEngine = class {
1163
1171
  }
1164
1172
 
1165
1173
  if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
1174
+ const initSegmentReference = reference.initSegmentReference;
1175
+ if (initSegmentReference && (!mediaState.lastSegmentReference ||
1176
+ !shaka.media.InitSegmentReference.equal(
1177
+ initSegmentReference, mediaState.lastInitSegmentReference))) {
1178
+ mediaState.segmentPrefetch.prefetchInitSegment(initSegmentReference);
1179
+ }
1166
1180
  mediaState.segmentPrefetch.prefetchSegments(reference);
1167
1181
  }
1168
1182
 
@@ -1373,6 +1387,11 @@ shaka.media.StreamingEngine = class {
1373
1387
  await this.append_(
1374
1388
  mediaState, presentationTime, stream, reference, dataToAppend,
1375
1389
  /* isChunkedData= */ true);
1390
+
1391
+ if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
1392
+ mediaState.segmentPrefetch.prefetchSegments(
1393
+ reference, /* skipFirst= */ true);
1394
+ }
1376
1395
  }
1377
1396
  };
1378
1397
 
@@ -1403,6 +1422,11 @@ shaka.media.StreamingEngine = class {
1403
1422
  await this.append_(
1404
1423
  mediaState, presentationTime, stream, reference, result);
1405
1424
  }
1425
+
1426
+ if (mediaState.segmentPrefetch && mediaState.segmentIterator) {
1427
+ mediaState.segmentPrefetch.prefetchSegments(
1428
+ reference, /* skipFirst= */ true);
1429
+ }
1406
1430
  } else {
1407
1431
  if (this.config_.lowLatencyMode && !isReadableStreamSupported) {
1408
1432
  shaka.log.warning('Low latency streaming mode is enabled, but ' +
@@ -1498,12 +1522,12 @@ shaka.media.StreamingEngine = class {
1498
1522
 
1499
1523
  /**
1500
1524
  * @param {!BufferSource} rawResult
1501
- * @param {shaka.extern.HlsAes128Key} aes128Key
1502
- * @param {!shaka.media.SegmentIterator} iter
1525
+ * @param {shaka.extern.aes128Key} aes128Key
1526
+ * @param {number} position
1503
1527
  * @return {!Promise.<!BufferSource>} finalResult
1504
1528
  * @private
1505
1529
  */
1506
- async aes128Decrypt_(rawResult, aes128Key, iter) {
1530
+ async aes128Decrypt_(rawResult, aes128Key, position) {
1507
1531
  const key = aes128Key;
1508
1532
  if (!key.cryptoKey) {
1509
1533
  goog.asserts.assert(key.fetchKey, 'If AES-128 cryptoKey was not ' +
@@ -1514,7 +1538,7 @@ shaka.media.StreamingEngine = class {
1514
1538
  let iv = key.iv;
1515
1539
  if (!iv) {
1516
1540
  iv = shaka.util.BufferUtils.toUint8(new ArrayBuffer(16));
1517
- let sequence = key.firstMediaSequenceNumber + iter.currentPosition();
1541
+ let sequence = key.firstMediaSequenceNumber + position;
1518
1542
  for (let i = iv.byteLength - 1; i >= 0; i--) {
1519
1543
  iv[i] = sequence & 0xff;
1520
1544
  sequence >>= 8;
@@ -1684,22 +1708,21 @@ shaka.media.StreamingEngine = class {
1684
1708
  shaka.log.v1(logPrefix,
1685
1709
  'setting append window end to ' + appendWindowEnd);
1686
1710
 
1687
- if ((mediaState.lastCodecs && codecs != mediaState.lastCodecs) ||
1688
- (mediaState.lastMimeType && mimeType != mediaState.lastMimeType)) {
1711
+ const isResetMediaSourceNecessary =
1712
+ mediaState.lastCodecs && mediaState.lastMimeType &&
1713
+ this.playerInterface_.mediaSourceEngine.isResetMediaSourceNecessary(
1714
+ mediaState.type, mediaState.stream);
1715
+ if (isResetMediaSourceNecessary) {
1716
+ let otherState = null;
1689
1717
  if (mediaState.type === ContentType.VIDEO) {
1690
- /** @type {shaka.media.StreamingEngine.MediaState_} */
1691
- const audioState = this.mediaStates_.get(ContentType.AUDIO);
1692
- if (audioState) {
1693
- audioState.lastInitSegmentReference = null;
1694
- this.abortOperations_(audioState);
1695
- }
1718
+ otherState = this.mediaStates_.get(ContentType.AUDIO);
1696
1719
  } else if (mediaState.type === ContentType.AUDIO) {
1697
- /** @type {shaka.media.StreamingEngine.MediaState_} */
1698
- const videoState = this.mediaStates_.get(ContentType.VIDEO);
1699
- if (videoState) {
1700
- videoState.lastInitSegmentReference = null;
1701
- this.abortOperations_(videoState);
1702
- }
1720
+ otherState = this.mediaStates_.get(ContentType.VIDEO);
1721
+ }
1722
+ if (otherState) {
1723
+ otherState.lastInitSegmentReference = null;
1724
+ this.forceClearBuffer_(otherState);
1725
+ this.abortOperations_(otherState).catch(() => {});
1703
1726
  }
1704
1727
  }
1705
1728
 
@@ -1729,6 +1752,19 @@ shaka.media.StreamingEngine = class {
1729
1752
  mediaState.type, timestampOffset, appendWindowStart,
1730
1753
  appendWindowEnd, ignoreTimestampOffset,
1731
1754
  mediaState.stream, streamsByType);
1755
+ if (isResetMediaSourceNecessary) {
1756
+ let otherState = null;
1757
+ if (mediaState.type === ContentType.VIDEO) {
1758
+ otherState = this.mediaStates_.get(ContentType.AUDIO);
1759
+ } else if (mediaState.type === ContentType.AUDIO) {
1760
+ otherState = this.mediaStates_.get(ContentType.VIDEO);
1761
+ }
1762
+ if (otherState) {
1763
+ otherState.waitingToClearBuffer = false;
1764
+ otherState.performingUpdate = false;
1765
+ this.forceClearBuffer_(otherState);
1766
+ }
1767
+ }
1732
1768
  } catch (error) {
1733
1769
  mediaState.lastAppendWindowStart = null;
1734
1770
  mediaState.lastAppendWindowEnd = null;
@@ -1738,7 +1774,10 @@ shaka.media.StreamingEngine = class {
1738
1774
  throw error;
1739
1775
  }
1740
1776
  };
1741
- operations.push(setProperties());
1777
+ // Dispatching init asynchronously causes the sourceBuffers in
1778
+ // the MediaSourceEngine to become detached do to race conditions
1779
+ // with mediaSource and sourceBuffers being created simultaneously.
1780
+ await setProperties();
1742
1781
  }
1743
1782
 
1744
1783
  if (!shaka.media.InitSegmentReference.equal(
@@ -1749,8 +1788,7 @@ shaka.media.StreamingEngine = class {
1749
1788
  shaka.log.v1(logPrefix, 'fetching init segment');
1750
1789
 
1751
1790
  const fetchInit =
1752
- this.fetch_(mediaState, reference.initSegmentReference,
1753
- /* streamDataCallback= */ undefined, /* isInit= */ true);
1791
+ this.fetch_(mediaState, reference.initSegmentReference);
1754
1792
  const append = async () => {
1755
1793
  try {
1756
1794
  const initSegment = await fetchInit;
@@ -2154,13 +2192,12 @@ shaka.media.StreamingEngine = class {
2154
2192
  * @param {(!shaka.media.InitSegmentReference|!shaka.media.SegmentReference)}
2155
2193
  * reference
2156
2194
  * @param {?function(BufferSource):!Promise=} streamDataCallback
2157
- * @param {boolean=} isInit
2158
2195
  *
2159
2196
  * @return {!Promise.<BufferSource>}
2160
2197
  * @private
2161
2198
  * @suppress {strictMissingProperties}
2162
2199
  */
2163
- async fetch_(mediaState, reference, streamDataCallback, isInit) {
2200
+ async fetch_(mediaState, reference, streamDataCallback) {
2164
2201
  if (reference instanceof shaka.media.InitSegmentReference) {
2165
2202
  const segmentData = reference.getSegmentData();
2166
2203
  if (segmentData) {
@@ -2168,27 +2205,26 @@ shaka.media.StreamingEngine = class {
2168
2205
  }
2169
2206
  }
2170
2207
  let op = null;
2171
- if (
2172
- mediaState.segmentPrefetch &&
2173
- reference instanceof shaka.media.SegmentReference
2174
- ) {
2208
+ if (mediaState.segmentPrefetch) {
2175
2209
  op = mediaState.segmentPrefetch.getPrefetchedSegment(
2176
2210
  reference, streamDataCallback);
2177
2211
  }
2178
2212
  if (!op) {
2179
2213
  op = this.dispatchFetch_(
2180
- reference, mediaState.stream, streamDataCallback, isInit,
2181
- );
2214
+ reference, mediaState.stream, streamDataCallback);
2215
+ }
2216
+
2217
+ let position = 0;
2218
+ if (mediaState.segmentIterator) {
2219
+ position = mediaState.segmentIterator.currentPosition();
2182
2220
  }
2183
2221
 
2184
2222
  mediaState.operation = op;
2185
2223
  const response = await op.promise;
2186
2224
  mediaState.operation = null;
2187
2225
  let result = response.data;
2188
- if (reference.hlsAes128Key) {
2189
- const iter = mediaState.segmentIterator;
2190
- goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
2191
- result = await this.aes128Decrypt_(result, reference.hlsAes128Key, iter);
2226
+ if (reference.aes128Key) {
2227
+ result = await this.aes128Decrypt_(result, reference.aes128Key, position);
2192
2228
  }
2193
2229
  return result;
2194
2230
  }
@@ -2200,18 +2236,17 @@ shaka.media.StreamingEngine = class {
2200
2236
  * @param {(!shaka.media.InitSegmentReference|!shaka.media.SegmentReference)}
2201
2237
  * reference
2202
2238
  * @param {?function(BufferSource):!Promise=} streamDataCallback
2203
- * @param {boolean=} isInit
2204
2239
  *
2205
2240
  * @return {!shaka.net.NetworkingEngine.PendingRequest}
2206
2241
  * @private
2207
2242
  */
2208
- dispatchFetch_(reference, stream, streamDataCallback, isInit) {
2243
+ dispatchFetch_(reference, stream, streamDataCallback) {
2209
2244
  const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
2210
- const type = isInit ?
2211
- shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT :
2212
- shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT;
2213
2245
  const segment = reference instanceof shaka.media.SegmentReference ?
2214
2246
  reference : undefined;
2247
+ const type = segment ?
2248
+ shaka.net.NetworkingEngine.AdvancedRequestType.MEDIA_SEGMENT :
2249
+ shaka.net.NetworkingEngine.AdvancedRequestType.INIT_SEGMENT;
2215
2250
  const request = shaka.util.Networking.createSegmentRequest(
2216
2251
  reference.getUris(),
2217
2252
  reference.startByte,
@@ -213,6 +213,22 @@ shaka.mss.MssParser = class {
213
213
  // No-op
214
214
  }
215
215
 
216
+ /**
217
+ * @override
218
+ * @exportInterface
219
+ */
220
+ onInitialVariantChosen(variant) {
221
+ // No-op
222
+ }
223
+
224
+ /**
225
+ * @override
226
+ * @exportInterface
227
+ */
228
+ banLocation(uri) {
229
+ // No-op
230
+ }
231
+
216
232
  /**
217
233
  * Makes a network request for the manifest and parses the resulting data.
218
234
  *
@@ -500,6 +516,7 @@ shaka.mss.MssParser = class {
500
516
  const stream = {
501
517
  id: id,
502
518
  originalId: streamIndex.getAttribute('Name') || String(id),
519
+ groupId: null,
503
520
  createSegmentIndex: () => Promise.resolve(),
504
521
  closeSegmentIndex: () => Promise.resolve(),
505
522
  segmentIndex: null,
@@ -528,6 +545,7 @@ shaka.mss.MssParser = class {
528
545
  spatialAudio: false,
529
546
  closedCaptions: null,
530
547
  hdr: undefined,
548
+ videoLayout: undefined,
531
549
  tilesLayout: undefined,
532
550
  matchedStreams: [],
533
551
  mssPrivateData: {
@@ -537,6 +555,7 @@ shaka.mss.MssParser = class {
537
555
  },
538
556
  accessibilityPurpose: null,
539
557
  external: false,
558
+ fastSwitching: false,
540
559
  };
541
560
 
542
561
  // This is specifically for text tracks.
@@ -1076,7 +1095,5 @@ shaka.mss.MssParser.Context;
1076
1095
  */
1077
1096
  shaka.mss.MssParser.TimeRange;
1078
1097
 
1079
- shaka.media.ManifestParser.registerParserByExtension(
1080
- 'ism', () => new shaka.mss.MssParser());
1081
1098
  shaka.media.ManifestParser.registerParserByMime(
1082
1099
  'application/vnd.ms-sstr+xml', () => new shaka.mss.MssParser());