@editframe/elements 0.20.4-beta.0 → 0.23.6-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 (183) hide show
  1. package/dist/DelayedLoadingState.js +0 -27
  2. package/dist/EF_FRAMEGEN.d.ts +5 -3
  3. package/dist/EF_FRAMEGEN.js +49 -11
  4. package/dist/_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js +7 -0
  5. package/dist/attachContextRoot.d.ts +1 -0
  6. package/dist/attachContextRoot.js +9 -0
  7. package/dist/elements/ContextProxiesController.d.ts +1 -2
  8. package/dist/elements/EFAudio.js +5 -9
  9. package/dist/elements/EFCaptions.d.ts +1 -3
  10. package/dist/elements/EFCaptions.js +112 -129
  11. package/dist/elements/EFImage.js +6 -7
  12. package/dist/elements/EFMedia/AssetIdMediaEngine.js +2 -5
  13. package/dist/elements/EFMedia/AssetMediaEngine.js +36 -33
  14. package/dist/elements/EFMedia/BaseMediaEngine.js +57 -73
  15. package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +1 -1
  16. package/dist/elements/EFMedia/BufferedSeekingInput.js +134 -78
  17. package/dist/elements/EFMedia/JitMediaEngine.js +9 -19
  18. package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +7 -13
  19. package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +2 -3
  20. package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +1 -1
  21. package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +6 -5
  22. package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +1 -3
  23. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +1 -1
  24. package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +1 -1
  25. package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +1 -1
  26. package/dist/elements/EFMedia/shared/AudioSpanUtils.js +9 -25
  27. package/dist/elements/EFMedia/shared/BufferUtils.js +2 -17
  28. package/dist/elements/EFMedia/shared/GlobalInputCache.js +0 -24
  29. package/dist/elements/EFMedia/shared/PrecisionUtils.js +0 -21
  30. package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +0 -17
  31. package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -10
  32. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.d.ts +29 -0
  33. package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +32 -0
  34. package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +1 -15
  35. package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +1 -7
  36. package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +8 -5
  37. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +12 -13
  38. package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +1 -1
  39. package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +134 -70
  40. package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +11 -18
  41. package/dist/elements/EFMedia.d.ts +19 -0
  42. package/dist/elements/EFMedia.js +44 -25
  43. package/dist/elements/EFSourceMixin.js +5 -7
  44. package/dist/elements/EFSurface.js +6 -9
  45. package/dist/elements/EFTemporal.browsertest.d.ts +11 -0
  46. package/dist/elements/EFTemporal.d.ts +10 -0
  47. package/dist/elements/EFTemporal.js +100 -41
  48. package/dist/elements/EFThumbnailStrip.js +23 -73
  49. package/dist/elements/EFTimegroup.browsertest.d.ts +3 -3
  50. package/dist/elements/EFTimegroup.d.ts +35 -14
  51. package/dist/elements/EFTimegroup.js +138 -181
  52. package/dist/elements/EFVideo.d.ts +16 -2
  53. package/dist/elements/EFVideo.js +156 -108
  54. package/dist/elements/EFWaveform.js +23 -40
  55. package/dist/elements/SampleBuffer.js +3 -7
  56. package/dist/elements/TargetController.js +5 -5
  57. package/dist/elements/durationConverter.js +4 -4
  58. package/dist/elements/renderTemporalAudio.d.ts +10 -0
  59. package/dist/elements/renderTemporalAudio.js +35 -0
  60. package/dist/elements/updateAnimations.js +19 -43
  61. package/dist/gui/ContextMixin.d.ts +5 -5
  62. package/dist/gui/ContextMixin.js +167 -162
  63. package/dist/gui/Controllable.browsertest.d.ts +0 -0
  64. package/dist/gui/Controllable.d.ts +15 -0
  65. package/dist/gui/Controllable.js +9 -0
  66. package/dist/gui/EFConfiguration.js +7 -7
  67. package/dist/gui/EFControls.browsertest.d.ts +11 -0
  68. package/dist/gui/EFControls.d.ts +18 -4
  69. package/dist/gui/EFControls.js +70 -28
  70. package/dist/gui/EFDial.browsertest.d.ts +0 -0
  71. package/dist/gui/EFDial.d.ts +18 -0
  72. package/dist/gui/EFDial.js +141 -0
  73. package/dist/gui/EFFilmstrip.browsertest.d.ts +11 -0
  74. package/dist/gui/EFFilmstrip.d.ts +12 -2
  75. package/dist/gui/EFFilmstrip.js +214 -129
  76. package/dist/gui/EFFitScale.js +5 -8
  77. package/dist/gui/EFFocusOverlay.js +4 -4
  78. package/dist/gui/EFPause.browsertest.d.ts +0 -0
  79. package/dist/gui/EFPause.d.ts +23 -0
  80. package/dist/gui/EFPause.js +59 -0
  81. package/dist/gui/EFPlay.browsertest.d.ts +0 -0
  82. package/dist/gui/EFPlay.d.ts +23 -0
  83. package/dist/gui/EFPlay.js +59 -0
  84. package/dist/gui/EFPreview.d.ts +4 -0
  85. package/dist/gui/EFPreview.js +18 -9
  86. package/dist/gui/EFResizableBox.browsertest.d.ts +0 -0
  87. package/dist/gui/EFResizableBox.d.ts +34 -0
  88. package/dist/gui/EFResizableBox.js +547 -0
  89. package/dist/gui/EFScrubber.d.ts +9 -3
  90. package/dist/gui/EFScrubber.js +13 -13
  91. package/dist/gui/EFTimeDisplay.d.ts +7 -1
  92. package/dist/gui/EFTimeDisplay.js +8 -8
  93. package/dist/gui/EFToggleLoop.d.ts +9 -3
  94. package/dist/gui/EFToggleLoop.js +7 -5
  95. package/dist/gui/EFTogglePlay.d.ts +12 -4
  96. package/dist/gui/EFTogglePlay.js +26 -21
  97. package/dist/gui/EFWorkbench.js +5 -5
  98. package/dist/gui/PlaybackController.d.ts +67 -0
  99. package/dist/gui/PlaybackController.js +310 -0
  100. package/dist/gui/TWMixin.js +1 -1
  101. package/dist/gui/TWMixin2.js +1 -1
  102. package/dist/gui/TargetOrContextMixin.d.ts +10 -0
  103. package/dist/gui/TargetOrContextMixin.js +98 -0
  104. package/dist/gui/efContext.d.ts +2 -2
  105. package/dist/index.d.ts +5 -0
  106. package/dist/index.js +5 -1
  107. package/dist/otel/BridgeSpanExporter.d.ts +13 -0
  108. package/dist/otel/BridgeSpanExporter.js +87 -0
  109. package/dist/otel/setupBrowserTracing.d.ts +12 -0
  110. package/dist/otel/setupBrowserTracing.js +32 -0
  111. package/dist/otel/tracingHelpers.d.ts +34 -0
  112. package/dist/otel/tracingHelpers.js +112 -0
  113. package/dist/style.css +1 -1
  114. package/dist/transcoding/cache/RequestDeduplicator.js +0 -21
  115. package/dist/transcoding/cache/URLTokenDeduplicator.js +1 -21
  116. package/dist/transcoding/utils/UrlGenerator.js +2 -19
  117. package/dist/utils/LRUCache.js +6 -53
  118. package/package.json +13 -5
  119. package/src/elements/ContextProxiesController.ts +10 -10
  120. package/src/elements/EFAudio.ts +1 -0
  121. package/src/elements/EFCaptions.browsertest.ts +128 -56
  122. package/src/elements/EFCaptions.ts +60 -34
  123. package/src/elements/EFImage.browsertest.ts +1 -2
  124. package/src/elements/EFMedia/AssetMediaEngine.ts +65 -37
  125. package/src/elements/EFMedia/BaseMediaEngine.ts +110 -52
  126. package/src/elements/EFMedia/BufferedSeekingInput.ts +218 -101
  127. package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +3 -0
  128. package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +7 -3
  129. package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +1 -1
  130. package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +76 -0
  131. package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +16 -10
  132. package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +7 -1
  133. package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +222 -116
  134. package/src/elements/EFMedia.browsertest.ts +8 -15
  135. package/src/elements/EFMedia.ts +54 -8
  136. package/src/elements/EFSurface.browsertest.ts +2 -6
  137. package/src/elements/EFSurface.ts +1 -0
  138. package/src/elements/EFTemporal.browsertest.ts +58 -1
  139. package/src/elements/EFTemporal.ts +140 -4
  140. package/src/elements/EFThumbnailStrip.browsertest.ts +2 -8
  141. package/src/elements/EFThumbnailStrip.ts +1 -0
  142. package/src/elements/EFTimegroup.browsertest.ts +16 -15
  143. package/src/elements/EFTimegroup.ts +281 -275
  144. package/src/elements/EFVideo.browsertest.ts +162 -74
  145. package/src/elements/EFVideo.ts +229 -101
  146. package/src/elements/FetchContext.browsertest.ts +7 -2
  147. package/src/elements/TargetController.browsertest.ts +1 -0
  148. package/src/elements/TargetController.ts +1 -0
  149. package/src/elements/renderTemporalAudio.ts +108 -0
  150. package/src/elements/updateAnimations.browsertest.ts +181 -6
  151. package/src/elements/updateAnimations.ts +6 -6
  152. package/src/gui/ContextMixin.browsertest.ts +274 -27
  153. package/src/gui/ContextMixin.ts +230 -175
  154. package/src/gui/Controllable.browsertest.ts +258 -0
  155. package/src/gui/Controllable.ts +41 -0
  156. package/src/gui/EFControls.browsertest.ts +294 -80
  157. package/src/gui/EFControls.ts +139 -28
  158. package/src/gui/EFDial.browsertest.ts +84 -0
  159. package/src/gui/EFDial.ts +172 -0
  160. package/src/gui/EFFilmstrip.browsertest.ts +712 -0
  161. package/src/gui/EFFilmstrip.ts +213 -23
  162. package/src/gui/EFPause.browsertest.ts +202 -0
  163. package/src/gui/EFPause.ts +73 -0
  164. package/src/gui/EFPlay.browsertest.ts +202 -0
  165. package/src/gui/EFPlay.ts +73 -0
  166. package/src/gui/EFPreview.ts +20 -5
  167. package/src/gui/EFResizableBox.browsertest.ts +79 -0
  168. package/src/gui/EFResizableBox.ts +898 -0
  169. package/src/gui/EFScrubber.ts +7 -5
  170. package/src/gui/EFTimeDisplay.browsertest.ts +19 -19
  171. package/src/gui/EFTimeDisplay.ts +3 -1
  172. package/src/gui/EFToggleLoop.ts +6 -5
  173. package/src/gui/EFTogglePlay.ts +30 -23
  174. package/src/gui/PlaybackController.ts +522 -0
  175. package/src/gui/TWMixin.css +3 -0
  176. package/src/gui/TargetOrContextMixin.ts +185 -0
  177. package/src/gui/efContext.ts +2 -2
  178. package/src/otel/BridgeSpanExporter.ts +150 -0
  179. package/src/otel/setupBrowserTracing.ts +73 -0
  180. package/src/otel/tracingHelpers.ts +251 -0
  181. package/test/cache-integration-verification.browsertest.ts +1 -1
  182. package/types.json +1 -1
  183. package/dist/elements/ContextProxiesController.js +0 -69
@@ -1,6 +1,6 @@
1
1
  import { ScrubInputCache } from "./ScrubInputCache.js";
2
2
  import { Task } from "@lit/task";
3
- const scrubInputCache = new ScrubInputCache();
3
+ var scrubInputCache = new ScrubInputCache();
4
4
  const makeScrubVideoSeekTask = (host) => {
5
5
  return new Task(host, {
6
6
  args: () => [host.desiredSeekTimeMs],
@@ -11,22 +11,21 @@ const makeScrubVideoSeekTask = (host) => {
11
11
  task: async ([desiredSeekTimeMs], { signal }) => {
12
12
  signal.throwIfAborted();
13
13
  const mediaEngine = host.mediaEngineTask.value;
14
- if (!mediaEngine) return void 0;
14
+ if (!mediaEngine) return;
15
15
  const scrubRendition = mediaEngine.getScrubVideoRendition();
16
- if (!scrubRendition) return void 0;
16
+ if (!scrubRendition) return;
17
17
  const scrubRenditionWithSrc = {
18
18
  ...scrubRendition,
19
19
  src: mediaEngine.src
20
20
  };
21
21
  const segmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, scrubRenditionWithSrc);
22
- if (segmentId === void 0) return void 0;
23
- const isCached = mediaEngine.isSegmentCached(segmentId, scrubRenditionWithSrc);
24
- if (!isCached) return void 0;
22
+ if (segmentId === void 0) return;
23
+ if (!mediaEngine.isSegmentCached(segmentId, scrubRenditionWithSrc)) return;
25
24
  signal.throwIfAborted();
26
25
  try {
27
26
  const scrubInput = await scrubInputCache.getOrCreateInput(segmentId, async () => {
28
27
  const [initSegment, mediaSegment] = await Promise.all([mediaEngine.fetchInitSegment(scrubRenditionWithSrc, signal), mediaEngine.fetchMediaSegment(segmentId, scrubRenditionWithSrc)]);
29
- if (!initSegment || !mediaSegment || signal.aborted) return void 0;
28
+ if (!initSegment || !mediaSegment || signal.aborted) return;
30
29
  const { BufferedSeekingInput } = await import("../BufferedSeekingInput.js");
31
30
  const { EFMedia } = await import("../../EFMedia.js");
32
31
  return new BufferedSeekingInput(await new Blob([initSegment, mediaSegment]).arrayBuffer(), {
@@ -35,16 +34,16 @@ const makeScrubVideoSeekTask = (host) => {
35
34
  startTimeOffsetMs: scrubRendition.startTimeOffsetMs
36
35
  });
37
36
  });
38
- if (!scrubInput) return void 0;
37
+ if (!scrubInput) return;
38
+ if (signal.aborted) return;
39
39
  const videoTrack = await scrubInput.getFirstVideoTrack();
40
- if (!videoTrack) return void 0;
41
- signal.throwIfAborted();
42
- const sample = await scrubInput.seek(videoTrack.id, desiredSeekTimeMs);
43
- return sample;
40
+ if (!videoTrack) return;
41
+ if (signal.aborted) return;
42
+ return await scrubInput.seek(videoTrack.id, desiredSeekTimeMs);
44
43
  } catch (error) {
45
44
  if (signal.aborted) return void 0;
46
45
  console.warn("Failed to get scrub video sample:", error);
47
- return void 0;
46
+ return;
48
47
  }
49
48
  }
50
49
  });
@@ -11,7 +11,7 @@ const makeScrubVideoSegmentIdTask = (host) => {
11
11
  const mediaEngine = await getLatestMediaEngine(host, signal);
12
12
  signal.throwIfAborted();
13
13
  const scrubRendition = mediaEngine.getScrubVideoRendition();
14
- if (!scrubRendition) return void 0;
14
+ if (!scrubRendition) return;
15
15
  return mediaEngine.computeSegmentId(targetSeekTimeMs, {
16
16
  ...scrubRendition,
17
17
  src: mediaEngine.src
@@ -1,7 +1,12 @@
1
+ import { withSpan } from "../../../otel/tracingHelpers.js";
1
2
  import { getLatestMediaEngine } from "../tasks/makeMediaEngineTask.js";
3
+ import { BufferedSeekingInput } from "../BufferedSeekingInput.js";
4
+ import { EFMedia } from "../../EFMedia.js";
2
5
  import { ScrubInputCache } from "./ScrubInputCache.js";
6
+ import { MainVideoInputCache } from "./MainVideoInputCache.js";
3
7
  import { Task } from "@lit/task";
4
- const scrubInputCache = new ScrubInputCache();
8
+ var scrubInputCache = new ScrubInputCache();
9
+ var mainVideoInputCache = new MainVideoInputCache();
5
10
  const makeUnifiedVideoSeekTask = (host) => {
6
11
  return new Task(host, {
7
12
  autoRun: false,
@@ -12,92 +17,151 @@ const makeUnifiedVideoSeekTask = (host) => {
12
17
  onComplete: (_value) => {},
13
18
  task: async ([desiredSeekTimeMs], { signal }) => {
14
19
  const mediaEngine = await getLatestMediaEngine(host, signal);
15
- if (!mediaEngine) return void 0;
20
+ if (!mediaEngine || signal.aborted) return void 0;
16
21
  const mainRendition = mediaEngine.videoRendition;
17
22
  if (mainRendition) {
18
23
  const mainSegmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, mainRendition);
19
- if (mainSegmentId !== void 0 && mediaEngine.isSegmentCached(mainSegmentId, mainRendition)) return await getMainVideoSample(host, mediaEngine, desiredSeekTimeMs, signal);
24
+ if (mainSegmentId !== void 0 && mediaEngine.isSegmentCached(mainSegmentId, mainRendition)) {
25
+ const result$1 = await getMainVideoSample(host, mediaEngine, desiredSeekTimeMs, signal);
26
+ if (signal.aborted) return;
27
+ return result$1;
28
+ }
20
29
  }
21
30
  const scrubSample = await tryGetScrubSample(mediaEngine, desiredSeekTimeMs, signal);
22
31
  if (scrubSample || signal.aborted) {
32
+ if (signal.aborted) return;
23
33
  if (scrubSample) startMainQualityUpgrade(host, mediaEngine, desiredSeekTimeMs, signal).catch(() => {});
24
34
  return scrubSample;
25
35
  }
26
- return await getMainVideoSample(host, mediaEngine, desiredSeekTimeMs, signal);
36
+ const result = await getMainVideoSample(host, mediaEngine, desiredSeekTimeMs, signal);
37
+ if (signal.aborted) return;
38
+ return result;
27
39
  }
28
40
  });
29
41
  };
30
- /**
31
- * Try to get scrub sample from cache (instant if available)
32
- */
33
42
  async function tryGetScrubSample(mediaEngine, desiredSeekTimeMs, signal) {
34
- try {
35
- let scrubRendition;
36
- if (typeof mediaEngine.getScrubVideoRendition === "function") scrubRendition = mediaEngine.getScrubVideoRendition();
37
- else if ("data" in mediaEngine && mediaEngine.data?.videoRenditions) scrubRendition = mediaEngine.data.videoRenditions.find((r) => r.id === "scrub");
38
- if (!scrubRendition) return void 0;
39
- const scrubRenditionWithSrc = {
40
- ...scrubRendition,
41
- src: mediaEngine.src
42
- };
43
- const segmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, scrubRenditionWithSrc);
44
- if (segmentId === void 0) return void 0;
45
- const isCached = mediaEngine.isSegmentCached(segmentId, scrubRenditionWithSrc);
46
- if (!isCached) return void 0;
47
- const scrubInput = await scrubInputCache.getOrCreateInput(segmentId, async () => {
48
- const [initSegment, mediaSegment] = await Promise.all([mediaEngine.fetchInitSegment(scrubRenditionWithSrc, signal), mediaEngine.fetchMediaSegment(segmentId, scrubRenditionWithSrc)]);
49
- if (!initSegment || !mediaSegment || signal.aborted) return void 0;
50
- const { BufferedSeekingInput } = await import("../BufferedSeekingInput.js");
51
- const { EFMedia } = await import("../../EFMedia.js");
52
- return new BufferedSeekingInput(await new Blob([initSegment, mediaSegment]).arrayBuffer(), {
53
- videoBufferSize: EFMedia.VIDEO_SAMPLE_BUFFER_SIZE,
54
- audioBufferSize: EFMedia.AUDIO_SAMPLE_BUFFER_SIZE,
55
- startTimeOffsetMs: scrubRendition.startTimeOffsetMs
43
+ return withSpan("video.tryGetScrubSample", {
44
+ desiredSeekTimeMs,
45
+ src: mediaEngine.src || "unknown"
46
+ }, void 0, async (span) => {
47
+ try {
48
+ let scrubRendition;
49
+ if (typeof mediaEngine.getScrubVideoRendition === "function") scrubRendition = mediaEngine.getScrubVideoRendition();
50
+ else if ("data" in mediaEngine && mediaEngine.data?.videoRenditions) scrubRendition = mediaEngine.data.videoRenditions.find((r) => r.id === "scrub");
51
+ if (!scrubRendition) {
52
+ span.setAttribute("result", "no-scrub-rendition");
53
+ return;
54
+ }
55
+ const scrubRenditionWithSrc = {
56
+ ...scrubRendition,
57
+ src: mediaEngine.src
58
+ };
59
+ const segmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, scrubRenditionWithSrc);
60
+ if (segmentId === void 0) {
61
+ span.setAttribute("result", "no-segment-id");
62
+ return;
63
+ }
64
+ const isCached = mediaEngine.isSegmentCached(segmentId, scrubRenditionWithSrc);
65
+ span.setAttribute("isCached", isCached);
66
+ if (!isCached) {
67
+ span.setAttribute("result", "not-cached");
68
+ return;
69
+ }
70
+ const scrubInput = await scrubInputCache.getOrCreateInput(segmentId, async () => {
71
+ const [initSegment, mediaSegment] = await Promise.all([mediaEngine.fetchInitSegment(scrubRenditionWithSrc, signal), mediaEngine.fetchMediaSegment(segmentId, scrubRenditionWithSrc)]);
72
+ if (!initSegment || !mediaSegment || signal.aborted) return void 0;
73
+ const { BufferedSeekingInput: BufferedSeekingInput$1 } = await import("../BufferedSeekingInput.js");
74
+ const { EFMedia: EFMedia$1 } = await import("../../EFMedia.js");
75
+ return new BufferedSeekingInput$1(await new Blob([initSegment, mediaSegment]).arrayBuffer(), {
76
+ videoBufferSize: EFMedia$1.VIDEO_SAMPLE_BUFFER_SIZE,
77
+ audioBufferSize: EFMedia$1.AUDIO_SAMPLE_BUFFER_SIZE,
78
+ startTimeOffsetMs: scrubRendition.startTimeOffsetMs
79
+ });
56
80
  });
57
- });
58
- if (!scrubInput) return void 0;
59
- const videoTrack = await scrubInput.getFirstVideoTrack();
60
- if (!videoTrack) return void 0;
61
- const sample = await scrubInput.seek(videoTrack.id, desiredSeekTimeMs);
62
- return sample;
63
- } catch (_error) {
64
- if (signal.aborted) return void 0;
65
- return void 0;
66
- }
81
+ if (!scrubInput) {
82
+ span.setAttribute("result", "no-scrub-input");
83
+ return;
84
+ }
85
+ if (signal.aborted) {
86
+ span.setAttribute("result", "aborted-after-scrub-input");
87
+ return;
88
+ }
89
+ const videoTrack = await scrubInput.getFirstVideoTrack();
90
+ if (!videoTrack) {
91
+ span.setAttribute("result", "no-video-track");
92
+ return;
93
+ }
94
+ if (signal.aborted) {
95
+ span.setAttribute("result", "aborted-after-scrub-track");
96
+ return;
97
+ }
98
+ const sample = await scrubInput.seek(videoTrack.id, desiredSeekTimeMs);
99
+ span.setAttribute("result", sample ? "success" : "no-sample");
100
+ return sample;
101
+ } catch (_error) {
102
+ if (signal.aborted) {
103
+ span.setAttribute("result", "aborted");
104
+ return;
105
+ }
106
+ span.setAttribute("result", "error");
107
+ return;
108
+ }
109
+ });
67
110
  }
68
- /**
69
- * Get main video sample (slower path with fetching)
70
- */
71
111
  async function getMainVideoSample(_host, mediaEngine, desiredSeekTimeMs, signal) {
72
- try {
73
- const videoRendition = mediaEngine.getVideoRendition();
74
- if (!videoRendition) throw new Error("Video rendition unavailable after checking videoRendition exists");
75
- const segmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, videoRendition);
76
- if (segmentId === void 0) return void 0;
77
- const [initSegment, mediaSegment] = await Promise.all([mediaEngine.fetchInitSegment(videoRendition, signal), mediaEngine.fetchMediaSegment(segmentId, videoRendition, signal)]);
78
- if (!initSegment || !mediaSegment) return void 0;
79
- signal.throwIfAborted();
80
- const { BufferedSeekingInput } = await import("../BufferedSeekingInput.js");
81
- const { EFMedia } = await import("../../EFMedia.js");
82
- const startTimeOffsetMs = videoRendition?.startTimeOffsetMs;
83
- const mainInput = new BufferedSeekingInput(await new Blob([initSegment, mediaSegment]).arrayBuffer(), {
84
- videoBufferSize: EFMedia.VIDEO_SAMPLE_BUFFER_SIZE,
85
- audioBufferSize: EFMedia.AUDIO_SAMPLE_BUFFER_SIZE,
86
- startTimeOffsetMs
87
- });
88
- const videoTrack = await mainInput.getFirstVideoTrack();
89
- if (!videoTrack) return void 0;
90
- signal.throwIfAborted();
91
- const sample = await mainInput.seek(videoTrack.id, desiredSeekTimeMs);
92
- return sample;
93
- } catch (error) {
94
- if (signal.aborted) return void 0;
95
- throw error;
96
- }
112
+ return withSpan("video.getMainVideoSample", {
113
+ desiredSeekTimeMs,
114
+ src: mediaEngine.src || "unknown"
115
+ }, void 0, async (span) => {
116
+ try {
117
+ const videoRendition = mediaEngine.getVideoRendition();
118
+ if (!videoRendition) throw new Error("Video rendition unavailable after checking videoRendition exists");
119
+ const segmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, videoRendition);
120
+ if (segmentId === void 0) {
121
+ span.setAttribute("result", "no-segment-id");
122
+ return;
123
+ }
124
+ span.setAttribute("segmentId", segmentId);
125
+ const mainInput = await mainVideoInputCache.getOrCreateInput(mediaEngine.src, segmentId, videoRendition.id, async () => {
126
+ const [initSegment, mediaSegment] = await Promise.all([mediaEngine.fetchInitSegment(videoRendition, signal), mediaEngine.fetchMediaSegment(segmentId, videoRendition, signal)]);
127
+ if (!initSegment || !mediaSegment) return;
128
+ signal.throwIfAborted();
129
+ const startTimeOffsetMs = videoRendition?.startTimeOffsetMs;
130
+ return new BufferedSeekingInput(await new Blob([initSegment, mediaSegment]).arrayBuffer(), {
131
+ videoBufferSize: EFMedia.VIDEO_SAMPLE_BUFFER_SIZE,
132
+ audioBufferSize: EFMedia.AUDIO_SAMPLE_BUFFER_SIZE,
133
+ startTimeOffsetMs
134
+ });
135
+ });
136
+ if (!mainInput) {
137
+ span.setAttribute("result", "no-segments");
138
+ return;
139
+ }
140
+ if (signal.aborted) {
141
+ span.setAttribute("result", "aborted-after-input");
142
+ return;
143
+ }
144
+ const videoTrack = await mainInput.getFirstVideoTrack();
145
+ if (!videoTrack) {
146
+ span.setAttribute("result", "no-video-track");
147
+ return;
148
+ }
149
+ if (signal.aborted) {
150
+ span.setAttribute("result", "aborted-after-track");
151
+ return;
152
+ }
153
+ const sample = await mainInput.seek(videoTrack.id, desiredSeekTimeMs);
154
+ span.setAttribute("result", sample ? "success" : "no-sample");
155
+ return sample;
156
+ } catch (error) {
157
+ if (signal.aborted) {
158
+ span.setAttribute("result", "aborted");
159
+ return;
160
+ }
161
+ throw error;
162
+ }
163
+ });
97
164
  }
98
- /**
99
- * Start background upgrade to main quality (non-blocking)
100
- */
101
165
  async function startMainQualityUpgrade(host, mediaEngine, targetSeekTimeMs, signal) {
102
166
  await new Promise((resolve) => setTimeout(resolve, 50));
103
167
  if (signal.aborted || host.desiredSeekTimeMs !== targetSeekTimeMs) return;
@@ -21,32 +21,25 @@ const makeVideoBufferTask = (host) => {
21
21
  },
22
22
  task: async ([seekTimeMs], { signal }) => {
23
23
  if (EF_RENDERING()) return currentState;
24
- const mediaEngine = await getLatestMediaEngine(host, signal);
25
- const engineConfig = mediaEngine.getBufferConfig();
26
- const bufferDurationMs = engineConfig.videoBufferDurationMs;
27
- const maxParallelFetches = engineConfig.maxVideoBufferFetches;
28
- const currentConfig = {
29
- bufferDurationMs,
30
- maxParallelFetches,
24
+ const engineConfig = (await getLatestMediaEngine(host, signal)).getBufferConfig();
25
+ return manageMediaBuffer(seekTimeMs, {
26
+ bufferDurationMs: engineConfig.videoBufferDurationMs,
27
+ maxParallelFetches: engineConfig.maxVideoBufferFetches,
31
28
  enableBuffering: host.enableVideoBuffering
32
- };
33
- return manageMediaBuffer(seekTimeMs, currentConfig, currentState, host.intrinsicDurationMs || 1e4, signal, {
29
+ }, currentState, host.intrinsicDurationMs || 1e4, signal, {
34
30
  computeSegmentId: async (timeMs, rendition) => {
35
- const mediaEngine$1 = await getLatestMediaEngine(host, signal);
36
- return mediaEngine$1.computeSegmentId(timeMs, rendition);
31
+ return (await getLatestMediaEngine(host, signal)).computeSegmentId(timeMs, rendition);
37
32
  },
38
33
  prefetchSegment: async (segmentId, rendition) => {
39
- const mediaEngine$1 = await getLatestMediaEngine(host, signal);
40
- await mediaEngine$1.fetchMediaSegment(segmentId, rendition);
34
+ await (await getLatestMediaEngine(host, signal)).fetchMediaSegment(segmentId, rendition);
41
35
  },
42
36
  isSegmentCached: (segmentId, rendition) => {
43
- const mediaEngine$1 = host.mediaEngineTask.value;
44
- if (!mediaEngine$1) return false;
45
- return mediaEngine$1.isSegmentCached(segmentId, rendition);
37
+ const mediaEngine = host.mediaEngineTask.value;
38
+ if (!mediaEngine) return false;
39
+ return mediaEngine.isSegmentCached(segmentId, rendition);
46
40
  },
47
41
  getRendition: async () => {
48
- const mediaEngine$1 = await getLatestMediaEngine(host, signal);
49
- return mediaEngine$1.getVideoRendition();
42
+ return (await getLatestMediaEngine(host, signal)).getVideoRendition();
50
43
  },
51
44
  logError: console.error
52
45
  });
@@ -1,4 +1,5 @@
1
1
  import { LitElement, PropertyValueMap } from 'lit';
2
+ import { ControllableInterface } from '../gui/Controllable.js';
2
3
  import { AudioSpan } from '../transcoding/types/index.ts';
3
4
  import { UrlGenerator } from '../transcoding/utils/UrlGenerator.ts';
4
5
  declare global {
@@ -9,6 +10,7 @@ export declare class IgnorableError extends Error {
9
10
  export declare const deepGetMediaElements: (element: Element, medias?: EFMedia[]) => EFMedia[];
10
11
  declare const EFMedia_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
11
12
  export declare class EFMedia extends EFMedia_base {
13
+ get efContext(): ControllableInterface | null;
12
14
  static readonly VIDEO_SAMPLE_BUFFER_SIZE = 30;
13
15
  static readonly AUDIO_SAMPLE_BUFFER_SIZE = 120;
14
16
  static get observedAttributes(): string[];
@@ -84,5 +86,22 @@ export declare class EFMedia extends EFMedia_base {
84
86
  * Returns undefined if no audio rendition is available
85
87
  */
86
88
  fetchAudioSpanningTime(fromMs: number, toMs: number, signal?: AbortSignal): Promise<AudioSpan | undefined>;
89
+ /**
90
+ * Wait for media engine to load and determine duration
91
+ * Ensures media is ready for playback
92
+ */
93
+ waitForMediaDurations(): Promise<void>;
94
+ /**
95
+ * Returns media elements for playback audio rendering
96
+ * For standalone media, returns [this]; for timegroups, returns all descendants
97
+ * Used by PlaybackController for audio-driven playback
98
+ */
99
+ getMediaElements(): EFMedia[];
100
+ /**
101
+ * Render audio buffer for playback
102
+ * Called by PlaybackController during live playback
103
+ * Delegates to shared renderTemporalAudio utility for consistent behavior
104
+ */
105
+ renderAudio(fromMs: number, toMs: number): Promise<AudioBuffer>;
87
106
  }
88
107
  export {};
@@ -1,4 +1,8 @@
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
2
+ import { EFTemporal } from "./EFTemporal.js";
3
+ import { efContext } from "../gui/efContext.js";
1
4
  import { isContextMixin } from "../gui/ContextMixin.js";
5
+ import { withSpan } from "../otel/tracingHelpers.js";
2
6
  import { UrlGenerator } from "../transcoding/utils/UrlGenerator.js";
3
7
  import { makeMediaEngineTask } from "./EFMedia/tasks/makeMediaEngineTask.js";
4
8
  import { makeAudioBufferTask } from "./EFMedia/audioTasks/makeAudioBufferTask.js";
@@ -11,13 +15,13 @@ import { makeAudioSegmentIdTask } from "./EFMedia/audioTasks/makeAudioSegmentIdT
11
15
  import { makeAudioTimeDomainAnalysisTask } from "./EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js";
12
16
  import { fetchAudioSpanningTime } from "./EFMedia/shared/AudioSpanUtils.js";
13
17
  import { EFSourceMixin } from "./EFSourceMixin.js";
14
- import { EFTemporal } from "./EFTemporal.js";
15
18
  import { FetchMixin } from "./FetchMixin.js";
19
+ import { renderTemporalAudio } from "./renderTemporalAudio.js";
16
20
  import { EFTargetable } from "./TargetController.js";
21
+ import { provide } from "@lit/context";
17
22
  import { LitElement, css } from "lit";
18
23
  import { property, state } from "lit/decorators.js";
19
- import _decorate from "@oxc-project/runtime/helpers/decorate";
20
- const freqWeightsCache = /* @__PURE__ */ new Map();
24
+ var freqWeightsCache = /* @__PURE__ */ new Map();
21
25
  var IgnorableError = class extends Error {};
22
26
  const deepGetMediaElements = (element, medias = []) => {
23
27
  for (const child of Array.from(element.children)) if (child instanceof EFMedia) medias.push(child);
@@ -47,6 +51,9 @@ var EFMedia = class extends EFTargetable(EFSourceMixin(EFTemporal(FetchMixin(Lit
47
51
  this.assetId = null;
48
52
  this._desiredSeekTimeMs = 0;
49
53
  }
54
+ get efContext() {
55
+ return this.rootTimegroup ?? this;
56
+ }
50
57
  static {
51
58
  this.VIDEO_SAMPLE_BUFFER_SIZE = 30;
52
59
  }
@@ -54,9 +61,8 @@ var EFMedia = class extends EFTargetable(EFSourceMixin(EFTemporal(FetchMixin(Lit
54
61
  this.AUDIO_SAMPLE_BUFFER_SIZE = 120;
55
62
  }
56
63
  static get observedAttributes() {
57
- const parentAttributes = super.observedAttributes || [];
58
64
  return [
59
- ...parentAttributes,
65
+ ...super.observedAttributes || [],
60
66
  "mute",
61
67
  "fft-size",
62
68
  "fft-decay",
@@ -108,14 +114,12 @@ var EFMedia = class extends EFTargetable(EFSourceMixin(EFTemporal(FetchMixin(Lit
108
114
  const newCurrentSourceTimeMs = this.currentSourceTimeMs;
109
115
  if (newCurrentSourceTimeMs !== this.desiredSeekTimeMs) this.executeSeek(newCurrentSourceTimeMs);
110
116
  if (changedProperties.has("ownCurrentTimeMs")) this.executeSeek(this.currentSourceTimeMs);
111
- const durationAffectingProps = [
117
+ if ([
112
118
  "_trimStartMs",
113
119
  "_trimEndMs",
114
120
  "_sourceInMs",
115
121
  "_sourceOutMs"
116
- ];
117
- const hasDurationChange = durationAffectingProps.some((prop) => changedProperties.has(prop));
118
- if (hasDurationChange) {
122
+ ].some((prop) => changedProperties.has(prop))) {
119
123
  if (this.parentTimegroup) {
120
124
  this.parentTimegroup.requestUpdate("durationMs");
121
125
  this.parentTimegroup.requestUpdate("currentTime");
@@ -142,56 +146,71 @@ var EFMedia = class extends EFTargetable(EFSourceMixin(EFTemporal(FetchMixin(Lit
142
146
  async executeSeek(seekToMs) {
143
147
  this.desiredSeekTimeMs = seekToMs;
144
148
  }
145
- /**
146
- * Main integration method for EFTimegroup audio playback
147
- * Now powered by clean, testable utility functions
148
- * Returns undefined if no audio rendition is available
149
- */
150
149
  async fetchAudioSpanningTime(fromMs, toMs, signal = new AbortController().signal) {
151
- return fetchAudioSpanningTime(this, fromMs, toMs, signal);
150
+ return withSpan("media.fetchAudioSpanningTime", {
151
+ elementId: this.id || "unknown",
152
+ tagName: this.tagName.toLowerCase(),
153
+ fromMs,
154
+ toMs,
155
+ durationMs: toMs - fromMs,
156
+ src: this.src || "none"
157
+ }, void 0, async () => {
158
+ return fetchAudioSpanningTime(this, fromMs, toMs, signal);
159
+ });
160
+ }
161
+ async waitForMediaDurations() {
162
+ if (this.mediaEngineTask.value) return;
163
+ await this.mediaEngineTask.run();
164
+ }
165
+ getMediaElements() {
166
+ return [this];
167
+ }
168
+ async renderAudio(fromMs, toMs) {
169
+ return renderTemporalAudio(this, fromMs, toMs);
152
170
  }
153
171
  };
154
- _decorate([property({
172
+ __decorate([provide({ context: efContext })], EFMedia.prototype, "efContext", null);
173
+ __decorate([property({
155
174
  type: Number,
156
175
  attribute: "audio-buffer-duration"
157
176
  })], EFMedia.prototype, "audioBufferDurationMs", void 0);
158
- _decorate([property({
177
+ __decorate([property({
159
178
  type: Number,
160
179
  attribute: "max-audio-buffer-fetches"
161
180
  })], EFMedia.prototype, "maxAudioBufferFetches", void 0);
162
- _decorate([property({
181
+ __decorate([property({
163
182
  type: Boolean,
164
183
  attribute: "enable-audio-buffering"
165
184
  })], EFMedia.prototype, "enableAudioBuffering", void 0);
166
- _decorate([property({
185
+ __decorate([property({
167
186
  type: Boolean,
168
187
  attribute: "mute",
169
188
  reflect: true
170
189
  })], EFMedia.prototype, "mute", void 0);
171
- _decorate([property({
190
+ __decorate([property({
172
191
  type: Number,
173
192
  attribute: "fft-size",
174
193
  reflect: true
175
194
  })], EFMedia.prototype, "fftSize", void 0);
176
- _decorate([property({
195
+ __decorate([property({
177
196
  type: Number,
178
197
  attribute: "fft-decay",
179
198
  reflect: true
180
199
  })], EFMedia.prototype, "fftDecay", void 0);
181
- _decorate([property({
200
+ __decorate([property({
182
201
  type: Number,
183
202
  attribute: "fft-gain",
184
203
  reflect: true
185
204
  })], EFMedia.prototype, "fftGain", void 0);
186
- _decorate([property({
205
+ __decorate([property({
187
206
  type: Boolean,
188
207
  attribute: "interpolate-frequencies",
189
208
  reflect: true
190
209
  })], EFMedia.prototype, "interpolateFrequencies", void 0);
191
- _decorate([property({
210
+ __decorate([property({
192
211
  type: String,
193
212
  attribute: "asset-id",
194
213
  reflect: true
195
214
  })], EFMedia.prototype, "assetId", void 0);
196
- _decorate([state()], EFMedia.prototype, "_desiredSeekTimeMs", void 0);
215
+ __decorate([state()], EFMedia.prototype, "_desiredSeekTimeMs", void 0);
197
216
  export { EFMedia, IgnorableError, deepGetMediaElements };
@@ -1,5 +1,5 @@
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
2
  import { Task } from "@lit/task";
2
- import _decorate from "@oxc-project/runtime/helpers/decorate";
3
3
  import { property } from "lit/decorators/property.js";
4
4
  function EFSourceMixin(superClass, options) {
5
5
  class EFSourceElement extends superClass {
@@ -11,17 +11,15 @@ function EFSourceMixin(superClass, options) {
11
11
  args: () => [this.src],
12
12
  task: async ([src], { signal }) => {
13
13
  const md5Path = `/@ef-asset/${src}`;
14
- const response = await fetch(md5Path, {
14
+ return (await fetch(md5Path, {
15
15
  method: "HEAD",
16
16
  signal
17
- });
18
- return response.headers.get("etag") ?? void 0;
17
+ })).headers.get("etag") ?? void 0;
19
18
  }
20
19
  });
21
20
  }
22
21
  get apiHost() {
23
- const apiHost = this.closest("ef-configuration")?.apiHost ?? this.closest("ef-workbench")?.apiHost ?? this.closest("ef-preview")?.apiHost;
24
- return apiHost || "https://editframe.dev";
22
+ return (this.closest("ef-configuration")?.apiHost ?? this.closest("ef-workbench")?.apiHost ?? this.closest("ef-preview")?.apiHost) || "https://editframe.dev";
25
23
  }
26
24
  productionSrc() {
27
25
  if (!this.md5SumLoader.value) throw new Error(`MD5 sum not available for ${this}. Cannot generate production URL`);
@@ -29,7 +27,7 @@ function EFSourceMixin(superClass, options) {
29
27
  return `${this.apiHost}/api/v1/${options.assetType}/${this.md5SumLoader.value}`;
30
28
  }
31
29
  }
32
- _decorate([property({ type: String })], EFSourceElement.prototype, "src", void 0);
30
+ __decorate([property({ type: String })], EFSourceElement.prototype, "src", void 0);
33
31
  return EFSourceElement;
34
32
  }
35
33
  export { EFSourceMixin };
@@ -1,10 +1,10 @@
1
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
1
2
  import { TargetController } from "./TargetController.js";
2
3
  import { Task } from "@lit/task";
3
4
  import { LitElement, css, html } from "lit";
4
5
  import { customElement, property, state } from "lit/decorators.js";
5
- import _decorate from "@oxc-project/runtime/helpers/decorate";
6
6
  import { createRef, ref } from "lit/directives/ref.js";
7
- let EFSurface = class EFSurface$1 extends LitElement {
7
+ var EFSurface = class EFSurface$1 extends LitElement {
8
8
  constructor(..._args) {
9
9
  super(..._args);
10
10
  this.canvasRef = createRef();
@@ -70,10 +70,7 @@ let EFSurface = class EFSurface$1 extends LitElement {
70
70
  const anyEl = from;
71
71
  if ("canvasElement" in anyEl) return anyEl.canvasElement ?? null;
72
72
  const sr = from.shadowRoot;
73
- if (sr) {
74
- const c = sr.querySelector("canvas");
75
- return c ?? null;
76
- }
73
+ if (sr) return sr.querySelector("canvas") ?? null;
77
74
  return null;
78
75
  }
79
76
  copyFromTarget(target) {
@@ -90,7 +87,7 @@ let EFSurface = class EFSurface$1 extends LitElement {
90
87
  ctx.drawImage(src, 0, 0, dst.width, dst.height);
91
88
  }
92
89
  };
93
- _decorate([state()], EFSurface.prototype, "targetElement", void 0);
94
- _decorate([property({ type: String })], EFSurface.prototype, "target", void 0);
95
- EFSurface = _decorate([customElement("ef-surface")], EFSurface);
90
+ __decorate([state()], EFSurface.prototype, "targetElement", void 0);
91
+ __decorate([property({ type: String })], EFSurface.prototype, "target", void 0);
92
+ EFSurface = __decorate([customElement("ef-surface")], EFSurface);
96
93
  export { EFSurface };
@@ -8,4 +8,15 @@ declare global {
8
8
  "ten-seconds": TenSeconds;
9
9
  }
10
10
  }
11
+ declare const TestLifecycleChild_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
12
+ declare class TestLifecycleChild extends TestLifecycleChild_base {
13
+ role: "root" | "child" | null;
14
+ didBecomeRoot(): void;
15
+ didBecomeChild(): void;
16
+ }
17
+ declare global {
18
+ interface HTMLElementTagNameMap {
19
+ "test-root-lifecycle": TestLifecycleChild;
20
+ }
21
+ }
11
22
  export {};