@editframe/elements 0.17.6-beta.0 → 0.18.7-beta.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 (211) hide show
  1. package/dist/EF_FRAMEGEN.js +1 -1
  2. package/dist/elements/EFAudio.d.ts +21 -2
  3. package/dist/elements/EFAudio.js +41 -11
  4. package/dist/elements/EFImage.d.ts +1 -0
  5. package/dist/elements/EFImage.js +11 -3
  6. package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
  7. package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
  8. package/dist/elements/EFMedia/AssetMediaEngine.browsertest.d.ts +0 -0
  9. package/dist/elements/EFMedia/AssetMediaEngine.d.ts +45 -0
  10. package/dist/elements/EFMedia/AssetMediaEngine.js +135 -0
  11. package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
  12. package/dist/elements/EFMedia/BaseMediaEngine.js +115 -0
  13. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
  14. package/dist/elements/EFMedia/BufferedSeekingInput.js +179 -0
  15. package/dist/elements/EFMedia/JitMediaEngine.browsertest.d.ts +0 -0
  16. package/dist/elements/EFMedia/JitMediaEngine.d.ts +31 -0
  17. package/dist/elements/EFMedia/JitMediaEngine.js +81 -0
  18. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.d.ts +9 -0
  19. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +16 -0
  20. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +48 -0
  21. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +3 -0
  22. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +141 -0
  23. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.d.ts +9 -0
  24. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.d.ts +4 -0
  25. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +16 -0
  26. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.d.ts +9 -0
  27. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.d.ts +3 -0
  28. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +30 -0
  29. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.d.ts +0 -0
  30. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
  31. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +32 -0
  32. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
  33. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +28 -0
  34. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
  35. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +17 -0
  36. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
  37. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +107 -0
  38. package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
  39. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
  40. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
  41. package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
  42. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
  43. package/dist/elements/EFMedia/shared/PrecisionUtils.d.ts +28 -0
  44. package/dist/elements/EFMedia/shared/PrecisionUtils.js +29 -0
  45. package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
  46. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
  47. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
  48. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
  49. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
  50. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
  51. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
  52. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
  53. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
  54. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
  55. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
  56. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
  57. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
  58. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +34 -0
  59. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
  60. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
  61. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +28 -0
  62. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
  63. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
  64. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +17 -0
  65. package/dist/elements/EFMedia.browsertest.d.ts +1 -0
  66. package/dist/elements/EFMedia.d.ts +63 -111
  67. package/dist/elements/EFMedia.js +117 -1113
  68. package/dist/elements/EFTemporal.d.ts +1 -1
  69. package/dist/elements/EFTemporal.js +1 -1
  70. package/dist/elements/EFTimegroup.d.ts +11 -0
  71. package/dist/elements/EFTimegroup.js +83 -13
  72. package/dist/elements/EFVideo.d.ts +54 -32
  73. package/dist/elements/EFVideo.js +100 -207
  74. package/dist/elements/EFWaveform.js +2 -2
  75. package/dist/elements/SampleBuffer.d.ts +14 -0
  76. package/dist/elements/SampleBuffer.js +52 -0
  77. package/dist/getRenderInfo.js +2 -1
  78. package/dist/gui/ContextMixin.js +3 -2
  79. package/dist/gui/EFFilmstrip.d.ts +3 -3
  80. package/dist/gui/EFFilmstrip.js +1 -1
  81. package/dist/gui/EFFitScale.d.ts +2 -2
  82. package/dist/gui/TWMixin.js +1 -1
  83. package/dist/style.css +1 -1
  84. package/dist/transcoding/cache/CacheManager.d.ts +73 -0
  85. package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
  86. package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
  87. package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
  88. package/dist/transcoding/types/index.d.ts +242 -0
  89. package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
  90. package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
  91. package/dist/transcoding/utils/UrlGenerator.js +45 -0
  92. package/dist/transcoding/utils/constants.d.ts +27 -0
  93. package/dist/utils/LRUCache.d.ts +34 -0
  94. package/dist/utils/LRUCache.js +115 -0
  95. package/package.json +3 -3
  96. package/src/elements/EFAudio.browsertest.ts +189 -49
  97. package/src/elements/EFAudio.ts +59 -13
  98. package/src/elements/EFImage.browsertest.ts +42 -0
  99. package/src/elements/EFImage.ts +23 -3
  100. package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
  101. package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
  102. package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +100 -0
  103. package/src/elements/EFMedia/AssetMediaEngine.ts +255 -0
  104. package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
  105. package/src/elements/EFMedia/BaseMediaEngine.ts +219 -0
  106. package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +481 -0
  107. package/src/elements/EFMedia/BufferedSeekingInput.ts +324 -0
  108. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
  109. package/src/elements/EFMedia/JitMediaEngine.ts +166 -0
  110. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
  111. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
  112. package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +250 -0
  113. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
  114. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
  115. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
  116. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +43 -0
  117. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +199 -0
  118. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +64 -0
  119. package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +45 -0
  120. package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +24 -0
  121. package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +183 -0
  122. package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
  123. package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
  124. package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
  125. package/src/elements/EFMedia/shared/PrecisionUtils.ts +46 -0
  126. package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
  127. package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
  128. package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
  129. package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
  130. package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
  131. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
  132. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
  133. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
  134. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
  135. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
  136. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
  137. package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +68 -0
  138. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
  139. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +43 -0
  140. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
  141. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +24 -0
  142. package/src/elements/EFMedia.browsertest.ts +706 -273
  143. package/src/elements/EFMedia.ts +136 -1769
  144. package/src/elements/EFTemporal.ts +3 -4
  145. package/src/elements/EFTimegroup.browsertest.ts +6 -3
  146. package/src/elements/EFTimegroup.ts +147 -21
  147. package/src/elements/EFVideo.browsertest.ts +980 -169
  148. package/src/elements/EFVideo.ts +113 -458
  149. package/src/elements/EFWaveform.ts +1 -1
  150. package/src/elements/MediaController.ts +2 -12
  151. package/src/elements/SampleBuffer.ts +95 -0
  152. package/src/gui/ContextMixin.ts +3 -6
  153. package/src/transcoding/cache/CacheManager.ts +208 -0
  154. package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
  155. package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
  156. package/src/transcoding/types/index.ts +269 -0
  157. package/src/transcoding/utils/MediaUtils.ts +63 -0
  158. package/src/transcoding/utils/UrlGenerator.ts +68 -0
  159. package/src/transcoding/utils/constants.ts +36 -0
  160. package/src/utils/LRUCache.ts +153 -0
  161. package/test/EFVideo.framegen.browsertest.ts +39 -30
  162. package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/data.bin +0 -0
  163. package/test/__cache__/GET__api_v1_transcode_audio_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__32da3954ba60c96ad732020c65a08ebc/metadata.json +21 -0
  164. package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/data.bin +0 -0
  165. package/test/__cache__/GET__api_v1_transcode_audio_1_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__9ed2d25c675aa6bb6ff5b3ae23887c71/metadata.json +22 -0
  166. package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/data.bin +0 -0
  167. package/test/__cache__/GET__api_v1_transcode_audio_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__b0b2b07efcf607de8ee0f650328c32f7/metadata.json +21 -0
  168. package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/data.bin +0 -0
  169. package/test/__cache__/GET__api_v1_transcode_audio_2_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__d5a3309a2bf756dd6e304807eb402f56/metadata.json +22 -0
  170. package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/data.bin +0 -0
  171. package/test/__cache__/GET__api_v1_transcode_audio_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a75c2252b542e0c152c780e9a8d7b154/metadata.json +21 -0
  172. package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/data.bin +0 -0
  173. package/test/__cache__/GET__api_v1_transcode_audio_3_mp4_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4_bytes_0__773254bb671e3466fca8677139fb239e/metadata.json +22 -0
  174. package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/data.bin +0 -0
  175. package/test/__cache__/GET__api_v1_transcode_audio_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a64ff1cfb1b52cae14df4b5dfa1e222b/metadata.json +21 -0
  176. package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/data.bin +0 -0
  177. package/test/__cache__/GET__api_v1_transcode_audio_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__91e8a522f950809b9f09f4173113b4b0/metadata.json +21 -0
  178. package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/data.bin +0 -0
  179. package/test/__cache__/GET__api_v1_transcode_audio_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__e66d2c831d951e74ad0aeaa6489795d0/metadata.json +21 -0
  180. package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/data.bin +0 -0
  181. package/test/__cache__/GET__api_v1_transcode_high_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__26197f6f7c46cacb0a71134131c3f775/metadata.json +21 -0
  182. package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/data.bin +0 -0
  183. package/test/__cache__/GET__api_v1_transcode_high_2_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__4cb6774cd3650ccf59c8f8dc6678c0b9/metadata.json +21 -0
  184. package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/data.bin +0 -0
  185. package/test/__cache__/GET__api_v1_transcode_high_3_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0b3b2b1c8933f7fcf8a9ecaa88d58b41/metadata.json +21 -0
  186. package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/data.bin +0 -0
  187. package/test/__cache__/GET__api_v1_transcode_high_4_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a6fb05a22b18d850f7f2950bbcdbdeed/metadata.json +21 -0
  188. package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/data.bin +0 -0
  189. package/test/__cache__/GET__api_v1_transcode_high_5_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__a50058c7c3602e90879fe3428ed891f4/metadata.json +21 -0
  190. package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/data.bin +0 -0
  191. package/test/__cache__/GET__api_v1_transcode_high_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__0798c479b44aaeef850609a430f6e613/metadata.json +21 -0
  192. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
  193. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
  194. package/test/createJitTestClips.ts +320 -188
  195. package/test/recordReplayProxyPlugin.js +352 -0
  196. package/test/useAssetMSW.ts +1 -1
  197. package/test/useMSW.ts +35 -22
  198. package/types.json +1 -1
  199. package/dist/JitTranscodingClient.d.ts +0 -167
  200. package/dist/JitTranscodingClient.js +0 -373
  201. package/dist/ScrubTrackManager.d.ts +0 -96
  202. package/dist/ScrubTrackManager.js +0 -216
  203. package/dist/elements/printTaskStatus.js +0 -11
  204. package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
  205. package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
  206. /package/dist/{DecoderResetFrequency.test.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
  207. /package/dist/{DecoderResetRecovery.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
  208. /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
  209. /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts} +0 -0
  210. /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts} +0 -0
  211. /package/dist/{SegmentSwitchLoading.test.d.ts → elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts} +0 -0
@@ -1,14 +1,18 @@
1
- import { VideoAsset } from "@editframe/assets/EncodedAsset.js";
2
1
  import { Task } from "@lit/task";
3
2
  import debug from "debug";
4
3
  import { css, html, type PropertyValueMap } from "lit";
5
- import { customElement, state } from "lit/decorators.js";
4
+ import { customElement, property, state } from "lit/decorators.js";
6
5
  import { createRef, ref } from "lit/directives/ref.js";
6
+
7
7
  import { DelayedLoadingState } from "../DelayedLoadingState.js";
8
8
  import { TWMixin } from "../gui/TWMixin.js";
9
- import { type CacheStats, ScrubTrackManager } from "../ScrubTrackManager.js";
9
+ import { makeVideoBufferTask } from "./EFMedia/videoTasks/makeVideoBufferTask.ts";
10
+ import { makeVideoInitSegmentFetchTask } from "./EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts";
11
+ import { makeVideoInputTask } from "./EFMedia/videoTasks/makeVideoInputTask.ts";
12
+ import { makeVideoSeekTask } from "./EFMedia/videoTasks/makeVideoSeekTask.ts";
13
+ import { makeVideoSegmentFetchTask } from "./EFMedia/videoTasks/makeVideoSegmentFetchTask.ts";
14
+ import { makeVideoSegmentIdTask } from "./EFMedia/videoTasks/makeVideoSegmentIdTask.ts";
10
15
  import { EFMedia } from "./EFMedia.js";
11
- import { printTaskStatus } from "./printTaskStatus.ts";
12
16
 
13
17
  // EF_FRAMEGEN is a global instance created in EF_FRAMEGEN.ts
14
18
  declare global {
@@ -25,6 +29,16 @@ interface LoadingState {
25
29
 
26
30
  @customElement("ef-video")
27
31
  export class EFVideo extends TWMixin(EFMedia) {
32
+ static get observedAttributes() {
33
+ const parentAttributes = EFMedia.observedAttributes || [];
34
+ return [
35
+ ...parentAttributes,
36
+ "video-buffer-duration",
37
+ "max-video-buffer-fetches",
38
+ "enable-video-buffering",
39
+ ];
40
+ }
41
+
28
42
  static styles = [
29
43
  /**
30
44
  *
@@ -92,14 +106,33 @@ export class EFVideo extends TWMixin(EFMedia) {
92
106
  canvasRef = createRef<HTMLCanvasElement>();
93
107
 
94
108
  /**
95
- * Scrub track manager for fast timeline navigation
109
+ * Duration in milliseconds for video buffering ahead of current time
110
+ * @domAttribute "video-buffer-duration"
111
+ */
112
+ @property({ type: Number, attribute: "video-buffer-duration" })
113
+ videoBufferDurationMs = 60000; // 60 seconds
114
+
115
+ /**
116
+ * Maximum number of concurrent video segment fetches for buffering
117
+ * @domAttribute "max-video-buffer-fetches"
96
118
  */
97
- scrubTrackManager?: ScrubTrackManager;
119
+ @property({ type: Number, attribute: "max-video-buffer-fetches" })
120
+ maxVideoBufferFetches = 2;
98
121
 
99
122
  /**
100
- * Track last seek time for fast seeking detection
123
+ * Enable/disable video buffering system
124
+ * @domAttribute "enable-video-buffering"
101
125
  */
102
- private lastSeekTimeMs = 0;
126
+ @property({ type: Boolean, attribute: "enable-video-buffering" })
127
+ enableVideoBuffering = true;
128
+
129
+ // Video-specific tasks
130
+ videoSegmentIdTask = makeVideoSegmentIdTask(this);
131
+ videoInitSegmentFetchTask = makeVideoInitSegmentFetchTask(this);
132
+ videoSegmentFetchTask = makeVideoSegmentFetchTask(this);
133
+ videoInputTask = makeVideoInputTask(this);
134
+ videoSeekTask = makeVideoSeekTask(this);
135
+ videoBufferTask = makeVideoBufferTask(this);
103
136
 
104
137
  /**
105
138
  * Delayed loading state manager for user feedback
@@ -153,35 +186,14 @@ export class EFVideo extends TWMixin(EFMedia) {
153
186
  return this.canvasRef.value;
154
187
  }
155
188
 
156
- // The underlying video decoder MUST NOT be used concurrently.
157
- // If frames are fed in out of order, the decoder may crash.
158
- #decoderLock = false;
159
-
160
- // Track if decoder needs reset due to errors
161
- #decoderNeedsReset = false;
162
-
163
189
  frameTask = new Task(this, {
164
190
  args: () => [this.desiredSeekTimeMs] as const,
165
191
  onError: (error) => {
166
192
  console.error("frameTask error", error);
167
193
  },
194
+ onComplete: () => {},
168
195
  task: async ([_desiredSeekTimeMs], { signal }) => {
169
- await this.seekTask.taskComplete;
170
- if (signal.aborted) {
171
- return;
172
- }
173
- await this.fragmentIndexTask.taskComplete;
174
- if (signal.aborted) {
175
- return;
176
- }
177
- await this.mediaSegmentsTask.taskComplete;
178
- if (signal.aborted) {
179
- return;
180
- }
181
- await this.videoAssetTask.taskComplete;
182
- if (signal.aborted) {
183
- return;
184
- }
196
+ await this.videoSeekTask.taskComplete;
185
197
  await this.paintTask.taskComplete;
186
198
  if (signal.aborted) {
187
199
  return;
@@ -189,70 +201,10 @@ export class EFVideo extends TWMixin(EFMedia) {
189
201
  },
190
202
  });
191
203
 
192
- get frameTaskStatus() {
193
- return {
194
- desiredSeekTimeMs: this.desiredSeekTimeMs,
195
- fragmentIndexTask: printTaskStatus(this.fragmentIndexTask.status),
196
- seekTask: printTaskStatus(this.seekTask.status),
197
- mediaSegmentsTask: printTaskStatus(this.mediaSegmentsTask.status),
198
- assetSegmentLoader: printTaskStatus(this.assetSegmentLoader.status),
199
- assetSegmentKeysTask: printTaskStatus(this.assetSegmentKeysTask.status),
200
- assetInitSegmentsTask: printTaskStatus(this.assetInitSegmentsTask.status),
201
- videoAssetTask: printTaskStatus(this.videoAssetTask.status),
202
- paintTask: printTaskStatus(this.paintTask.status),
203
- frameTask: printTaskStatus(this.frameTask.status),
204
- };
205
- }
206
-
207
- #lastVideoAsset: any = null;
208
-
209
204
  protected updated(
210
205
  changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>,
211
206
  ): void {
212
207
  super.updated(changedProperties);
213
-
214
- const currentVideoAsset = this.videoAssetTask.value;
215
- if (currentVideoAsset !== this.#lastVideoAsset) {
216
- // Track video asset changes for reference, but don't reset decoder
217
- // Decoder resets should only happen due to actual decoder errors, not normal asset transitions
218
- this.#lastVideoAsset = currentVideoAsset;
219
- }
220
-
221
- // Initialize scrub track manager for JIT transcode mode
222
- this.initializeScrubTrackManager();
223
- }
224
-
225
- /**
226
- * Initialize scrub track manager if needed
227
- */
228
- private async initializeScrubTrackManager(): Promise<void> {
229
- const mode = this.effectiveMode;
230
-
231
- // Only initialize for JIT transcode mode with valid src
232
- if (mode === "jit-transcode" && this.src && !this.scrubTrackManager) {
233
- const jitClient = this.jitClientTask.value;
234
- if (jitClient) {
235
- try {
236
- this.scrubTrackManager = new ScrubTrackManager(this.src, jitClient, {
237
- onLoadingStateChange: (isLoading: boolean, message?: string) => {
238
- if (isLoading) {
239
- // Only show loading for user-visible operations (non-background)
240
- this.startDelayedLoading(
241
- "scrub-segment",
242
- message || "Loading scrub track...",
243
- );
244
- } else {
245
- this.clearDelayedLoading("scrub-segment");
246
- }
247
- },
248
- });
249
-
250
- await this.scrubTrackManager.initialize();
251
- } catch (error) {
252
- console.warn("Failed to initialize scrub track manager:", error);
253
- }
254
- }
255
- }
256
208
  }
257
209
 
258
210
  /**
@@ -288,107 +240,24 @@ export class EFVideo extends TWMixin(EFMedia) {
288
240
  };
289
241
  }
290
242
 
291
- videoAssetTask = new Task(this, {
292
- autoRun: true,
293
- args: () => [this.effectiveMode, this.mediaSegmentsTask.value] as const,
294
- onError: (error) => {
295
- console.error("videoAsset task error", error);
296
- },
297
- task: async ([mode, _files], { signal: _signal }) => {
298
- await this.mediaSegmentsTask.taskComplete;
299
- if (_signal.aborted) {
300
- return undefined;
301
- }
302
-
303
- await this.fragmentIndexTask.taskComplete;
304
- if (_signal.aborted) {
305
- return undefined;
306
- }
307
-
308
- // Get fresh values
309
- const files = this.mediaSegmentsTask.value;
310
- const fragmentIndex = this.fragmentIndexTask.value;
311
-
312
- if (!files) {
313
- log("trace: videoAsset task aborted - no files");
314
- throw new Error(
315
- `Video asset creation failed: No media segment files available. This indicates a problem with media segment loading for source: "${this.src}"`,
316
- );
317
- }
318
-
319
- const computedVideoTrackId = Object.values(fragmentIndex ?? {}).find(
320
- (track) => track.type === "video",
321
- )?.track;
322
-
323
- if (computedVideoTrackId === undefined) {
324
- log("trace: videoAsset task aborted - no video track");
325
- throw new Error(
326
- `Video asset creation failed: No video track found in media segments. Source may not contain video content: "${this.src}"`,
327
- );
328
- }
329
-
330
- const videoFile = files[computedVideoTrackId];
331
- if (!videoFile) {
332
- log("trace: videoAsset task aborted - no video file");
333
- throw new Error(
334
- `Video asset creation failed: Video file not available for track ${computedVideoTrackId}. Media segment loading may have failed for source: "${this.src}"`,
335
- );
336
- }
337
-
338
- // Cleanup existing asset
339
- const existingAsset = this.videoAssetTask.value;
340
- if (existingAsset) {
341
- for (const frame of existingAsset?.decodedFrames || []) {
342
- frame.close();
343
- }
344
- const decoder = existingAsset?.videoDecoder;
345
- if (decoder && decoder.state !== "closed") {
346
- decoder.close();
347
- }
348
- }
349
-
350
- if (_signal.aborted) {
351
- return undefined;
352
- }
353
-
354
- log("trace: creating video asset", { mode });
355
-
356
- // Get start time offset from fragment index (timing correction for FFmpeg processing)
357
- const videoTrackFragmentIndex = Object.values(fragmentIndex ?? {}).find(
358
- (track) => track.type === "video",
359
- );
360
- const startTimeOffsetMs = Number(
361
- (videoTrackFragmentIndex?.startTimeOffsetMs ?? 0).toFixed(5),
362
- );
363
-
364
- // Single branching point for creation method
365
- if (mode === "jit-transcode") {
366
- const result = await VideoAsset.createFromCompleteMP4(
367
- `jit-segment-${computedVideoTrackId}`,
368
- videoFile,
369
- { startTimeOffsetMs },
370
- );
371
- return result;
372
- }
373
- const result = await VideoAsset.createFromReadableStream(
374
- "video.mp4",
375
- videoFile.stream(),
376
- videoFile,
377
- { startTimeOffsetMs },
378
- );
379
- return result;
380
- },
381
- });
382
-
383
243
  paintTask = new Task(this, {
384
244
  args: () => [this.desiredSeekTimeMs] as const,
385
245
  onError: (error) => {
386
246
  console.error("paintTask error", error);
387
247
  },
248
+ onComplete: () => {},
388
249
  task: async ([_seekToMs], { signal }) => {
250
+ await this.videoSeekTask.taskComplete;
389
251
  // Check if we're in production rendering mode vs preview mode
390
252
  const isProductionRendering = this.isInProductionRenderingMode();
391
253
 
254
+ const sample = this.videoSeekTask.value;
255
+ if (sample) {
256
+ const videoFrame = sample.toVideoFrame();
257
+ this.displayFrame(videoFrame, _seekToMs);
258
+ videoFrame.close();
259
+ }
260
+
392
261
  // EF_FRAMEGEN-aware rendering mode detection
393
262
  if (!isProductionRendering) {
394
263
  // Preview mode: skip rendering during initialization to prevent artifacts
@@ -417,277 +286,9 @@ export class EFVideo extends TWMixin(EFMedia) {
417
286
  if (signal.aborted) {
418
287
  return;
419
288
  }
420
-
421
- // CRITICAL: For segment transitions, ensure we wait for the correct mediaSegmentsTask
422
- // This prevents using stale VideoAssets from previous segments
423
-
424
- await this.mediaSegmentsTask.taskComplete;
425
- if (signal.aborted) {
426
- return;
427
- }
428
-
429
- // CRITICAL: Always await fresh videoAsset just before using it
430
- // This prevents race conditions where old VideoAssets with closed decoders are used
431
- await this.videoAssetTask.taskComplete;
432
- if (signal.aborted) {
433
- return;
434
- }
435
-
436
- // Get fresh values after await - ensures we use current VideoAsset
437
- const videoAsset = this.videoAssetTask.value;
438
- const currentSeekToMs = this.desiredSeekTimeMs; // Use current seek time, not captured
439
-
440
- if (!videoAsset) {
441
- log("trace: paintTask aborted - no video asset");
442
- throw new Error(
443
- `Frame rendering failed: No video asset available. This may indicate a problem with video loading or an invalid source: "${this.src}"`,
444
- );
445
- }
446
-
447
- // Check if decoder needs reset due to previous errors
448
- if (this.#decoderNeedsReset) {
449
- try {
450
- // Reset the video decoder
451
- if (videoAsset?.videoDecoder) {
452
- videoAsset.configureDecoder();
453
- } else {
454
- console.warn("No video decoder available for reset");
455
- }
456
-
457
- // Clear the flag after successful reset
458
- this.#decoderNeedsReset = false;
459
- } catch (resetError) {
460
- console.error("reset error", resetError);
461
- // Keep the flag set if reset fails
462
- throw new Error(
463
- `Frame rendering failed: Unable to reset video decoder after previous error. Decoder state: ${resetError instanceof Error ? resetError.message : "Unknown error"}. Try refreshing the page or reloading the video.`,
464
- );
465
- }
466
- }
467
- if (signal.aborted) {
468
- return;
469
- }
470
-
471
- if (this.#decoderLock) {
472
- return;
473
- }
474
-
475
- try {
476
- this.#decoderLock = true;
477
-
478
- // Validate VideoAsset is still current and decoder is in valid state
479
- const currentVideoAsset = this.videoAssetTask.value;
480
- if (videoAsset !== currentVideoAsset) {
481
- return; // Skip render with stale videoAsset
482
- }
483
-
484
- // Check decoder state before using it
485
- const decoderState = videoAsset?.videoDecoder?.state;
486
- if (decoderState === "closed") {
487
- return; // Skip render with closed decoder
488
- }
489
-
490
- // Try scrub track first for JIT transcode mode
491
- if (this.effectiveMode === "jit-transcode" && this.scrubTrackManager) {
492
- const shouldUseScrub =
493
- this.scrubTrackManager.shouldUseScrubTrack(currentSeekToMs);
494
- const isFastSeeking = this.scrubTrackManager.isFastSeeking(
495
- this.lastSeekTimeMs,
496
- currentSeekToMs,
497
- );
498
-
499
- if (false || shouldUseScrub || isFastSeeking) {
500
- try {
501
- // Use delayed loading instead of immediate loading
502
- this.startDelayedLoading(
503
- "scrub-segment-load",
504
- "Loading scrub segment...",
505
- );
506
-
507
- const scrubFrame =
508
- await this.scrubTrackManager.getScrubFrame(currentSeekToMs);
509
-
510
- if (scrubFrame && this.canvasElement) {
511
- this.scrubTrackManager.recordCacheMiss();
512
- this.lastSeekTimeMs = currentSeekToMs;
513
-
514
- // Clear loading and display scrub frame
515
- this.clearDelayedLoading("scrub-segment-load");
516
- return this.displayFrame(scrubFrame, currentSeekToMs);
517
- }
518
-
519
- // Scrub frame was null/failed - fall back to normal video
520
- console.warn(
521
- "Scrub track returned null frame, falling back to normal video",
522
- );
523
- this.clearDelayedLoading("scrub-segment-load");
524
- this.startDelayedLoading(
525
- "video-segment-fallback",
526
- "Loading high quality video...",
527
- );
528
- } catch (error) {
529
- this.clearDelayedLoading("scrub-segment-load");
530
- console.warn(
531
- "Scrub track failed, falling back to normal video:",
532
- error,
533
- );
534
-
535
- // Show loading for normal video fallback
536
- this.startDelayedLoading(
537
- "video-segment-fallback",
538
- "Loading high quality video...",
539
- );
540
- }
541
- } else {
542
- // Cache hit for normal video - scrub track manager exists, record the hit
543
- this.scrubTrackManager?.recordCacheHit();
544
- }
545
- }
546
-
547
- // Normal video rendering path (for all cases where scrub track isn't used)
548
- // Check if we need to show loading for normal video operations
549
- const shouldShowLoading =
550
- !this.delayedLoadingState.isLoading &&
551
- (this.effectiveMode !== "asset" || !videoAsset);
552
-
553
- if (shouldShowLoading) {
554
- this.startDelayedLoading("video-segment", "Loading video segment...");
555
- }
556
-
557
- // Render normal video - pass fresh VideoAsset reference
558
- this.lastSeekTimeMs = currentSeekToMs;
559
- const result = await this.renderNormalVideo(
560
- videoAsset,
561
- currentSeekToMs,
562
- );
563
-
564
- // Clear loading state after normal video renders
565
- this.clearDelayedLoading("video-segment");
566
- this.clearDelayedLoading("video-segment-fallback");
567
-
568
- return result;
569
- } catch (error) {
570
- // Clear all loading states on error
571
- this.clearDelayedLoading("scrub-segment-load");
572
- this.clearDelayedLoading("video-segment");
573
- this.clearDelayedLoading("video-segment-fallback");
574
-
575
- // Handle errors with proper error propagation
576
- if (error instanceof Error) {
577
- if (
578
- error.name === "DataError" &&
579
- error.message.includes("key frame is required")
580
- ) {
581
- console.warn(
582
- "Decoder reset during VideoAsset due to key frame requirement",
583
- );
584
- this.#decoderNeedsReset = true;
585
-
586
- if (this.effectiveMode === "jit-transcode") {
587
- this.requestUpdate();
588
- }
589
- throw error;
590
- }
591
- if (error.name === "AbortError") {
592
- // AbortError is expected behavior when tasks are cancelled
593
- throw new Error(
594
- "Frame rendering cancelled: Operation was aborted, likely due to a new seek request or component unmounting.",
595
- );
596
- }
597
- if (
598
- error.message.includes("VideoAsset decoder closed") ||
599
- error.message.includes("recreation in progress")
600
- ) {
601
- // This is now expected behavior during VideoAsset transitions - don't treat as error
602
- return; // Gracefully abort instead of throwing
603
- }
604
- if (
605
- error.name === "InvalidStateError" &&
606
- error.message.includes("closed codec")
607
- ) {
608
- // Expected during VideoAsset recreation - gracefully abort
609
- return; // Gracefully abort instead of throwing
610
- }
611
- console.warn("Decoder reset during VideoAsset recreation", error);
612
- this.#decoderNeedsReset = true;
613
- throw error;
614
- }
615
-
616
- // For non-Error objects, still provide descriptive error
617
- throw new Error(
618
- `Frame rendering failed: Unknown error during video rendering at ${currentSeekToMs}ms. Error: ${String(error)}`,
619
- );
620
- } finally {
621
- this.#decoderLock = false;
622
- }
623
289
  },
624
290
  });
625
291
 
626
- /**
627
- * Render normal video using existing logic
628
- */
629
- private async renderNormalVideo(
630
- videoAsset: VideoAsset,
631
- seekToMs: number,
632
- ): Promise<number> {
633
- let targetSeekTimeSeconds = seekToMs / 1000;
634
-
635
- try {
636
- // Validate VideoAsset is still current before seeking
637
- const currentVideoAsset = this.videoAssetTask.value;
638
- if (videoAsset !== currentVideoAsset) {
639
- throw new Error(
640
- "VideoAsset decoder closed during seek - recreation in progress",
641
- );
642
- }
643
-
644
- // Check decoder state immediately before seeking
645
- const decoderState = videoAsset?.videoDecoder?.state;
646
- if (decoderState === "closed") {
647
- throw new Error(
648
- "VideoAsset decoder closed during seek - recreation in progress",
649
- );
650
- }
651
- if (this.effectiveMode === "jit-transcode") {
652
- targetSeekTimeSeconds %= 2;
653
- }
654
-
655
- const frame = await videoAsset.seekToTime(targetSeekTimeSeconds);
656
-
657
- if (frame) {
658
- // Final validation that VideoAsset is still current before displaying
659
- const finalVideoAsset = this.videoAssetTask.value;
660
- if (videoAsset !== finalVideoAsset) {
661
- frame.close(); // Clean up the frame
662
- throw new Error(
663
- "VideoAsset decoder closed during seek - recreation in progress",
664
- );
665
- }
666
-
667
- // Read fresh time right before displaying - final safeguard against stale values
668
- const finalSeekToMs = this.desiredSeekTimeMs;
669
- return this.displayFrame(frame, finalSeekToMs);
670
- }
671
-
672
- log("trace: no frame returned from seekToTime");
673
- throw new Error(
674
- `Frame rendering failed: No frame available at time ${seekToMs}ms (${targetSeekTimeSeconds}s). This may indicate seeking beyond video duration, corrupted video data, or an incompatible video format.`,
675
- );
676
- } catch (error) {
677
- if (
678
- error instanceof Error &&
679
- (error.message.includes("VideoAsset decoder closed") ||
680
- error.message.includes("recreation in progress"))
681
- ) {
682
- // This is the expected narrow timing window race condition during VideoAsset transitions
683
- throw error; // Re-throw to let paintTask handle it gracefully
684
- }
685
-
686
- // Re-throw other unexpected errors
687
- throw error;
688
- }
689
- }
690
-
691
292
  /**
692
293
  * Display a video frame on the canvas
693
294
  */
@@ -729,7 +330,7 @@ export class EFVideo extends TWMixin(EFMedia) {
729
330
  );
730
331
  }
731
332
 
732
- log("trace: drawing frame to canvas");
333
+ log("trace: drawing frame to canvas", frame.timestamp / 1000);
733
334
  ctx.drawImage(
734
335
  frame,
735
336
  0,
@@ -785,11 +386,68 @@ export class EFVideo extends TWMixin(EFMedia) {
785
386
  return currentTime >= renderStartTime;
786
387
  }
787
388
 
389
+ // Getter properties for backward compatibility with tests
390
+ /**
391
+ * Effective mode - always returns "asset" for EFVideo
392
+ */
393
+ get effectiveMode(): string {
394
+ return "asset";
395
+ }
396
+
397
+ /**
398
+ * Legacy getter for asset index loader (maps to mediaEngine task)
399
+ */
400
+ get assetIndexLoader() {
401
+ return this.mediaEngineTask;
402
+ }
403
+
404
+ /**
405
+ * Legacy getter for fragment index task (maps to videoSegmentIdTask)
406
+ */
407
+ get fragmentIndexTask() {
408
+ return this.videoSegmentIdTask;
409
+ }
410
+
411
+ /**
412
+ * Legacy getter for seek task (maps to videoSeekTask)
413
+ */
414
+ get seekTask() {
415
+ return this.videoSeekTask;
416
+ }
417
+
418
+ /**
419
+ * Legacy getter for media segments task (maps to videoSegmentFetchTask)
420
+ */
421
+ get mediaSegmentsTask() {
422
+ return this.videoSegmentFetchTask;
423
+ }
424
+
425
+ /**
426
+ * Legacy getter for asset segment keys task (maps to videoSegmentIdTask)
427
+ */
428
+ get assetSegmentKeysTask() {
429
+ return this.videoSegmentIdTask;
430
+ }
431
+
788
432
  /**
789
- * Get scrub track performance statistics
433
+ * Legacy getter for asset init segments task (maps to videoInitSegmentFetchTask)
790
434
  */
791
- getScrubTrackStats(): CacheStats | null {
792
- return this.scrubTrackManager?.getCacheStats() || null;
435
+ get assetInitSegmentsTask() {
436
+ return this.videoInitSegmentFetchTask;
437
+ }
438
+
439
+ /**
440
+ * Legacy getter for asset segment loader (maps to videoSegmentFetchTask)
441
+ */
442
+ get assetSegmentLoader() {
443
+ return this.videoSegmentFetchTask;
444
+ }
445
+
446
+ /**
447
+ * Legacy getter for video asset task (maps to videoBufferTask)
448
+ */
449
+ get videoAssetTask() {
450
+ return this.videoBufferTask;
793
451
  }
794
452
 
795
453
  /**
@@ -798,9 +456,6 @@ export class EFVideo extends TWMixin(EFMedia) {
798
456
  disconnectedCallback(): void {
799
457
  super.disconnectedCallback();
800
458
 
801
- // Clean up scrub track manager
802
- this.scrubTrackManager?.cleanup();
803
-
804
459
  // Clean up delayed loading state
805
460
  this.delayedLoadingState.clearAllLoading();
806
461
  }
@@ -16,8 +16,8 @@ import { TargetController } from "./TargetController.ts";
16
16
  export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
17
17
  static styles = css`
18
18
  :host {
19
- display: block;
20
19
  all: inherit;
20
+ display: block;
21
21
  position: relative;
22
22
  }
23
23