shaka-player 4.2.5 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/.github/workflows/build-and-test.yaml +7 -0
  2. package/.github/workflows/sync-labels.yaml +1 -1
  3. package/.github/workflows/update-issues.yaml +1 -1
  4. package/AUTHORS +4 -0
  5. package/CHANGELOG.md +114 -74
  6. package/CONTRIBUTORS +4 -0
  7. package/README.md +14 -0
  8. package/conditional/dummy_cast_proxy.js +120 -0
  9. package/demo/common/assets.js +58 -0
  10. package/demo/common/message_ids.js +22 -1
  11. package/demo/config.js +89 -5
  12. package/demo/demo.less +7 -1
  13. package/demo/index.html +8 -1
  14. package/demo/locales/en.json +21 -1
  15. package/demo/locales/source.json +82 -2
  16. package/demo/main.js +57 -1
  17. package/demo/search.js +2 -0
  18. package/demo/visualizer.js +337 -0
  19. package/demo/visualizer_button.js +103 -0
  20. package/dist/controls.css +1 -1
  21. package/dist/controls.css.map +1 -1
  22. package/dist/demo.compiled.debug.js +107 -88
  23. package/dist/demo.compiled.debug.map +4 -4
  24. package/dist/demo.compiled.js +107 -88
  25. package/dist/demo.compiled.map +4 -4
  26. package/dist/demo.css +1 -1
  27. package/dist/demo.css.map +1 -1
  28. package/dist/deps.js +21 -13
  29. package/dist/locales.js +31 -31
  30. package/dist/receiver.compiled.debug.js +75 -77
  31. package/dist/receiver.compiled.debug.map +3 -3
  32. package/dist/receiver.compiled.js +75 -77
  33. package/dist/receiver.compiled.map +3 -3
  34. package/dist/shaka-player.compiled.d.ts +181 -27
  35. package/dist/shaka-player.compiled.debug.d.ts +181 -27
  36. package/dist/shaka-player.compiled.debug.externs.js +169 -31
  37. package/dist/shaka-player.compiled.debug.js +510 -450
  38. package/dist/shaka-player.compiled.debug.map +4 -4
  39. package/dist/shaka-player.compiled.externs.js +169 -31
  40. package/dist/shaka-player.compiled.js +912 -874
  41. package/dist/shaka-player.compiled.map +4 -4
  42. package/dist/shaka-player.ui.d.ts +181 -27
  43. package/dist/shaka-player.ui.debug.d.ts +181 -27
  44. package/dist/shaka-player.ui.debug.externs.js +169 -31
  45. package/dist/shaka-player.ui.debug.js +533 -471
  46. package/dist/shaka-player.ui.debug.map +4 -4
  47. package/dist/shaka-player.ui.externs.js +169 -31
  48. package/dist/shaka-player.ui.js +1073 -1036
  49. package/dist/shaka-player.ui.map +4 -4
  50. package/docs/design/lcevc-architecture.png +0 -0
  51. package/docs/design/lcevc-demo.png +0 -0
  52. package/docs/design/lcevc-integration.md +72 -0
  53. package/docs/tutorials/fairplay.md +7 -0
  54. package/docs/tutorials/faq.md +1 -1
  55. package/docs/tutorials/ui.md +7 -7
  56. package/docs/tutorials/upgrade.md +6 -0
  57. package/externs/ima.js +13 -1
  58. package/externs/lcevc.js +81 -0
  59. package/externs/mux.js +1 -42
  60. package/externs/shaka/ads.js +11 -1
  61. package/externs/shaka/manifest_parser.js +5 -1
  62. package/externs/shaka/mp4_parser.js +3 -0
  63. package/externs/shaka/player.js +178 -15
  64. package/lib/abr/simple_abr_manager.js +7 -0
  65. package/lib/ads/ad_manager.js +0 -8
  66. package/lib/ads/client_side_ad.js +15 -0
  67. package/lib/ads/client_side_ad_manager.js +21 -8
  68. package/lib/ads/server_side_ad.js +15 -0
  69. package/lib/ads/server_side_ad_manager.js +3 -3
  70. package/lib/cast/cast_utils.js +2 -0
  71. package/lib/cea/dummy_cea_parser.js +28 -0
  72. package/lib/cea/i_cea_parser.js +14 -2
  73. package/lib/cea/mp4_cea_parser.js +108 -5
  74. package/lib/config/auto_show_text.js +33 -0
  75. package/lib/dash/dash_parser.js +1 -1
  76. package/lib/hls/hls_parser.js +808 -384
  77. package/lib/lcevc/lcevc_dil.js +152 -0
  78. package/lib/media/closed_caption_parser.js +9 -6
  79. package/lib/media/drm_engine.js +14 -6
  80. package/lib/media/media_source_capabilities.js +36 -0
  81. package/lib/media/media_source_engine.js +113 -28
  82. package/lib/media/presentation_timeline.js +26 -11
  83. package/lib/media/segment_reference.js +49 -1
  84. package/lib/media/streaming_engine.js +142 -12
  85. package/lib/media/transmuxer.js +78 -21
  86. package/lib/offline/storage.js +1 -0
  87. package/lib/player.js +456 -77
  88. package/lib/polyfill/media_capabilities.js +9 -5
  89. package/lib/polyfill/patchedmediakeys_apple.js +63 -4
  90. package/lib/text/vtt_text_parser.js +35 -1
  91. package/lib/util/dom_utils.js +0 -1
  92. package/lib/util/error.js +17 -0
  93. package/lib/util/fake_event.js +2 -0
  94. package/lib/util/id3_utils.js +300 -0
  95. package/lib/util/mime_utils.js +3 -6
  96. package/lib/util/mp4_box_parsers.js +39 -5
  97. package/lib/util/mp4_parser.js +35 -0
  98. package/lib/util/player_configuration.js +23 -1
  99. package/lib/util/stream_utils.js +5 -3
  100. package/lib/util/ts_parser.js +499 -0
  101. package/maintained-branches.md +2 -2
  102. package/package.json +7 -4
  103. package/roadmap.md +5 -3
  104. package/test/ads/ad_manager_unit.js +182 -29
  105. package/test/cast/cast_utils_unit.js +3 -1
  106. package/test/dash/dash_parser_content_protection_unit.js +1 -0
  107. package/test/dash/dash_parser_live_unit.js +1 -0
  108. package/test/dash/dash_parser_manifest_unit.js +93 -1
  109. package/test/dash/dash_parser_segment_base_unit.js +1 -0
  110. package/test/dash/dash_parser_segment_list_unit.js +1 -0
  111. package/test/dash/dash_parser_segment_template_unit.js +1 -0
  112. package/test/demo/demo_unit.js +2 -1
  113. package/test/hls/hls_live_unit.js +253 -19
  114. package/test/hls/hls_parser_unit.js +631 -12
  115. package/test/media/closed_caption_parser_unit.js +2 -1
  116. package/test/media/drm_engine_integration.js +3 -1
  117. package/test/media/media_source_engine_integration.js +71 -6
  118. package/test/media/media_source_engine_unit.js +10 -5
  119. package/test/media/streaming_engine_integration.js +4 -1
  120. package/test/media/streaming_engine_unit.js +144 -1
  121. package/test/media/transmuxer_integration.js +21 -10
  122. package/test/player_integration.js +224 -82
  123. package/test/player_unit.js +5 -2
  124. package/test/polyfill/media_capabilities_unit.js +21 -23
  125. package/test/polyfill/patchedmediakeys_apple_unit.js +130 -0
  126. package/test/test/assets/id3-metadata.aac +0 -0
  127. package/test/test/assets/id3-metadata.ts +0 -0
  128. package/test/test/assets/thumbnails-sprites.vtt +10 -0
  129. package/test/test/assets/thumbnails.vtt +10 -0
  130. package/test/test/util/dash_parser_util.js +2 -0
  131. package/test/test/util/fake_ad.js +21 -0
  132. package/test/test/util/fake_media_source_engine.js +7 -0
  133. package/test/test/util/id3_generator.js +100 -0
  134. package/test/test/util/manifest_generator.js +3 -6
  135. package/test/test/util/simple_fakes.js +4 -0
  136. package/test/test/util/stream_generator.js +38 -0
  137. package/test/test/util/test_scheme.js +43 -14
  138. package/test/text/vtt_text_parser_unit.js +11 -0
  139. package/test/util/id3_utils_unit.js +116 -0
  140. package/test/util/ts_parser_unit.js +77 -0
  141. package/third_party/closure-uri/uri.js +1 -1
  142. package/ui/less/containers.less +7 -0
  143. package/ui/ui.js +43 -4
@@ -17,6 +17,7 @@ shakaDemo.MessageIds = {
17
17
  DASH: 'DEMO_DASH',
18
18
  HIGH_DEFINITION: 'DEMO_HIGH_DEFINITION',
19
19
  HLS: 'DEMO_HLS',
20
+ LCEVC: 'DEMO_LCEVC',
20
21
  LIVE: 'DEMO_LIVE',
21
22
  MP2TS: 'DEMO_MP2TS',
22
23
  MP4: 'DEMO_MP4',
@@ -85,6 +86,10 @@ shakaDemo.MessageIds = {
85
86
  UNSUPPORTED_NO_OFFLINE: 'DEMO_UNSUPPORTED_NO_OFFLINE',
86
87
  UNSUPPORTED_NO_KEY_SUPPORT: 'DEMO_UNSUPPORTED_NO_KEY_SUPPORT',
87
88
  UNSUPPORTED_NO_LICENSE_SUPPORT: 'DEMO_UNSUPPORTED_NO_LICENSE_SUPPORT',
89
+ /* Visualizer. */
90
+ VISUALIZER_AUTO_SCREENSHOT_TOGGLE: 'DEMO_VISUALIZER_AUTO_SCREENSHOT_TOGGLE',
91
+ VISUALIZER_BUTTON: 'DEMO_VISUALIZER_BUTTON',
92
+ VISUALIZER_SCREENSHOT_BUTTON: 'DEMO_VISUALIZER_SCREENSHOT_BUTTON',
88
93
  /* Asset card. */
89
94
  DELETE_STORED_PROMPT: 'DEMO_DELETE_STORED_PROMPT',
90
95
  UNSUPPORTED: 'DEMO_UNSUPPORTED',
@@ -151,6 +156,11 @@ shakaDemo.MessageIds = {
151
156
  AUDIO_ROBUSTNESS: 'DEMO_AUDIO_ROBUSTNESS',
152
157
  AUTO_CORRECT_DASH_DRIFT: 'DEMO_AUTO_CORRECT_DASH_DRIFT',
153
158
  AUTO_LOW_LATENCY: 'DEMO_AUTO_LOW_LATENCY',
159
+ AUTO_SHOW_TEXT: 'DEMO_AUTO_SHOW_TEXT',
160
+ AUTO_SHOW_TEXT_NEVER: 'DEMO_AUTO_SHOW_TEXT_NEVER',
161
+ AUTO_SHOW_TEXT_ALWAYS: 'DEMO_AUTO_SHOW_TEXT_ALWAYS',
162
+ AUTO_SHOW_TEXT_IF_PREFERRED_TEXT_LANGUAGE: 'DEMO_AUTO_SHOW_TEXT_IF_PREFERRED_TEXT_LANGUAGE',
163
+ AUTO_SHOW_TEXT_IF_SUBTITLES_MAY_BE_NEEDED: 'DEMO_AUTO_SHOW_TEXT_IF_SUBTITLES_MAY_BE_NEEDED',
154
164
  AVAILABILITY_WINDOW_OVERRIDE: 'DEMO_AVAILABILITY_WINDOW_OVERRIDE',
155
165
  BACKOFF_FACTOR: 'DEMO_BACKOFF_FACTOR',
156
166
  BASE_DELAY: 'DEMO_BASE_DELAY',
@@ -181,7 +191,7 @@ shakaDemo.MessageIds = {
181
191
  ENABLED: 'DEMO_ENABLED',
182
192
  FAST_HALF_LIFE: 'DEMO_FAST_HALF_LIFE',
183
193
  FORCE_HTTPS: 'DEMO_FORCE_HTTPS',
184
- FORCE_TRANSMUX_TS: 'DEMO_FORCE_TRANSMUX_TS',
194
+ FORCE_TRANSMUX: 'DEMO_FORCE_TRANSMUX',
185
195
  FUZZ_FACTOR: 'DEMO_FUZZ_FACTOR',
186
196
  GAP_DETECTION_THRESHOLD: 'DEMO_GAP_DETECTION_THRESHOLD',
187
197
  IGNORE_DASH_EMPTY_ADAPTATION_SET: 'DEMO_IGNORE_DASH_EMPTY_ADAPTATION_SET',
@@ -197,6 +207,11 @@ shakaDemo.MessageIds = {
197
207
  INACCURATE_MANIFEST_TOLERANCE: 'DEMO_INACCURATE_MANIFEST_TOLERANCE',
198
208
  INITIAL_SEGMENT_LIMIT: 'DEMO_INITIAL_SEGMENT_LIMIT',
199
209
  LANGUAGE_SECTION_HEADER: 'DEMO_LANGUAGE_SECTION_HEADER',
210
+ LCEVC_DRAW_LOGO: 'DEMO_LCEVC_DRAW_LOGO',
211
+ LCEVC_DYNAMIC_PERFORMANCE_SCALING: 'DEMO_LCEVC_DYNAMIC_PERFORMANCE_SCALING',
212
+ LCEVC_LOG_LEVEL: 'DEMO_LCEVC_LOG_LEVEL',
213
+ LCEVC_SECTION_HEADER: 'DEMO_LCEVC_SECTION_HEADER',
214
+ LIVE_SEGMENTS_DELAY: 'DEMO_LIVE_SEGMENTS_DELAY',
200
215
  LOG_LEVEL: 'DEMO_LOG_LEVEL',
201
216
  LOG_LEVEL_DEBUG: 'DEMO_LOG_LEVEL_DEBUG',
202
217
  LOG_LEVEL_INFO: 'DEMO_LOG_LEVEL_INFO',
@@ -213,6 +228,7 @@ shakaDemo.MessageIds = {
213
228
  MAX_HEIGHT: 'DEMO_MAX_HEIGHT',
214
229
  MAX_PIXELS: 'DEMO_MAX_PIXELS',
215
230
  MAX_WIDTH: 'DEMO_MAX_WIDTH',
231
+ MEDIA_SOURCE_SECTION_HEADER: 'DEMO_MEDIA_SOURCE_SECTION_HEADER',
216
232
  MIN_BANDWIDTH: 'DEMO_MIN_BANDWIDTH',
217
233
  MIN_BYTES: 'DEMO_MIN_BYTES',
218
234
  MIN_FRAMERATE: 'DEMO_MIN_FRAMERATE',
@@ -232,13 +248,16 @@ shakaDemo.MessageIds = {
232
248
  PREFER_NATIVE_HLS: 'DEMO_PREFER_NATIVE_HLS',
233
249
  REBUFFERING_GOAL: 'DEMO_REBUFFERING_GOAL',
234
250
  RESTRICT_TO_ELEMENT_SIZE: 'DEMO_RESTRICT_TO_ELEMENT_SIZE',
251
+ RESTRICT_TO_SCREEN_SIZE: 'DEMO_RESTRICT_TO_SCREEN_SIZE',
235
252
  RESTRICTIONS_SECTION_HEADER: 'DEMO_RESTRICTIONS_SECTION_HEADER',
236
253
  SAFE_SEEK_OFFSET: 'DEMO_SAFE_SEEK_OFFSET',
237
254
  SAFE_SKIP_DISTANCE: 'DEMO_SAFE_SKIP_DISTANCE',
238
255
  SEGMENT_RELATIVE_VTT_TIMING: 'DEMO_SEGMENT_RELATIVE_VTT_TIMING',
256
+ SEQUENCE_MODE: 'DEMO_SEQUENCE_MODE',
239
257
  SESSION_ID: 'DEMO_SESSION_ID',
240
258
  SHAKA_CONTROLS: 'DEMO_SHAKA_CONTROLS',
241
259
  SLOW_HALF_LIFE: 'DEMO_SLOW_HALF_LIFE',
260
+ SOURCE_BUFFER_EXTRA_FEATURES: 'DEMO_SOURCE_BUFFER_EXTRA_FEATURES',
242
261
  STALL_DETECTOR_ENABLED: 'DEMO_STALL_DETECTOR_ENABLED',
243
262
  STALL_THRESHOLD: 'DEMO_STALL_THRESHOLD',
244
263
  STALL_TIMEOUT: 'DEMO_STALL_TIMEOUT',
@@ -257,7 +276,9 @@ shakaDemo.MessageIds = {
257
276
  USE_HEADERS: 'DEMO_USE_HEADERS',
258
277
  USE_NATIVE_HLS_SAFARI: 'DEMO_USE_NATIVE_HLS_SAFARI',
259
278
  USE_PERSISTENT_LICENSES: 'DEMO_USE_PERSISTENT_LICENSES',
279
+ USE_SAFARI_BEHAVIOR_FOR_LIVE: 'DEMO_USE_SAFARI_BEHAVIOR_FOR_LIVE',
260
280
  VIDEO_ROBUSTNESS: 'DEMO_VIDEO_ROBUSTNESS',
281
+ VNOVA: 'DEMO_VNOVA',
261
282
  XLINK_FAIL_GRACEFULLY: 'DEMO_XLINK_FAIL_GRACEFULLY',
262
283
  };
263
284
  /* eslint-enable max-len */
package/demo/config.js CHANGED
@@ -92,10 +92,12 @@ shakaDemo.Config = class {
92
92
  this.addOfflineSection_();
93
93
  this.addDrmSection_();
94
94
  this.addStreamingSection_();
95
+ this.addMediaSourceSection_();
95
96
  this.addManifestSection_();
96
97
  this.addRetrictionsSection_('',
97
98
  shakaDemo.MessageIds.RESTRICTIONS_SECTION_HEADER);
98
99
  this.addCmcdSection_();
100
+ this.addLcevcSection_();
99
101
  }
100
102
 
101
103
  /**
@@ -216,6 +218,10 @@ shakaDemo.Config = class {
216
218
  'manifest.hls.defaultVideoCodec')
217
219
  .addBoolInput_(MessageIds.IGNORE_MANIFEST_PROGRAM_DATE_TIME,
218
220
  'manifest.hls.ignoreManifestProgramDateTime')
221
+ .addBoolInput_(MessageIds.USE_SAFARI_BEHAVIOR_FOR_LIVE,
222
+ 'manifest.hls.useSafariBehaviorForLive')
223
+ .addNumberInput_(MessageIds.LIVE_SEGMENTS_DELAY,
224
+ 'manifest.hls.liveSegmentsDelay')
219
225
  .addNumberInput_(MessageIds.AVAILABILITY_WINDOW_OVERRIDE,
220
226
  'manifest.availabilityWindowOverride',
221
227
  /* canBeDecimal= */ true,
@@ -231,6 +237,8 @@ shakaDemo.Config = class {
231
237
  /* canBeDecimal= */ false,
232
238
  /* canBeZero= */ false,
233
239
  /* canBeUnset= */ true)
240
+ .addBoolInput_(MessageIds.SEQUENCE_MODE,
241
+ 'manifest.dash.sequenceMode')
234
242
  .addBoolInput_(MessageIds.DISABLE_AUDIO,
235
243
  'manifest.disableAudio')
236
244
  .addBoolInput_(MessageIds.DISABLE_VIDEO,
@@ -276,6 +284,8 @@ shakaDemo.Config = class {
276
284
  /* canBeDecimal= */ true)
277
285
  .addBoolInput_(MessageIds.RESTRICT_TO_ELEMENT_SIZE,
278
286
  'abr.restrictToElementSize')
287
+ .addBoolInput_(MessageIds.RESTRICT_TO_SCREEN_SIZE,
288
+ 'abr.restrictToScreenSize')
279
289
  .addBoolInput_(MessageIds.IGNORE_DEVICE_PIXEL_RATIO,
280
290
  'abr.ignoreDevicePixelRatio');
281
291
  this.addRetrictionsSection_('abr',
@@ -293,6 +303,18 @@ shakaDemo.Config = class {
293
303
  .addBoolInput_(MessageIds.USE_HEADERS, 'cmcd.useHeaders');
294
304
  }
295
305
 
306
+ /** @private */
307
+ addLcevcSection_() {
308
+ const MessageIds = shakaDemo.MessageIds;
309
+ const docLink = this.resolveExternLink_('.LcevcConfiguration');
310
+ this.addSection_(MessageIds.LCEVC_SECTION_HEADER, docLink)
311
+ .addBoolInput_(MessageIds.ENABLED, 'lcevc.enabled')
312
+ .addBoolInput_(MessageIds.LCEVC_DYNAMIC_PERFORMANCE_SCALING,
313
+ 'lcevc.dynamicPerformanceScaling')
314
+ .addNumberInput_(MessageIds.LCEVC_LOG_LEVEL, 'lcevc.logLevel')
315
+ .addBoolInput_(MessageIds.LCEVC_DRAW_LOGO, 'lcevc.drawLogo');
316
+ }
317
+
296
318
  /**
297
319
  * @param {string} category
298
320
  * @param {!shakaDemo.MessageIds} sectionName
@@ -414,8 +436,8 @@ shakaDemo.Config = class {
414
436
  this.latestInput_.input().checked = true;
415
437
  }
416
438
 
417
- this.addBoolInput_(MessageIds.FORCE_TRANSMUX_TS,
418
- 'streaming.forceTransmuxTS')
439
+ this.addBoolInput_(MessageIds.FORCE_TRANSMUX,
440
+ 'streaming.forceTransmux')
419
441
  .addBoolInput_(MessageIds.START_AT_SEGMENT_BOUNDARY,
420
442
  'streaming.startAtSegmentBoundary')
421
443
  .addBoolInput_(MessageIds.IGNORE_TEXT_FAILURES,
@@ -428,14 +450,40 @@ shakaDemo.Config = class {
428
450
  MessageIds.STREAMING_RETRY_SECTION_HEADER);
429
451
  }
430
452
 
453
+ /** @private */
454
+ addMediaSourceSection_() {
455
+ const MessageIds = shakaDemo.MessageIds;
456
+ const docLink = this.resolveExternLink_('.MediaSourceConfiguration');
457
+ this.addSection_(MessageIds.MEDIA_SOURCE_SECTION_HEADER, docLink)
458
+ .addTextInput_(MessageIds.SOURCE_BUFFER_EXTRA_FEATURES,
459
+ 'mediaSource.sourceBufferExtraFeatures');
460
+ }
461
+
431
462
  /** @private */
432
463
  addLanguageSection_() {
433
464
  const MessageIds = shakaDemo.MessageIds;
434
465
  const docLink = this.resolveExternLink_('.PlayerConfiguration');
466
+
467
+ const autoShowTextOptions = shaka.config.AutoShowText;
468
+ const localize = (name) => shakaDemoMain.getLocalizedString(name);
469
+ const autoShowTextOptionNames = {
470
+ 'NEVER': localize(MessageIds.AUTO_SHOW_TEXT_NEVER),
471
+ 'ALWAYS': localize(MessageIds.AUTO_SHOW_TEXT_ALWAYS),
472
+ 'IF_PREFERRED_TEXT_LANGUAGE':
473
+ localize(MessageIds.AUTO_SHOW_TEXT_IF_PREFERRED_TEXT_LANGUAGE),
474
+ 'IF_SUBTITLES_MAY_BE_NEEDED':
475
+ localize(MessageIds.AUTO_SHOW_TEXT_IF_SUBTITLES_MAY_BE_NEEDED),
476
+ };
477
+
435
478
  this.addSection_(MessageIds.LANGUAGE_SECTION_HEADER, docLink)
436
479
  .addTextInput_(MessageIds.AUDIO_LANGUAGE, 'preferredAudioLanguage')
437
480
  .addTextInput_(MessageIds.TEXT_LANGUAGE, 'preferredTextLanguage')
438
- .addTextInput_(MessageIds.TEXT_ROLE, 'preferredTextRole');
481
+ .addTextInput_(MessageIds.TEXT_ROLE, 'preferredTextRole')
482
+ .addSelectInput_(
483
+ MessageIds.AUTO_SHOW_TEXT,
484
+ 'autoShowText',
485
+ autoShowTextOptions,
486
+ autoShowTextOptionNames);
439
487
  const onChange = (input) => {
440
488
  shakaDemoMain.setUILocale(input.value);
441
489
  shakaDemoMain.remakeHash();
@@ -525,7 +573,7 @@ shakaDemo.Config = class {
525
573
  }
526
574
  shakaDemoMain.remakeHash();
527
575
  };
528
- this.addSelectInput_(MessageIds.LOG_LEVEL, logLevels, onChange);
576
+ this.addCustomSelectInput_(MessageIds.LOG_LEVEL, logLevels, onChange);
529
577
  const input = this.latestInput_.input();
530
578
  switch (shaka['log']['currentLevel']) {
531
579
  case Level['DEBUG']:
@@ -707,7 +755,7 @@ shakaDemo.Config = class {
707
755
  * @return {!shakaDemo.Config}
708
756
  * @private
709
757
  */
710
- addSelectInput_(name, values, onChange, tooltipMessage) {
758
+ addCustomSelectInput_(name, values, onChange, tooltipMessage) {
711
759
  this.createRow_(name, tooltipMessage);
712
760
  // The input is not provided a name, as (in this enclosed space) it makes
713
761
  // the actual field unreadable.
@@ -716,6 +764,42 @@ shakaDemo.Config = class {
716
764
  return this;
717
765
  }
718
766
 
767
+ /**
768
+ * @param {!shakaDemo.MessageIds} name
769
+ * @param {string} valueName
770
+ * @param {!Object.<string, ?>} options
771
+ * @param {!Object.<string, string>} optionNames
772
+ * @param {shakaDemo.MessageIds=} tooltipMessage
773
+ * @return {!shakaDemo.Config}
774
+ * @private
775
+ */
776
+ addSelectInput_(name, valueName, options, optionNames, tooltipMessage) {
777
+ const onChange = (input) => {
778
+ shakaDemoMain.configure(valueName, options[input.value]);
779
+ shakaDemoMain.remakeHash();
780
+ };
781
+
782
+ // If there are any translations missing for option names, fill in the
783
+ // constant from the enum. This ensures new enum values are usable in the
784
+ // demo in some form, even if they are forgotten in the demo config.
785
+ for (const key in options) {
786
+ if (!(key in optionNames)) {
787
+ optionNames[key] = key;
788
+ }
789
+ }
790
+
791
+ this.addCustomSelectInput_(name, optionNames, onChange, tooltipMessage);
792
+
793
+ const initialValue = shakaDemoMain.getCurrentConfigValue(valueName);
794
+ for (const key in options) {
795
+ if (options[key] == initialValue) {
796
+ this.latestInput_.input().value = key;
797
+ }
798
+ }
799
+
800
+ return this;
801
+ }
802
+
719
803
  /**
720
804
  * @param {!shakaDemo.MessageIds} name
721
805
  * @param {shakaDemo.MessageIds=} tooltipMessage
package/demo/demo.less CHANGED
@@ -125,7 +125,7 @@ html, body {
125
125
  .hamburger-menu .mdl-textfield {
126
126
  padding: 0;
127
127
  // The default width of 300px is a bit too wide for us.
128
- width: 200px;
128
+ width: 220px;
129
129
  }
130
130
 
131
131
  .hamburger-menu .mdl-textfield__label {
@@ -510,6 +510,12 @@ footer .mdl-mega-footer__link-list {
510
510
  max-width: 100%;
511
511
  }
512
512
 
513
+ #visualizer-canvas {
514
+ display: flex;
515
+ width: 100%;
516
+ height: 120px;
517
+ }
518
+
513
519
  #video-bar.no-input-sized {
514
520
  /* Add some additional padding so that TV overscan doesn't cut off the version
515
521
  * number or other information we might need. */
package/demo/index.html CHANGED
@@ -38,6 +38,8 @@
38
38
  <script defer src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
39
39
  <!-- transmuxing support is enabled by including this: -->
40
40
  <script defer src="../node_modules/mux.js/dist/mux.min.js"></script>
41
+ <!-- MPEG-5 Part2 LCEVC support is enabled by including this: -->
42
+ <script defer src="../node_modules/lcevc_dil.js/dist/lcevc_dil.min.js"></script>
41
43
  <!-- MDL is enabled by including this: -->
42
44
  <script defer src="../node_modules/material-design-lite/dist/material.min.js"></script>
43
45
  <!-- MDL modal dialogs are enabled by including these: -->
@@ -126,10 +128,15 @@ UNCOMPILED_JS = [
126
128
  </div>
127
129
  <main class="mdl-layout__content" id="main-div">
128
130
  <div id="video-bar" class="hidden">
129
- <div data-shaka-player-container data-shaka-player-cast-receiver-id="A67E4E9A" class="video-container">
131
+ <div data-shaka-player-container data-shaka-player-cast-receiver-id="8D8C71A7" class="video-container">
130
132
  <video data-shaka-player autoplay playsinline id="video"></video>
131
133
  </div>
132
134
  </div>
135
+ <div id="visualizer-div" class="hidden should-disable-on-fail">
136
+ <canvas id="visualizer-canvas"></canvas>
137
+ <div id="visualizer-controls-div"></div>
138
+ <div id="visualizer-screenshot-div"></div>
139
+ </div>
133
140
  <div id="contents" class="should-hide-in-no-input-mode"></div>
134
141
  <footer class="mdl-mega-footer should-hide-in-no-input-mode">
135
142
  <div class="mdl-mega-footer__middle-section">
@@ -16,6 +16,11 @@
16
16
  "DEMO_AUDIO_ROBUSTNESS": "Audio Robustness",
17
17
  "DEMO_AUTO_CORRECT_DASH_DRIFT": "Auto-Correct DASH Drift",
18
18
  "DEMO_AUTO_LOW_LATENCY": "Auto Low Latency Mode",
19
+ "DEMO_AUTO_SHOW_TEXT": "Auto-Show Text",
20
+ "DEMO_AUTO_SHOW_TEXT_NEVER": "Never",
21
+ "DEMO_AUTO_SHOW_TEXT_ALWAYS": "Always",
22
+ "DEMO_AUTO_SHOW_TEXT_IF_PREFERRED_TEXT_LANGUAGE": "If preferred text language",
23
+ "DEMO_AUTO_SHOW_TEXT_IF_SUBTITLES_MAY_BE_NEEDED": "If subtitles may be needed",
19
24
  "DEMO_AVAILABILITY_WINDOW_OVERRIDE": "Availability Window Override",
20
25
  "DEMO_AXINOM": "Axinom",
21
26
  "DEMO_AZURE_MEDIA_SERVICES": "Azure Media Services",
@@ -77,7 +82,7 @@
77
82
  "DEMO_FAIRPLAY": "Fairplay DRM",
78
83
  "DEMO_FAST_HALF_LIFE": "Fast half life",
79
84
  "DEMO_FORCE_HTTPS": "Force HTTPS",
80
- "DEMO_FORCE_TRANSMUX_TS": "Force Transmux TS",
85
+ "DEMO_FORCE_TRANSMUX": "Force Transmux",
81
86
  "DEMO_FRONT_INTRO_DISMISS": "Dismiss",
82
87
  "DEMO_FRONT_INTRO_ONE": "This is a demo of Google's Shaka Player, a JavaScript library for adaptive video streaming.",
83
88
  "DEMO_FRONT_INTRO_TWO": "Choose a video to playback; more assets are available via the \"all content\" tab.",
@@ -110,6 +115,11 @@
110
115
  "DEMO_IRT": "IRT",
111
116
  "DEMO_JSDELIVR": "jsDelivr",
112
117
  "DEMO_LANGUAGE_SECTION_HEADER": "Language",
118
+ "DEMO_LCEVC": "LCEVC",
119
+ "DEMO_LCEVC_DRAW_LOGO": "Draw LCEVC Logo",
120
+ "DEMO_LCEVC_DYNAMIC_PERFORMANCE_SCALING": "LCEVC Dynamic Performance scaling",
121
+ "DEMO_LCEVC_LOG_LEVEL": "LCEVC Log Level",
122
+ "DEMO_LCEVC_SECTION_HEADER": "MPEG-5 Part-2 LCEVC",
113
123
  "DEMO_LIBRARIES": "Google Hosted Libraries",
114
124
  "DEMO_LICENSE": "Apache License",
115
125
  "DEMO_LICENSE_CERTIFICATE_URL": "Custom License Certificate URL",
@@ -119,6 +129,7 @@
119
129
  "DEMO_LICENSE_SERVER_URL": "Custom License Server URL",
120
130
  "DEMO_LIVE": "Live",
121
131
  "DEMO_LIVE_SEARCH": "Live",
132
+ "DEMO_LIVE_SEGMENTS_DELAY": "Live segments delay",
122
133
  "DEMO_LOG_LEVEL": "Log Level",
123
134
  "DEMO_LOG_LEVEL_DEBUG": "Debug",
124
135
  "DEMO_LOG_LEVEL_INFO": "Info",
@@ -139,6 +150,7 @@
139
150
  "DEMO_MAX_HEIGHT": "Max Height",
140
151
  "DEMO_MAX_PIXELS": "Max Pixels",
141
152
  "DEMO_MAX_WIDTH": "Max Width",
153
+ "DEMO_MEDIA_SOURCE_SECTION_HEADER": "Media source",
142
154
  "DEMO_METACDN": "MetaCDN",
143
155
  "DEMO_MICROSOFT": "Microsoft",
144
156
  "DEMO_MIME_TYPE": "MIME Type",
@@ -180,16 +192,19 @@
180
192
  "DEMO_REBUFFERING_GOAL": "Rebuffering Goal",
181
193
  "DEMO_REPORT_BUG": "REPORT BUG",
182
194
  "DEMO_RESTRICT_TO_ELEMENT_SIZE": "Restrict to element size",
195
+ "DEMO_RESTRICT_TO_SCREEN_SIZE": "Restrict to screen size",
183
196
  "DEMO_RESTRICTIONS_SECTION_HEADER": "Restrictions",
184
197
  "DEMO_SAFE_SEEK_OFFSET": "Safe Seek Offset",
185
198
  "DEMO_SAFE_SKIP_DISTANCE": "Safe Skip Distance",
186
199
  "DEMO_SEGMENT_RELATIVE_VTT_TIMING": "Enable segment-relative VTT Timing",
200
+ "DEMO_SEQUENCE_MODE": "Enable sequence mode",
187
201
  "DEMO_SESSION_ID": "Session ID",
188
202
  "DEMO_SAVE_BUTTON": "Save",
189
203
  "DEMO_SHAKA": "Shaka",
190
204
  "DEMO_SHAKA_CONTROLS": "Shaka Controls",
191
205
  "DEMO_SLOW_HALF_LIFE": "Slow half life",
192
206
  "DEMO_SOURCE": "Source on GitHub",
207
+ "DEMO_SOURCE_BUFFER_EXTRA_FEATURES": "Source buffer extra features",
193
208
  "DEMO_SOURCE_SEARCH": "Source",
194
209
  "DEMO_STALL_DETECTOR_ENABLED": "Stall Detector Enabled",
195
210
  "DEMO_STALL_THRESHOLD": "Stall Threshold",
@@ -232,7 +247,12 @@
232
247
  "DEMO_USE_HEADERS": "Use Headers",
233
248
  "DEMO_USE_NATIVE_HLS_SAFARI": "Use native HLS on Safari",
234
249
  "DEMO_USE_PERSISTENT_LICENSES": "Use Persistent Licenses",
250
+ "DEMO_USE_SAFARI_BEHAVIOR_FOR_LIVE": "Use Safari behavior for live",
235
251
  "DEMO_VIDEO_ROBUSTNESS": "Video Robustness",
252
+ "DEMO_VISUALIZER_AUTO_SCREENSHOT_TOGGLE": "Take Screenshot On Stall",
253
+ "DEMO_VISUALIZER_BUTTON": "Buffer Visualizer",
254
+ "DEMO_VISUALIZER_SCREENSHOT_BUTTON": "Take Screenshot",
255
+ "DEMO_VNOVA": "V-Nova",
236
256
  "DEMO_VOD": "VOD",
237
257
  "DEMO_WEBM": "WebM",
238
258
  "DEMO_WIDEVINE": "Widevine DRM",
@@ -67,6 +67,26 @@
67
67
  "description": "The name of a configuration value.",
68
68
  "message": "Auto Low Latency Streaming"
69
69
  },
70
+ "DEMO_AUTO_SHOW_TEXT": {
71
+ "description": "The name of a configuration value.",
72
+ "message": "Auto-Show Text"
73
+ },
74
+ "DEMO_AUTO_SHOW_TEXT_NEVER": {
75
+ "description": "The name of a configuration value.",
76
+ "message": "Never"
77
+ },
78
+ "DEMO_AUTO_SHOW_TEXT_ALWAYS": {
79
+ "description": "The name of a configuration value.",
80
+ "message": "Always"
81
+ },
82
+ "DEMO_AUTO_SHOW_TEXT_IF_PREFERRED_TEXT_LANGUAGE": {
83
+ "description": "The name of a configuration value.",
84
+ "message": "If preferred text language"
85
+ },
86
+ "DEMO_AUTO_SHOW_TEXT_IF_SUBTITLES_MAY_BE_NEEDED": {
87
+ "description": "The name of a configuration value.",
88
+ "message": "If subtitles may be needed"
89
+ },
70
90
  "DEMO_AVAILABILITY_WINDOW_OVERRIDE": {
71
91
  "description": "The name of a configuration value.",
72
92
  "message": "Availability Window Override"
@@ -311,9 +331,9 @@
311
331
  "description": "The name of a configuration value.",
312
332
  "message": "Force [JARGON:HTTPS]"
313
333
  },
314
- "DEMO_FORCE_TRANSMUX_TS": {
334
+ "DEMO_FORCE_TRANSMUX": {
315
335
  "description": "The name of a configuration value.",
316
- "message": "Force Transmux [JARGON:MPEG-2 TS]"
336
+ "message": "Force Transmux"
317
337
  },
318
338
  "DEMO_FRONT_INTRO_DISMISS": {
319
339
  "description": "A button allowing users to dismiss the intro message.",
@@ -443,6 +463,26 @@
443
463
  "description": "The header for a section of configuration values.",
444
464
  "message": "Language"
445
465
  },
466
+ "DEMO_LCEVC": {
467
+ "description": "Text that describes an asset that has LCEVC.",
468
+ "message": "[PROPER_NAME:LCEVC]"
469
+ },
470
+ "DEMO_LCEVC_DRAW_LOGO": {
471
+ "description": "LCEVC Watermark on the top left hand corner of the canvas.",
472
+ "message": "Draw [PROPER_NAME:LCEVC] Logo"
473
+ },
474
+ "DEMO_LCEVC_DYNAMIC_PERFORMANCE_SCALING": {
475
+ "description": "Dynamic Performance scaling for enabling/disabling LCEVC decoding based on decode performance.",
476
+ "message": "[PROPER_NAME:LCEVC] [JARGON:Dynamic Performance scaling]"
477
+ },
478
+ "DEMO_LCEVC_LOG_LEVEL": {
479
+ "description": "Log Level for LCEVC Lib (0-5)",
480
+ "message": "[PROPER_NAME:LCEVC] Log Level"
481
+ },
482
+ "DEMO_LCEVC_SECTION_HEADER": {
483
+ "description": "The header for a section of configuration values.",
484
+ "message": "[PROPER_NAME:MPEG-5 Part-2 LCEVC]"
485
+ },
446
486
  "DEMO_LIBRARIES": {
447
487
  "description": "A link in the footer, to Shaka Player in the Google Hosted Libraries CDN.",
448
488
  "message": "[PROPER_NAME:Google Hosted Libraries]"
@@ -479,6 +519,10 @@
479
519
  "description": "A header on a search field that filters by whether the asset is live or not.",
480
520
  "message": "Live"
481
521
  },
522
+ "DEMO_LIVE_SEGMENTS_DELAY": {
523
+ "description": "The name of a configuration value.",
524
+ "message": "Live segments delay"
525
+ },
482
526
  "DEMO_LOG_LEVEL": {
483
527
  "description": "The name of a configuration value.",
484
528
  "message": "Log Level"
@@ -559,6 +603,10 @@
559
603
  "description": "The name of a configuration value.",
560
604
  "message": "Max Width"
561
605
  },
606
+ "DEMO_MEDIA_SOURCE_SECTION_HEADER": {
607
+ "description": "The header for a section of configuration values.",
608
+ "message": "Media source"
609
+ },
562
610
  "DEMO_METACDN": {
563
611
  "description": "Text that describes an asset that comes from the MetaCDN asset library.",
564
612
  "message": "[PROPER_NAME:MetaCDN]"
@@ -723,6 +771,10 @@
723
771
  "description": "The name of a configuration value.",
724
772
  "message": "Restrict to element size"
725
773
  },
774
+ "DEMO_RESTRICT_TO_SCREEN_SIZE": {
775
+ "description": "The name of a configuration value.",
776
+ "message": "Restrict to screen size"
777
+ },
726
778
  "DEMO_RESTRICTIONS_SECTION_HEADER": {
727
779
  "description": "The header for a section of configuration values.",
728
780
  "message": "Restrictions"
@@ -743,6 +795,10 @@
743
795
  "description": "The name of a configuration value.",
744
796
  "message": "Enable segment-relative VTT Timing"
745
797
  },
798
+ "DEMO_SEQUENCE_MODE": {
799
+ "description": "The name of a configuration value.",
800
+ "message": "Enable sequence mode"
801
+ },
746
802
  "DEMO_SESSION_ID": {
747
803
  "description": "The name of a configuration value.",
748
804
  "message": "Session ID"
@@ -763,6 +819,10 @@
763
819
  "description": "A link in the footer, to the Shaka Player source on GitHub.",
764
820
  "message": "Source on [PROPER_NAME:GitHub]"
765
821
  },
822
+ "DEMO_SOURCE_BUFFER_EXTRA_FEATURES": {
823
+ "description": "The name of a configuration value.",
824
+ "message": "Source buffer extra features"
825
+ },
766
826
  "DEMO_SOURCE_SEARCH": {
767
827
  "description": "A header on a search field that filters by the source of the asset.",
768
828
  "message": "Source"
@@ -931,10 +991,30 @@
931
991
  "description": "The name of a configuration value.",
932
992
  "message": "Use Persistent Licenses"
933
993
  },
994
+ "DEMO_USE_SAFARI_BEHAVIOR_FOR_LIVE": {
995
+ "description": "The name of a configuration value.",
996
+ "message": "Use Safari behavior for live"
997
+ },
934
998
  "DEMO_VIDEO_ROBUSTNESS": {
935
999
  "description": "The name of a configuration value.",
936
1000
  "message": "Video Robustness"
937
1001
  },
1002
+ "DEMO_VISUALIZER_AUTO_SCREENSHOT_TOGGLE": {
1003
+ "description": "A configuration toggle that makes the visualizer take a screenshot when the presentation stalls.",
1004
+ "message": "Take Screenshot On Stall"
1005
+ },
1006
+ "DEMO_VISUALIZER_BUTTON": {
1007
+ "description": "A button on the video that opens or hides the visualizer.",
1008
+ "message": "Buffer Visualizer"
1009
+ },
1010
+ "DEMO_VISUALIZER_SCREENSHOT_BUTTON": {
1011
+ "description": "A button that takes a screenshot of the current visualizer state.",
1012
+ "message": "Take Screenshot"
1013
+ },
1014
+ "DEMO_VNOVA": {
1015
+ "description": "Text that describes an asset that comes from V-Nova.",
1016
+ "message": "[PROPER_NAME:V-Nova]"
1017
+ },
938
1018
  "DEMO_VOD": {
939
1019
  "description": "Text that describes an asset that is a VOD (Video On Delivery).",
940
1020
  "message": "[JARGON:VOD]"
package/demo/main.js CHANGED
@@ -12,6 +12,8 @@ goog.require('goog.asserts');
12
12
  goog.require('shakaDemo.CloseButton');
13
13
  goog.require('shakaDemo.MessageIds');
14
14
  goog.require('shakaDemo.Utils');
15
+ goog.require('shakaDemo.Visualizer');
16
+ goog.require('shakaDemo.VisualizerButton');
15
17
 
16
18
  /**
17
19
  * Shaka Player demo, main section.
@@ -80,6 +82,9 @@ shakaDemo.Main = class {
80
82
  // Override the icon for the MDL library's menu button.
81
83
  // eslint-disable-next-line no-restricted-syntax
82
84
  MaterialLayout.prototype.Constant_.MENU_ICON = 'settings';
85
+
86
+ /** @private {?shakaDemo.Visualizer} */
87
+ this.visualizer_ = null;
83
88
  }
84
89
 
85
90
  /**
@@ -183,7 +188,7 @@ shakaDemo.Main = class {
183
188
  this.support_ = await shaka.Player.probeSupport();
184
189
 
185
190
  this.video_ =
186
- /** @type {!HTMLVideoElement} */(document.getElementById('video'));
191
+ /** @type {!HTMLVideoElement} */ (document.getElementById('video'));
187
192
  this.video_.poster = shakaDemo.Main.mainPoster_;
188
193
 
189
194
  this.container_ = /** @type {!HTMLElement} */(
@@ -221,6 +226,22 @@ shakaDemo.Main = class {
221
226
  // Also fullscreen the container.
222
227
  this.container_.classList.add('no-input-sized');
223
228
  document.getElementById('video-bar').classList.add('no-input-sized');
229
+ } else {
230
+ goog.asserts.assert(this.player_, 'Player should exist by now.');
231
+
232
+ // Make the visualizer element.
233
+ const vCanvas = /** @type {!HTMLCanvasElement} */ (
234
+ document.getElementById('visualizer-canvas'));
235
+ const vDiv = /** @type {!HTMLElement} */ (
236
+ document.getElementById('visualizer-div'));
237
+ const vControlsDiv = /** @type {!HTMLElement} */ (
238
+ document.getElementById('visualizer-controls-div'));
239
+ const vScreenshotDiv = /** @type {!HTMLElement} */ (
240
+ document.getElementById('visualizer-screenshot-div'));
241
+ /** @private {?shakaDemo.Visualizer} */
242
+ this.visualizer_ = new shakaDemo.Visualizer(
243
+ vCanvas, vDiv, vScreenshotDiv, vControlsDiv, this.video_,
244
+ this.player_);
224
245
  }
225
246
 
226
247
  // The main page is loaded. Dispatch an event, so the various
@@ -337,6 +358,9 @@ shakaDemo.Main = class {
337
358
  if (!uiConfig.controlPanelElements.includes('close')) {
338
359
  uiConfig.controlPanelElements.push('close');
339
360
  }
361
+ if (!uiConfig.overflowMenuButtons.includes('visualizer')) {
362
+ uiConfig.overflowMenuButtons.push('visualizer');
363
+ }
340
364
  ui.configure(uiConfig);
341
365
  }
342
366
 
@@ -356,6 +380,8 @@ shakaDemo.Main = class {
356
380
  // Register custom controls to the UI.
357
381
  const closeFactory = new shakaDemo.CloseButton.Factory();
358
382
  shaka.ui.Controls.registerElement('close', closeFactory);
383
+ const visualizerFactory = new shakaDemo.VisualizerButton.Factory();
384
+ shaka.ui.OverflowMenu.registerElement('visualizer', visualizerFactory);
359
385
 
360
386
  // Configure UI.
361
387
  this.configureUI_();
@@ -1117,8 +1143,34 @@ shakaDemo.Main = class {
1117
1143
  return response.data;
1118
1144
  }
1119
1145
 
1146
+ /** @return {boolean} */
1147
+ getIsVisualizerActive() {
1148
+ if (this.visualizer_) {
1149
+ return this.visualizer_.active;
1150
+ }
1151
+ return false;
1152
+ }
1153
+
1154
+ /** @param {boolean} active */
1155
+ setIsVisualizerActive(active) {
1156
+ if (this.visualizer_) {
1157
+ const wasActive = this.visualizer_.active;
1158
+ this.visualizer_.active = active;
1159
+ if (wasActive != active) {
1160
+ if (active) {
1161
+ this.visualizer_.start();
1162
+ } else {
1163
+ this.visualizer_.stop();
1164
+ }
1165
+ }
1166
+ }
1167
+ }
1168
+
1120
1169
  /** Unload the currently-playing asset. */
1121
1170
  unload() {
1171
+ if (this.visualizer_) {
1172
+ this.visualizer_.stop();
1173
+ }
1122
1174
  this.selectedAsset = null;
1123
1175
  const videoBar = document.getElementById('video-bar');
1124
1176
  this.hideElement_(videoBar);
@@ -1299,6 +1351,10 @@ shakaDemo.Main = class {
1299
1351
  metadata.artist = asset.source;
1300
1352
  navigator.mediaSession.metadata = new MediaMetadata(metadata);
1301
1353
  }
1354
+
1355
+ if (this.visualizer_ && this.visualizer_.active) {
1356
+ this.visualizer_.start();
1357
+ }
1302
1358
  } catch (reason) {
1303
1359
  const error = /** @type {!shaka.util.Error} */ (reason);
1304
1360
  if (error.code == shaka.util.Error.Code.LOAD_INTERRUPTED) {
package/demo/search.js CHANGED
@@ -401,6 +401,8 @@ shakaDemo.Search = class {
401
401
  shakaDemo.MessageIds.AUDIO_ONLY_SEARCH);
402
402
  this.makeBooleanInput_(specialContainer, Feature.THUMBNAILS, FEATURE,
403
403
  shakaDemo.MessageIds.THUMBNAILS);
404
+ this.makeBooleanInput_(specialContainer, Feature.LCEVC, FEATURE,
405
+ shakaDemo.MessageIds.LCEVC);
404
406
 
405
407
  container.appendChild(this.resultsDiv_);
406
408
  }