@editframe/elements 0.17.6-beta.0 → 0.18.3-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 (218) hide show
  1. package/dist/EF_FRAMEGEN.js +1 -1
  2. package/dist/ScrubTrackManager.d.ts +2 -2
  3. package/dist/elements/EFAudio.d.ts +21 -2
  4. package/dist/elements/EFAudio.js +41 -11
  5. package/dist/elements/EFImage.d.ts +1 -0
  6. package/dist/elements/EFImage.js +11 -3
  7. package/dist/elements/EFMedia/AssetIdMediaEngine.d.ts +18 -0
  8. package/dist/elements/EFMedia/AssetIdMediaEngine.js +41 -0
  9. package/dist/elements/EFMedia/AssetMediaEngine.d.ts +47 -0
  10. package/dist/elements/EFMedia/AssetMediaEngine.js +116 -0
  11. package/dist/elements/EFMedia/BaseMediaEngine.d.ts +55 -0
  12. package/dist/elements/EFMedia/BaseMediaEngine.js +96 -0
  13. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +43 -0
  14. package/dist/elements/EFMedia/BufferedSeekingInput.js +159 -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 +62 -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 +138 -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 +22 -0
  29. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.d.ts +7 -0
  30. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +24 -0
  31. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.d.ts +4 -0
  32. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +18 -0
  33. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.d.ts +4 -0
  34. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +16 -0
  35. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +3 -0
  36. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +104 -0
  37. package/dist/elements/EFMedia/services/AudioElementFactory.d.ts +22 -0
  38. package/dist/elements/EFMedia/services/AudioElementFactory.js +72 -0
  39. package/dist/elements/EFMedia/services/MediaSourceService.browsertest.d.ts +1 -0
  40. package/dist/elements/EFMedia/services/MediaSourceService.d.ts +47 -0
  41. package/dist/elements/EFMedia/services/MediaSourceService.js +73 -0
  42. package/dist/elements/EFMedia/shared/AudioSpanUtils.d.ts +7 -0
  43. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +54 -0
  44. package/dist/elements/EFMedia/shared/BufferUtils.d.ts +70 -0
  45. package/dist/elements/EFMedia/shared/BufferUtils.js +89 -0
  46. package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +23 -0
  47. package/dist/elements/EFMedia/shared/RenditionHelpers.browsertest.d.ts +1 -0
  48. package/dist/elements/EFMedia/shared/RenditionHelpers.d.ts +19 -0
  49. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts +1 -0
  50. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.d.ts +18 -0
  51. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +60 -0
  52. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts +1 -0
  53. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +9 -0
  54. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +16 -0
  55. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +46 -0
  56. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +9 -0
  57. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.d.ts +4 -0
  58. package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +16 -0
  59. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +9 -0
  60. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.d.ts +3 -0
  61. package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +27 -0
  62. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +7 -0
  63. package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +25 -0
  64. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +9 -0
  65. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +4 -0
  66. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +18 -0
  67. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +9 -0
  68. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +4 -0
  69. package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.js +16 -0
  70. package/dist/elements/EFMedia.browsertest.d.ts +1 -0
  71. package/dist/elements/EFMedia.d.ts +75 -111
  72. package/dist/elements/EFMedia.js +141 -1111
  73. package/dist/elements/EFTemporal.d.ts +1 -1
  74. package/dist/elements/EFTemporal.js +1 -1
  75. package/dist/elements/EFTimegroup.d.ts +11 -0
  76. package/dist/elements/EFTimegroup.js +88 -13
  77. package/dist/elements/EFVideo.d.ts +60 -29
  78. package/dist/elements/EFVideo.js +103 -203
  79. package/dist/elements/EFWaveform.js +2 -2
  80. package/dist/elements/SampleBuffer.d.ts +14 -0
  81. package/dist/elements/SampleBuffer.js +52 -0
  82. package/dist/getRenderInfo.d.ts +2 -2
  83. package/dist/getRenderInfo.js +2 -1
  84. package/dist/gui/ContextMixin.js +17 -70
  85. package/dist/gui/EFFilmstrip.d.ts +3 -3
  86. package/dist/gui/EFFilmstrip.js +1 -1
  87. package/dist/gui/EFFitScale.d.ts +2 -2
  88. package/dist/gui/TWMixin.js +1 -1
  89. package/dist/gui/services/ElementConnectionManager.browsertest.d.ts +1 -0
  90. package/dist/gui/services/ElementConnectionManager.d.ts +59 -0
  91. package/dist/gui/services/ElementConnectionManager.js +128 -0
  92. package/dist/gui/services/PlaybackController.browsertest.d.ts +1 -0
  93. package/dist/gui/services/PlaybackController.d.ts +103 -0
  94. package/dist/gui/services/PlaybackController.js +290 -0
  95. package/dist/services/MediaSourceManager.d.ts +62 -0
  96. package/dist/services/MediaSourceManager.js +211 -0
  97. package/dist/style.css +1 -1
  98. package/dist/transcoding/cache/CacheManager.d.ts +73 -0
  99. package/dist/transcoding/cache/RequestDeduplicator.d.ts +29 -0
  100. package/dist/transcoding/cache/RequestDeduplicator.js +53 -0
  101. package/dist/transcoding/cache/RequestDeduplicator.test.d.ts +1 -0
  102. package/dist/transcoding/types/index.d.ts +242 -0
  103. package/dist/transcoding/utils/MediaUtils.d.ts +9 -0
  104. package/dist/transcoding/utils/UrlGenerator.d.ts +26 -0
  105. package/dist/transcoding/utils/UrlGenerator.js +45 -0
  106. package/dist/transcoding/utils/constants.d.ts +27 -0
  107. package/dist/utils/LRUCache.d.ts +34 -0
  108. package/dist/utils/LRUCache.js +115 -0
  109. package/package.json +3 -2
  110. package/src/elements/EFAudio.browsertest.ts +183 -43
  111. package/src/elements/EFAudio.ts +59 -13
  112. package/src/elements/EFImage.browsertest.ts +42 -0
  113. package/src/elements/EFImage.ts +23 -3
  114. package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +222 -0
  115. package/src/elements/EFMedia/AssetIdMediaEngine.ts +70 -0
  116. package/src/elements/EFMedia/AssetMediaEngine.ts +210 -0
  117. package/src/elements/EFMedia/BaseMediaEngine.test.ts +164 -0
  118. package/src/elements/EFMedia/BaseMediaEngine.ts +170 -0
  119. package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +400 -0
  120. package/src/elements/EFMedia/BufferedSeekingInput.ts +267 -0
  121. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +165 -0
  122. package/src/elements/EFMedia/JitMediaEngine.ts +110 -0
  123. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +554 -0
  124. package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +81 -0
  125. package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +241 -0
  126. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +59 -0
  127. package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +23 -0
  128. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +55 -0
  129. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +35 -0
  130. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +42 -0
  131. package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +34 -0
  132. package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +23 -0
  133. package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +174 -0
  134. package/src/elements/EFMedia/services/AudioElementFactory.browsertest.ts +325 -0
  135. package/src/elements/EFMedia/services/AudioElementFactory.ts +119 -0
  136. package/src/elements/EFMedia/services/MediaSourceService.browsertest.ts +257 -0
  137. package/src/elements/EFMedia/services/MediaSourceService.ts +102 -0
  138. package/src/elements/EFMedia/shared/AudioSpanUtils.ts +128 -0
  139. package/src/elements/EFMedia/shared/BufferUtils.ts +310 -0
  140. package/src/elements/EFMedia/shared/MediaTaskUtils.ts +44 -0
  141. package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +247 -0
  142. package/src/elements/EFMedia/shared/RenditionHelpers.ts +79 -0
  143. package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +128 -0
  144. package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +233 -0
  145. package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +89 -0
  146. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +555 -0
  147. package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +79 -0
  148. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +59 -0
  149. package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts +23 -0
  150. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +55 -0
  151. package/src/elements/EFMedia/videoTasks/makeVideoInputTask.ts +45 -0
  152. package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +44 -0
  153. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +57 -0
  154. package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +32 -0
  155. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +56 -0
  156. package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.ts +23 -0
  157. package/src/elements/EFMedia.browsertest.ts +658 -265
  158. package/src/elements/EFMedia.ts +173 -1763
  159. package/src/elements/EFTemporal.ts +3 -4
  160. package/src/elements/EFTimegroup.browsertest.ts +6 -3
  161. package/src/elements/EFTimegroup.ts +152 -21
  162. package/src/elements/EFVideo.browsertest.ts +115 -37
  163. package/src/elements/EFVideo.ts +123 -452
  164. package/src/elements/EFWaveform.ts +1 -1
  165. package/src/elements/MediaController.ts +2 -12
  166. package/src/elements/SampleBuffer.ts +97 -0
  167. package/src/gui/ContextMixin.ts +23 -104
  168. package/src/gui/services/ElementConnectionManager.browsertest.ts +263 -0
  169. package/src/gui/services/ElementConnectionManager.ts +224 -0
  170. package/src/gui/services/PlaybackController.browsertest.ts +437 -0
  171. package/src/gui/services/PlaybackController.ts +521 -0
  172. package/src/services/MediaSourceManager.ts +333 -0
  173. package/src/transcoding/cache/CacheManager.ts +208 -0
  174. package/src/transcoding/cache/RequestDeduplicator.test.ts +170 -0
  175. package/src/transcoding/cache/RequestDeduplicator.ts +65 -0
  176. package/src/transcoding/types/index.ts +265 -0
  177. package/src/transcoding/utils/MediaUtils.ts +63 -0
  178. package/src/transcoding/utils/UrlGenerator.ts +68 -0
  179. package/src/transcoding/utils/constants.ts +36 -0
  180. package/src/utils/LRUCache.ts +153 -0
  181. package/test/EFVideo.framegen.browsertest.ts +38 -29
  182. 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
  183. 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
  184. 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
  185. 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
  186. 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
  187. 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
  188. 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
  189. 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
  190. 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
  191. 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
  192. 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
  193. 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
  194. 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
  195. 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
  196. 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
  197. 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
  198. 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
  199. 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
  200. 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
  201. 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
  202. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/data.bin +1 -0
  203. package/test/__cache__/GET__api_v1_transcode_manifest_json_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__3be92a0437de726b431ed5af2369158a/metadata.json +19 -0
  204. package/test/createJitTestClips.ts +320 -188
  205. package/test/recordReplayProxyPlugin.js +302 -0
  206. package/test/useAssetMSW.ts +1 -1
  207. package/test/useMSW.ts +35 -22
  208. package/types.json +1 -1
  209. package/dist/JitTranscodingClient.d.ts +0 -167
  210. package/dist/JitTranscodingClient.js +0 -373
  211. package/dist/ScrubTrackManager.js +0 -216
  212. package/dist/elements/printTaskStatus.js +0 -11
  213. package/src/elements/__screenshots__/EFMedia.browsertest.ts/EFMedia-JIT-audio-playback-audioBufferTask-should-work-in-JIT-mode-without-URL-errors-1.png +0 -0
  214. package/test/EFVideo.frame-tasks.browsertest.ts +0 -524
  215. /package/dist/{JitTranscodingClient.browsertest.d.ts → elements/EFMedia/AssetIdMediaEngine.test.d.ts} +0 -0
  216. /package/dist/{JitTranscodingClient.test.d.ts → elements/EFMedia/BaseMediaEngine.test.d.ts} +0 -0
  217. /package/dist/{ScrubTrackIntegration.test.d.ts → elements/EFMedia/BufferedSeekingInput.browsertest.d.ts} +0 -0
  218. /package/dist/{SegmentSwitchLoading.test.d.ts → elements/EFMedia/services/AudioElementFactory.browsertest.d.ts} +0 -0
@@ -1,524 +0,0 @@
1
- import { TaskStatus } from "@lit/task";
2
- import { html, render } from "lit";
3
- import { assert, beforeEach, describe, expect, test } from "vitest";
4
- import "../src/elements/EFVideo.js";
5
- import "../src/elements/EFTimegroup.js";
6
- import type { EFTimegroup } from "../src/elements/EFTimegroup.js";
7
- import type { EFVideo } from "../src/elements/EFVideo.js";
8
- import { assetMSWHandlers } from "./useAssetMSW.js";
9
- import { useMSW } from "./useMSW.ts";
10
-
11
- /**
12
- * Test suite for robust frame task chain functionality.
13
- * Validates that frame tasks either succeed with pixels or fail with descriptive errors.
14
- */
15
- describe("EFVideo Frame Tasks", () => {
16
- const worker = useMSW();
17
-
18
- beforeEach(() => {
19
- document.body.innerHTML = "";
20
-
21
- // Set up centralized MSW handlers to proxy requests to test assets
22
- worker.use(...assetMSWHandlers);
23
- });
24
-
25
- test("should properly track frame tasks during initial render", async () => {
26
- const container = document.createElement("div");
27
- render(
28
- html`<ef-workbench>
29
- <ef-timegroup mode="contain" style="width: 100px; height: 100px;">
30
- <ef-video
31
- src="/test-assets/media/bars-n-tone2.mp4"
32
- mode="asset"
33
- ></ef-video>
34
- </ef-timegroup>
35
- </ef-workbench>`,
36
- container,
37
- );
38
- document.body.appendChild(container);
39
-
40
- const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
41
- const video = container.querySelector("ef-video") as EFVideo;
42
-
43
- await video.updateComplete;
44
-
45
- // Verify task dependencies are properly set up
46
- expect(video.fragmentIndexTask).toBeDefined();
47
- expect(video.mediaSegmentsTask).toBeDefined();
48
- expect(video.seekTask).toBeDefined();
49
- expect(video.videoAssetTask).toBeDefined();
50
- expect(video.paintTask).toBeDefined();
51
-
52
- timegroup.currentTimeMs = 1000;
53
- await timegroup.updateComplete;
54
-
55
- // Check if we can successfully render when avoiding concurrency conflicts
56
- await new Promise((resolve) => setTimeout(resolve, 200));
57
-
58
- try {
59
- await video.paintTask.run();
60
-
61
- // Verify frame was actually rendered OR we get proper error
62
- const canvas = video.canvasRef.value;
63
- assert.ok(canvas, "Canvas should exist");
64
-
65
- const ctx = canvas.getContext("2d");
66
- assert.ok(ctx, "Canvas context should exist");
67
-
68
- // Either we have pixels OR we expect the video system is working correctly
69
- // (based on seeing DECODED FRAME traces in test output)
70
- expect(canvas.width).toBeGreaterThan(0);
71
- expect(canvas.height).toBeGreaterThan(0);
72
- } catch (error) {
73
- // This is expected when decoder lock prevents concurrent access
74
- const errorMessage =
75
- error instanceof Error ? error.message : String(error);
76
-
77
- if (errorMessage.includes("decoder is currently in use")) {
78
- // Verify error message is descriptive and actionable
79
- expect(errorMessage).toContain("Frame rendering failed");
80
- expect(errorMessage).toContain("decoder is currently in use");
81
- expect(errorMessage).toContain("concurrency issue");
82
- } else {
83
- throw error;
84
- }
85
- }
86
- });
87
-
88
- test("should validate task dependency chain completion order", async () => {
89
- const container = document.createElement("div");
90
- render(
91
- html`<ef-workbench>
92
- <ef-timegroup mode="contain" style="width: 100px; height: 100px;">
93
- <ef-video
94
- src="/test-assets/media/bars-n-tone2.mp4"
95
- mode="asset"
96
- ></ef-video>
97
- </ef-timegroup>
98
- </ef-workbench>`,
99
- container,
100
- );
101
- document.body.appendChild(container);
102
-
103
- const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
104
- const video = container.querySelector("ef-video") as EFVideo;
105
-
106
- await video.updateComplete;
107
-
108
- // Track task completion order
109
- const completionOrder: string[] = [];
110
- const taskMap = {
111
- assetIndexLoader: video.assetIndexLoader,
112
- fragmentIndexTask: video.fragmentIndexTask,
113
- mediaSegmentsTask: video.mediaSegmentsTask,
114
- seekTask: video.seekTask,
115
- videoAssetTask: video.videoAssetTask,
116
- paintTask: video.paintTask,
117
- frameTask: video.frameTask,
118
- };
119
-
120
- for (const [name, task] of Object.entries(taskMap)) {
121
- task.taskComplete
122
- .then(() => {
123
- completionOrder.push(name);
124
- })
125
- .catch(() => {
126
- // Tasks may fail due to concurrency, but still track completion
127
- completionOrder.push(name);
128
- });
129
- }
130
-
131
- timegroup.currentTimeMs = 1000;
132
- await timegroup.updateComplete;
133
-
134
- // Wait for tasks with error handling
135
- await Promise.allSettled(
136
- Object.values(taskMap).map((task) => task.taskComplete),
137
- );
138
-
139
- // Validate dependency order constraints if tasks completed
140
- if (completionOrder.length >= 4) {
141
- const getIndex = (taskName: string) => completionOrder.indexOf(taskName);
142
-
143
- // Only test order relationships for tasks that actually completed
144
- if (
145
- getIndex("assetIndexLoader") >= 0 &&
146
- getIndex("fragmentIndexTask") >= 0
147
- ) {
148
- expect(getIndex("assetIndexLoader")).toBeLessThan(
149
- getIndex("fragmentIndexTask"),
150
- );
151
- }
152
- if (getIndex("fragmentIndexTask") >= 0 && getIndex("seekTask") >= 0) {
153
- expect(getIndex("fragmentIndexTask")).toBeLessThan(
154
- getIndex("seekTask"),
155
- );
156
- }
157
- if (getIndex("mediaSegmentsTask") >= 0 && getIndex("seekTask") >= 0) {
158
- expect(getIndex("mediaSegmentsTask")).toBeLessThan(
159
- getIndex("seekTask"),
160
- );
161
- }
162
- }
163
-
164
- // Verify prerequisite tasks at least started properly
165
- expect(video.fragmentIndexTask.status).toBeGreaterThanOrEqual(
166
- TaskStatus.PENDING,
167
- );
168
- expect(video.mediaSegmentsTask.status).toBeGreaterThanOrEqual(
169
- TaskStatus.PENDING,
170
- );
171
- expect(video.videoAssetTask.status).toBeGreaterThanOrEqual(
172
- TaskStatus.PENDING,
173
- );
174
- });
175
-
176
- test("should throw descriptive errors instead of silent failures", async () => {
177
- const container = document.createElement("div");
178
- render(
179
- html`<ef-workbench>
180
- <ef-timegroup mode="contain" style="width: 100px; height: 100px;">
181
- <ef-video
182
- src="/test-assets/media/bars-n-tone2.mp4"
183
- mode="asset"
184
- ></ef-video>
185
- </ef-timegroup>
186
- </ef-workbench>`,
187
- container,
188
- );
189
- document.body.appendChild(container);
190
-
191
- const video = container.querySelector("ef-video") as EFVideo;
192
- await video.updateComplete;
193
-
194
- // Wait for video asset to be available
195
- await new Promise((resolve) => setTimeout(resolve, 500));
196
-
197
- // Test case 1: Missing video asset should throw descriptive error
198
- const originalVideoAssetTask = video.videoAssetTask;
199
- Object.defineProperty(video, "videoAssetTask", {
200
- get: () => ({
201
- ...originalVideoAssetTask,
202
- value: null,
203
- taskComplete: Promise.resolve(),
204
- }),
205
- configurable: true,
206
- });
207
-
208
- try {
209
- await video.paintTask.run();
210
- // If we get here without error, that's actually OK - it means the error checking
211
- // prevented the operation rather than failing silently
212
- expect(true).toBe(true); // Test passes - no silent failure
213
- } catch (error) {
214
- // Good - we got an error instead of silent failure
215
- expect(error.message).toBeDefined();
216
- expect(typeof error.message).toBe("string");
217
- }
218
-
219
- // Restore original
220
- Object.defineProperty(video, "videoAssetTask", {
221
- get: () => originalVideoAssetTask,
222
- configurable: true,
223
- });
224
-
225
- // Test case 2: Canvas context error should throw descriptive error
226
- const canvas = video.canvasRef.value;
227
- if (canvas) {
228
- const originalGetContext = canvas.getContext;
229
- canvas.getContext = () => null;
230
-
231
- try {
232
- await video.paintTask.run();
233
- // If we get here, that's OK - means error was prevented
234
- expect(true).toBe(true);
235
- } catch (error) {
236
- // Good - we got an error instead of silent failure
237
- expect(error.message).toBeDefined();
238
- expect(typeof error.message).toBe("string");
239
- }
240
-
241
- canvas.getContext = originalGetContext;
242
- }
243
- });
244
-
245
- test("should handle concurrent paintTask execution properly", async () => {
246
- const container = document.createElement("div");
247
- render(
248
- html`<ef-workbench>
249
- <ef-timegroup mode="contain" style="width: 100px; height: 100px;">
250
- <ef-video
251
- src="/test-assets/media/bars-n-tone2.mp4"
252
- mode="asset"
253
- ></ef-video>
254
- </ef-timegroup>
255
- </ef-workbench>`,
256
- container,
257
- );
258
- document.body.appendChild(container);
259
-
260
- const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
261
- const video = container.querySelector("ef-video") as EFVideo;
262
-
263
- await video.updateComplete;
264
-
265
- // Test case 1: Trigger multiple paint operations simultaneously
266
- const times = [500, 1000, 1500, 2000];
267
- const paintPromises: Promise<any>[] = [];
268
-
269
- for (const time of times) {
270
- timegroup.currentTimeMs = time;
271
- await timegroup.updateComplete;
272
-
273
- paintPromises.push(
274
- video.paintTask.run().catch((error) => {
275
- return { error, time };
276
- }),
277
- );
278
- }
279
-
280
- const results = await Promise.allSettled(paintPromises);
281
-
282
- let successCount = 0;
283
- let failureCount = 0;
284
- let totalAttempts = 0;
285
-
286
- for (let i = 0; i < results.length; i++) {
287
- const result = results[i];
288
- totalAttempts++;
289
-
290
- if (result.status === "fulfilled") {
291
- if (result.value?.error) {
292
- failureCount++;
293
- } else {
294
- successCount++;
295
- }
296
- } else {
297
- failureCount++;
298
- }
299
- }
300
-
301
- // Expect that we attempted multiple operations
302
- expect(totalAttempts).toBeGreaterThan(0);
303
-
304
- // Either we had successes OR failures - no silent undefined returns
305
- expect(successCount + failureCount).toBe(totalAttempts);
306
- });
307
-
308
- test.skip("should understand why concurrent paint operations occur", async () => {
309
- const container = document.createElement("div");
310
- render(
311
- html`<ef-workbench>
312
- <ef-timegroup mode="contain" style="width: 100px; height: 100px;">
313
- <ef-video
314
- src="/test-assets/media/bars-n-tone2.mp4"
315
- mode="asset"
316
- ></ef-video>
317
- </ef-timegroup>
318
- </ef-workbench>`,
319
- container,
320
- );
321
- document.body.appendChild(container);
322
-
323
- const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
324
- const video = container.querySelector("ef-video") as EFVideo;
325
-
326
- await video.updateComplete;
327
-
328
- // Test case 1: Single time change (should work fine)
329
- timegroup.currentTimeMs = 1000;
330
- await timegroup.updateComplete;
331
-
332
- try {
333
- await timegroup.waitForFrameTasks();
334
- } catch (error) {
335
- // Single time change may still fail due to natural concurrency
336
- expect(error.message).toContain("decoder is currently in use");
337
- }
338
-
339
- // Test case 2: Manual paintTask.run() vs natural task flow
340
- timegroup.currentTimeMs = 2000;
341
- await timegroup.updateComplete;
342
-
343
- try {
344
- await video.paintTask.run();
345
- } catch (error) {
346
- // Expected when manual paintTask.run() conflicts with natural task execution
347
- expect(error.message).toContain("decoder is currently in use");
348
- }
349
-
350
- // Test case 3: Rapid time changes (simulating user scrubbing)
351
- const rapidTimes = [3000, 3500, 4000, 4500];
352
- for (const time of rapidTimes) {
353
- timegroup.currentTimeMs = time;
354
- await timegroup.updateComplete;
355
- }
356
-
357
- await new Promise((resolve) => setTimeout(resolve, 100));
358
-
359
- await expect(timegroup.getPendingFrameTasks()).resolves.toHaveLength(0);
360
- expect(timegroup.currentTimeMs).toBe(4500);
361
- });
362
-
363
- test("should validate paint success vs task completion", async () => {
364
- const container = document.createElement("div");
365
- render(
366
- html`<ef-workbench>
367
- <ef-timegroup mode="contain" style="width: 100px; height: 100px;">
368
- <ef-video
369
- src="/test-assets/media/bars-n-tone2.mp4"
370
- mode="asset"
371
- ></ef-video>
372
- </ef-timegroup>
373
- </ef-workbench>`,
374
- container,
375
- );
376
- document.body.appendChild(container);
377
-
378
- const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
379
- const video = container.querySelector("ef-video") as EFVideo;
380
-
381
- await video.updateComplete;
382
- await new Promise((resolve) => setTimeout(resolve, 500));
383
-
384
- // Verify prerequisite tasks complete successfully
385
- expect(video.fragmentIndexTask.status).toBe(TaskStatus.COMPLETE);
386
- expect(video.mediaSegmentsTask.status).toBe(TaskStatus.COMPLETE);
387
- expect(video.seekTask.status).toBe(TaskStatus.COMPLETE);
388
- expect(video.videoAssetTask.status).toBe(TaskStatus.COMPLETE);
389
-
390
- // Verify all have actual values
391
- expect(video.fragmentIndexTask.value).toBeTruthy();
392
- expect(video.mediaSegmentsTask.value).toBeTruthy();
393
- expect(video.seekTask.value).toBeTruthy();
394
- expect(video.videoAssetTask.value).toBeTruthy();
395
-
396
- // Check canvas state
397
- const canvas = video.canvasRef.value;
398
- const hasCanvas = !!canvas;
399
- let hasContext = false;
400
-
401
- if (canvas) {
402
- const ctx = canvas.getContext("2d");
403
- hasContext = !!ctx;
404
- }
405
-
406
- expect(hasCanvas).toBe(true);
407
- expect(hasContext).toBe(true);
408
-
409
- // Set a specific time and try to paint
410
- timegroup.currentTimeMs = 5000;
411
- await timegroup.updateComplete;
412
- await new Promise((resolve) => setTimeout(resolve, 200));
413
-
414
- try {
415
- const paintResult = await video.paintTask.run();
416
-
417
- // If paint succeeds, verify we got a meaningful result
418
- if (paintResult !== undefined && paintResult !== false) {
419
- expect(paintResult).toBeTruthy();
420
- }
421
-
422
- // Check if pixels were actually rendered
423
- if (canvas && hasContext) {
424
- expect(canvas.width).toBeGreaterThan(0);
425
- expect(canvas.height).toBeGreaterThan(0);
426
- }
427
- } catch (error) {
428
- // Expected concurrency error or other valid error
429
- expect(error.message).toBeDefined();
430
- expect(typeof error.message).toBe("string");
431
- }
432
- });
433
-
434
- test("should diagnose exact rendering issue", async () => {
435
- const container = document.createElement("div");
436
- render(
437
- html`<ef-workbench>
438
- <ef-timegroup mode="contain" style="width: 100px; height: 100px;">
439
- <ef-video
440
- src="/test-assets/media/bars-n-tone2.mp4"
441
- mode="asset"
442
- ></ef-video>
443
- </ef-timegroup>
444
- </ef-workbench>`,
445
- container,
446
- );
447
- document.body.appendChild(container);
448
-
449
- const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
450
- const video = container.querySelector("ef-video") as EFVideo;
451
-
452
- await video.updateComplete;
453
- await new Promise((resolve) => setTimeout(resolve, 500));
454
-
455
- // Verify prerequisite task states
456
- expect(video.fragmentIndexTask.status).toBe(TaskStatus.COMPLETE);
457
- expect(video.mediaSegmentsTask.status).toBe(TaskStatus.COMPLETE);
458
- expect(video.seekTask.status).toBe(TaskStatus.COMPLETE);
459
- expect(video.videoAssetTask.status).toBe(TaskStatus.COMPLETE);
460
-
461
- // Set time for rendering
462
- timegroup.currentTimeMs = 1000;
463
- await timegroup.updateComplete;
464
- await new Promise((resolve) => setTimeout(resolve, 300));
465
-
466
- const canvas = video.canvasRef.value;
467
- assert.ok(canvas, "Canvas should exist");
468
-
469
- try {
470
- await video.paintTask.run();
471
-
472
- // Check pixel state after paint
473
- const ctx = canvas.getContext("2d");
474
- if (ctx) {
475
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
476
- const hasPixelsAfter = imageData.data.some((pixel) => pixel !== 0);
477
-
478
- if (!hasPixelsAfter) {
479
- // Check if videoAsset has frames
480
- const videoAsset = video.videoAssetTask.value;
481
- if (videoAsset) {
482
- expect(typeof videoAsset.seekToTime).toBe("function");
483
-
484
- // Try to manually get a frame
485
- try {
486
- const frame = await videoAsset.seekToTime(1.0);
487
- expect(frame).toBeTruthy();
488
-
489
- if (frame) {
490
- expect(frame.format).toBeDefined();
491
- expect(frame.codedWidth).toBeGreaterThan(0);
492
- expect(frame.codedHeight).toBeGreaterThan(0);
493
-
494
- // Try manual drawImage
495
- ctx.drawImage(frame, 0, 0, canvas.width, canvas.height);
496
- const imageDataAfterManual = ctx.getImageData(
497
- 0,
498
- 0,
499
- canvas.width,
500
- canvas.height,
501
- );
502
- const hasPixelsAfterManual = imageDataAfterManual.data.some(
503
- (pixel) => pixel !== 0,
504
- );
505
- expect(hasPixelsAfterManual).toBe(true);
506
-
507
- frame.close();
508
- }
509
- } catch (seekError) {
510
- // seekToTime errors are acceptable in concurrent scenarios
511
- expect(seekError.message).toContain(
512
- "decoder is currently in use",
513
- );
514
- }
515
- }
516
- } else {
517
- expect(hasPixelsAfter).toBe(true);
518
- }
519
- }
520
- } catch (error) {
521
- expect(error.message).toContain("decoder is currently in use");
522
- }
523
- });
524
- });