@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.
- package/dist/DelayedLoadingState.js +0 -27
- package/dist/EF_FRAMEGEN.d.ts +5 -3
- package/dist/EF_FRAMEGEN.js +49 -11
- package/dist/_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js +7 -0
- package/dist/attachContextRoot.d.ts +1 -0
- package/dist/attachContextRoot.js +9 -0
- package/dist/elements/ContextProxiesController.d.ts +1 -2
- package/dist/elements/EFAudio.js +5 -9
- package/dist/elements/EFCaptions.d.ts +1 -3
- package/dist/elements/EFCaptions.js +112 -129
- package/dist/elements/EFImage.js +6 -7
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +2 -5
- package/dist/elements/EFMedia/AssetMediaEngine.js +36 -33
- package/dist/elements/EFMedia/BaseMediaEngine.js +57 -73
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js +134 -78
- package/dist/elements/EFMedia/JitMediaEngine.js +9 -19
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +7 -13
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +2 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +6 -5
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +1 -3
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +9 -25
- package/dist/elements/EFMedia/shared/BufferUtils.js +2 -17
- package/dist/elements/EFMedia/shared/GlobalInputCache.js +0 -24
- package/dist/elements/EFMedia/shared/PrecisionUtils.js +0 -21
- package/dist/elements/EFMedia/shared/ThumbnailExtractor.js +0 -17
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +1 -10
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.d.ts +29 -0
- package/dist/elements/EFMedia/videoTasks/MainVideoInputCache.js +32 -0
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +1 -15
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +1 -7
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +8 -5
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +12 -13
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +1 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +134 -70
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +11 -18
- package/dist/elements/EFMedia.d.ts +19 -0
- package/dist/elements/EFMedia.js +44 -25
- package/dist/elements/EFSourceMixin.js +5 -7
- package/dist/elements/EFSurface.js +6 -9
- package/dist/elements/EFTemporal.browsertest.d.ts +11 -0
- package/dist/elements/EFTemporal.d.ts +10 -0
- package/dist/elements/EFTemporal.js +100 -41
- package/dist/elements/EFThumbnailStrip.js +23 -73
- package/dist/elements/EFTimegroup.browsertest.d.ts +3 -3
- package/dist/elements/EFTimegroup.d.ts +35 -14
- package/dist/elements/EFTimegroup.js +138 -181
- package/dist/elements/EFVideo.d.ts +16 -2
- package/dist/elements/EFVideo.js +156 -108
- package/dist/elements/EFWaveform.js +23 -40
- package/dist/elements/SampleBuffer.js +3 -7
- package/dist/elements/TargetController.js +5 -5
- package/dist/elements/durationConverter.js +4 -4
- package/dist/elements/renderTemporalAudio.d.ts +10 -0
- package/dist/elements/renderTemporalAudio.js +35 -0
- package/dist/elements/updateAnimations.js +19 -43
- package/dist/gui/ContextMixin.d.ts +5 -5
- package/dist/gui/ContextMixin.js +167 -162
- package/dist/gui/Controllable.browsertest.d.ts +0 -0
- package/dist/gui/Controllable.d.ts +15 -0
- package/dist/gui/Controllable.js +9 -0
- package/dist/gui/EFConfiguration.js +7 -7
- package/dist/gui/EFControls.browsertest.d.ts +11 -0
- package/dist/gui/EFControls.d.ts +18 -4
- package/dist/gui/EFControls.js +70 -28
- package/dist/gui/EFDial.browsertest.d.ts +0 -0
- package/dist/gui/EFDial.d.ts +18 -0
- package/dist/gui/EFDial.js +141 -0
- package/dist/gui/EFFilmstrip.browsertest.d.ts +11 -0
- package/dist/gui/EFFilmstrip.d.ts +12 -2
- package/dist/gui/EFFilmstrip.js +214 -129
- package/dist/gui/EFFitScale.js +5 -8
- package/dist/gui/EFFocusOverlay.js +4 -4
- package/dist/gui/EFPause.browsertest.d.ts +0 -0
- package/dist/gui/EFPause.d.ts +23 -0
- package/dist/gui/EFPause.js +59 -0
- package/dist/gui/EFPlay.browsertest.d.ts +0 -0
- package/dist/gui/EFPlay.d.ts +23 -0
- package/dist/gui/EFPlay.js +59 -0
- package/dist/gui/EFPreview.d.ts +4 -0
- package/dist/gui/EFPreview.js +18 -9
- package/dist/gui/EFResizableBox.browsertest.d.ts +0 -0
- package/dist/gui/EFResizableBox.d.ts +34 -0
- package/dist/gui/EFResizableBox.js +547 -0
- package/dist/gui/EFScrubber.d.ts +9 -3
- package/dist/gui/EFScrubber.js +13 -13
- package/dist/gui/EFTimeDisplay.d.ts +7 -1
- package/dist/gui/EFTimeDisplay.js +8 -8
- package/dist/gui/EFToggleLoop.d.ts +9 -3
- package/dist/gui/EFToggleLoop.js +7 -5
- package/dist/gui/EFTogglePlay.d.ts +12 -4
- package/dist/gui/EFTogglePlay.js +26 -21
- package/dist/gui/EFWorkbench.js +5 -5
- package/dist/gui/PlaybackController.d.ts +67 -0
- package/dist/gui/PlaybackController.js +310 -0
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin2.js +1 -1
- package/dist/gui/TargetOrContextMixin.d.ts +10 -0
- package/dist/gui/TargetOrContextMixin.js +98 -0
- package/dist/gui/efContext.d.ts +2 -2
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -1
- package/dist/otel/BridgeSpanExporter.d.ts +13 -0
- package/dist/otel/BridgeSpanExporter.js +87 -0
- package/dist/otel/setupBrowserTracing.d.ts +12 -0
- package/dist/otel/setupBrowserTracing.js +32 -0
- package/dist/otel/tracingHelpers.d.ts +34 -0
- package/dist/otel/tracingHelpers.js +112 -0
- package/dist/style.css +1 -1
- package/dist/transcoding/cache/RequestDeduplicator.js +0 -21
- package/dist/transcoding/cache/URLTokenDeduplicator.js +1 -21
- package/dist/transcoding/utils/UrlGenerator.js +2 -19
- package/dist/utils/LRUCache.js +6 -53
- package/package.json +13 -5
- package/src/elements/ContextProxiesController.ts +10 -10
- package/src/elements/EFAudio.ts +1 -0
- package/src/elements/EFCaptions.browsertest.ts +128 -56
- package/src/elements/EFCaptions.ts +60 -34
- package/src/elements/EFImage.browsertest.ts +1 -2
- package/src/elements/EFMedia/AssetMediaEngine.ts +65 -37
- package/src/elements/EFMedia/BaseMediaEngine.ts +110 -52
- package/src/elements/EFMedia/BufferedSeekingInput.ts +218 -101
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +3 -0
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +7 -3
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +1 -1
- package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +76 -0
- package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +16 -10
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +7 -1
- package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +222 -116
- package/src/elements/EFMedia.browsertest.ts +8 -15
- package/src/elements/EFMedia.ts +54 -8
- package/src/elements/EFSurface.browsertest.ts +2 -6
- package/src/elements/EFSurface.ts +1 -0
- package/src/elements/EFTemporal.browsertest.ts +58 -1
- package/src/elements/EFTemporal.ts +140 -4
- package/src/elements/EFThumbnailStrip.browsertest.ts +2 -8
- package/src/elements/EFThumbnailStrip.ts +1 -0
- package/src/elements/EFTimegroup.browsertest.ts +16 -15
- package/src/elements/EFTimegroup.ts +281 -275
- package/src/elements/EFVideo.browsertest.ts +162 -74
- package/src/elements/EFVideo.ts +229 -101
- package/src/elements/FetchContext.browsertest.ts +7 -2
- package/src/elements/TargetController.browsertest.ts +1 -0
- package/src/elements/TargetController.ts +1 -0
- package/src/elements/renderTemporalAudio.ts +108 -0
- package/src/elements/updateAnimations.browsertest.ts +181 -6
- package/src/elements/updateAnimations.ts +6 -6
- package/src/gui/ContextMixin.browsertest.ts +274 -27
- package/src/gui/ContextMixin.ts +230 -175
- package/src/gui/Controllable.browsertest.ts +258 -0
- package/src/gui/Controllable.ts +41 -0
- package/src/gui/EFControls.browsertest.ts +294 -80
- package/src/gui/EFControls.ts +139 -28
- package/src/gui/EFDial.browsertest.ts +84 -0
- package/src/gui/EFDial.ts +172 -0
- package/src/gui/EFFilmstrip.browsertest.ts +712 -0
- package/src/gui/EFFilmstrip.ts +213 -23
- package/src/gui/EFPause.browsertest.ts +202 -0
- package/src/gui/EFPause.ts +73 -0
- package/src/gui/EFPlay.browsertest.ts +202 -0
- package/src/gui/EFPlay.ts +73 -0
- package/src/gui/EFPreview.ts +20 -5
- package/src/gui/EFResizableBox.browsertest.ts +79 -0
- package/src/gui/EFResizableBox.ts +898 -0
- package/src/gui/EFScrubber.ts +7 -5
- package/src/gui/EFTimeDisplay.browsertest.ts +19 -19
- package/src/gui/EFTimeDisplay.ts +3 -1
- package/src/gui/EFToggleLoop.ts +6 -5
- package/src/gui/EFTogglePlay.ts +30 -23
- package/src/gui/PlaybackController.ts +522 -0
- package/src/gui/TWMixin.css +3 -0
- package/src/gui/TargetOrContextMixin.ts +185 -0
- package/src/gui/efContext.ts +2 -2
- package/src/otel/BridgeSpanExporter.ts +150 -0
- package/src/otel/setupBrowserTracing.ts +73 -0
- package/src/otel/tracingHelpers.ts +251 -0
- package/test/cache-integration-verification.browsertest.ts +1 -1
- package/types.json +1 -1
- package/dist/elements/ContextProxiesController.js +0 -69
package/dist/elements/EFVideo.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
|
|
2
2
|
import { TWMixin } from "../gui/TWMixin2.js";
|
|
3
|
+
import { withSpan, withSpanSync } from "../otel/tracingHelpers.js";
|
|
4
|
+
import { EFMedia } from "./EFMedia.js";
|
|
5
|
+
import { updateAnimations } from "./updateAnimations.js";
|
|
3
6
|
import { DelayedLoadingState } from "../DelayedLoadingState.js";
|
|
4
7
|
import { makeScrubVideoBufferTask } from "./EFMedia/videoTasks/makeScrubVideoBufferTask.js";
|
|
5
8
|
import { makeScrubVideoInitSegmentFetchTask } from "./EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js";
|
|
@@ -13,10 +16,10 @@ import { Task } from "@lit/task";
|
|
|
13
16
|
import debug from "debug";
|
|
14
17
|
import { css, html } from "lit";
|
|
15
18
|
import { customElement, property, state } from "lit/decorators.js";
|
|
16
|
-
import
|
|
19
|
+
import { context, trace } from "@opentelemetry/api";
|
|
17
20
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
var log = debug("ef:elements:EFVideo");
|
|
22
|
+
var EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
|
|
20
23
|
static {
|
|
21
24
|
this.styles = [css`
|
|
22
25
|
:host {
|
|
@@ -104,43 +107,33 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
|
|
|
104
107
|
console.error("frameTask error", error);
|
|
105
108
|
},
|
|
106
109
|
onComplete: () => {},
|
|
107
|
-
task: async ([_desiredSeekTimeMs]) => {
|
|
108
|
-
|
|
109
|
-
await
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
},
|
|
120
|
-
onComplete: () => {},
|
|
121
|
-
task: async ([_seekToMs], { signal }) => {
|
|
122
|
-
const isProductionRendering = this.isInProductionRenderingMode();
|
|
123
|
-
try {
|
|
110
|
+
task: async ([_desiredSeekTimeMs], { signal }) => {
|
|
111
|
+
const t0 = performance.now();
|
|
112
|
+
await withSpan("video.frameTask", {
|
|
113
|
+
elementId: this.id || "unknown",
|
|
114
|
+
desiredSeekTimeMs: _desiredSeekTimeMs,
|
|
115
|
+
src: this.src || "none"
|
|
116
|
+
}, void 0, async (span) => {
|
|
117
|
+
const t1 = performance.now();
|
|
118
|
+
span.setAttribute("preworkMs", t1 - t0);
|
|
119
|
+
this.unifiedVideoSeekTask.run();
|
|
120
|
+
const t2 = performance.now();
|
|
121
|
+
span.setAttribute("seekRunMs", t2 - t1);
|
|
124
122
|
await this.unifiedVideoSeekTask.taskComplete;
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
} finally {
|
|
131
|
-
videoFrame.close();
|
|
132
|
-
}
|
|
123
|
+
const t3 = performance.now();
|
|
124
|
+
span.setAttribute("seekAwaitMs", t3 - t2);
|
|
125
|
+
if (signal.aborted) {
|
|
126
|
+
span.setAttribute("aborted", true);
|
|
127
|
+
return;
|
|
133
128
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
if (signal.aborted) return;
|
|
129
|
+
this.paint(this.desiredSeekTimeMs, span);
|
|
130
|
+
if (!this.parentTimegroup) updateAnimations(this);
|
|
131
|
+
const t4 = performance.now();
|
|
132
|
+
this.paint(_desiredSeekTimeMs, span);
|
|
133
|
+
const t5 = performance.now();
|
|
134
|
+
span.setAttribute("paintMs", t5 - t4);
|
|
135
|
+
span.setAttribute("totalFrameMs", t5 - t0);
|
|
136
|
+
});
|
|
144
137
|
}
|
|
145
138
|
});
|
|
146
139
|
this.delayedLoadingState = new DelayedLoadingState(250, (isLoading, message) => {
|
|
@@ -171,23 +164,13 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
|
|
|
171
164
|
if (referencedCanvas) return referencedCanvas;
|
|
172
165
|
const shadowCanvas = this.shadowRoot?.querySelector("canvas");
|
|
173
166
|
if (shadowCanvas) return shadowCanvas;
|
|
174
|
-
return void 0;
|
|
175
167
|
}
|
|
176
|
-
/**
|
|
177
|
-
* Start a delayed loading operation for testing
|
|
178
|
-
*/
|
|
179
168
|
startDelayedLoading(operationId, message, options = {}) {
|
|
180
169
|
this.delayedLoadingState.startLoading(operationId, message, options);
|
|
181
170
|
}
|
|
182
|
-
/**
|
|
183
|
-
* Clear a delayed loading operation for testing
|
|
184
|
-
*/
|
|
185
171
|
clearDelayedLoading(operationId) {
|
|
186
172
|
this.delayedLoadingState.clearLoading(operationId);
|
|
187
173
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Set loading state for user feedback
|
|
190
|
-
*/
|
|
191
174
|
setLoadingState(isLoading, operation = null, message = "") {
|
|
192
175
|
this.loadingState = {
|
|
193
176
|
isLoading,
|
|
@@ -195,96 +178,161 @@ let EFVideo = class EFVideo$1 extends TWMixin(EFMedia) {
|
|
|
195
178
|
message
|
|
196
179
|
};
|
|
197
180
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
181
|
+
paint(seekToMs, parentSpan) {
|
|
182
|
+
const parentContext = parentSpan ? trace.setSpan(context.active(), parentSpan) : void 0;
|
|
183
|
+
withSpanSync("video.paint", {
|
|
184
|
+
elementId: this.id || "unknown",
|
|
185
|
+
seekToMs,
|
|
186
|
+
src: this.src || "none"
|
|
187
|
+
}, parentContext, (span) => {
|
|
188
|
+
const t0 = performance.now();
|
|
189
|
+
const isProductionRendering = this.isInProductionRenderingMode();
|
|
190
|
+
const t1 = performance.now();
|
|
191
|
+
span.setAttribute("isProductionRendering", isProductionRendering);
|
|
192
|
+
span.setAttribute("modeCheckMs", t1 - t0);
|
|
193
|
+
try {
|
|
194
|
+
const t2 = performance.now();
|
|
195
|
+
const videoSample = this.unifiedVideoSeekTask.value;
|
|
196
|
+
span.setAttribute("hasVideoSample", !!videoSample);
|
|
197
|
+
span.setAttribute("valueAccessMs", t2 - t1);
|
|
198
|
+
if (videoSample) {
|
|
199
|
+
const t3 = performance.now();
|
|
200
|
+
const videoFrame = videoSample.toVideoFrame();
|
|
201
|
+
const t4 = performance.now();
|
|
202
|
+
span.setAttribute("toVideoFrameMs", t4 - t3);
|
|
203
|
+
try {
|
|
204
|
+
const t5 = performance.now();
|
|
205
|
+
this.displayFrame(videoFrame, seekToMs, span);
|
|
206
|
+
const t6 = performance.now();
|
|
207
|
+
span.setAttribute("displayFrameMs", t6 - t5);
|
|
208
|
+
} finally {
|
|
209
|
+
videoFrame.close();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} catch (error) {
|
|
213
|
+
console.warn("Unified video pipeline error:", error);
|
|
214
|
+
}
|
|
215
|
+
if (!isProductionRendering) {
|
|
216
|
+
if (!this.rootTimegroup || this.rootTimegroup.currentTimeMs === 0 && this.desiredSeekTimeMs === 0) {
|
|
217
|
+
span.setAttribute("skipped", "preview-initialization");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
if (!this.rootTimegroup) {
|
|
222
|
+
span.setAttribute("skipped", "no-root-timegroup");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (!this.isFrameRenderingActive()) {
|
|
226
|
+
span.setAttribute("skipped", "frame-rendering-not-active");
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const tEnd = performance.now();
|
|
231
|
+
span.setAttribute("totalPaintMs", tEnd - t0);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
201
234
|
clearCanvas() {
|
|
202
235
|
if (!this.canvasElement) return;
|
|
203
236
|
const ctx = this.canvasElement.getContext("2d");
|
|
204
237
|
if (ctx) ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
|
|
205
238
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
log("trace: displayFrame start", {
|
|
239
|
+
displayFrame(frame, seekToMs, parentSpan) {
|
|
240
|
+
const parentContext = parentSpan ? trace.setSpan(context.active(), parentSpan) : void 0;
|
|
241
|
+
withSpanSync("video.displayFrame", {
|
|
242
|
+
elementId: this.id || "unknown",
|
|
211
243
|
seekToMs,
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (this.canvasElement.width !== frame.codedWidth || this.canvasElement.height !== frame.codedHeight) {
|
|
225
|
-
log("trace: updating canvas dimensions", {
|
|
226
|
-
width: frame.codedWidth,
|
|
227
|
-
height: frame.codedHeight
|
|
228
|
-
});
|
|
229
|
-
this.canvasElement.width = frame.codedWidth;
|
|
230
|
-
this.canvasElement.height = frame.codedHeight;
|
|
244
|
+
format: frame.format || "unknown",
|
|
245
|
+
width: frame.codedWidth,
|
|
246
|
+
height: frame.codedHeight
|
|
247
|
+
}, parentContext, (span) => {
|
|
248
|
+
const t0 = performance.now();
|
|
249
|
+
log("trace: displayFrame start", {
|
|
250
|
+
seekToMs,
|
|
251
|
+
frameFormat: frame.format
|
|
252
|
+
});
|
|
253
|
+
if (!this.canvasElement) {
|
|
254
|
+
log("trace: displayFrame aborted - no canvas element");
|
|
255
|
+
throw new Error(`Frame display failed: Canvas element is not available at time ${seekToMs}ms. The video component may not be properly initialized.`);
|
|
231
256
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
257
|
+
const t1 = performance.now();
|
|
258
|
+
span.setAttribute("getCanvasMs", Math.round((t1 - t0) * 100) / 100);
|
|
259
|
+
const ctx = this.canvasElement.getContext("2d");
|
|
260
|
+
const t2 = performance.now();
|
|
261
|
+
span.setAttribute("getCtxMs", Math.round((t2 - t1) * 100) / 100);
|
|
262
|
+
if (!ctx) {
|
|
263
|
+
log("trace: displayFrame aborted - no canvas context");
|
|
264
|
+
throw new Error(`Frame display failed: Unable to get 2D canvas context at time ${seekToMs}ms. This may indicate a browser compatibility issue or canvas corruption.`);
|
|
265
|
+
}
|
|
266
|
+
let resized = false;
|
|
267
|
+
if (frame?.codedWidth && frame?.codedHeight) {
|
|
268
|
+
if (this.canvasElement.width !== frame.codedWidth || this.canvasElement.height !== frame.codedHeight) {
|
|
269
|
+
log("trace: updating canvas dimensions", {
|
|
270
|
+
width: frame.codedWidth,
|
|
271
|
+
height: frame.codedHeight
|
|
272
|
+
});
|
|
273
|
+
this.canvasElement.width = frame.codedWidth;
|
|
274
|
+
this.canvasElement.height = frame.codedHeight;
|
|
275
|
+
resized = true;
|
|
276
|
+
const t3 = performance.now();
|
|
277
|
+
span.setAttribute("resizeMs", Math.round((t3 - t2) * 100) / 100);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
span.setAttribute("canvasResized", resized);
|
|
281
|
+
if (frame.format === null) {
|
|
282
|
+
log("trace: displayFrame aborted - null frame format");
|
|
283
|
+
throw new Error(`Frame display failed: Video frame has null format at time ${seekToMs}ms. This indicates corrupted or incompatible video data.`);
|
|
284
|
+
}
|
|
285
|
+
const tDrawStart = performance.now();
|
|
286
|
+
ctx.drawImage(frame, 0, 0, this.canvasElement.width, this.canvasElement.height);
|
|
287
|
+
const tDrawEnd = performance.now();
|
|
288
|
+
span.setAttribute("drawImageMs", Math.round((tDrawEnd - tDrawStart) * 100) / 100);
|
|
289
|
+
span.setAttribute("totalDisplayMs", Math.round((tDrawEnd - t0) * 100) / 100);
|
|
290
|
+
span.setAttribute("canvasWidth", this.canvasElement.width);
|
|
291
|
+
span.setAttribute("canvasHeight", this.canvasElement.height);
|
|
292
|
+
log("trace: frame drawn to canvas", { seekToMs });
|
|
293
|
+
});
|
|
240
294
|
}
|
|
241
|
-
/**
|
|
242
|
-
* Check if we're in production rendering mode (EF_FRAMEGEN active) vs preview mode
|
|
243
|
-
*/
|
|
244
295
|
isInProductionRenderingMode() {
|
|
245
296
|
if (typeof window.EF_RENDERING === "function") return window.EF_RENDERING();
|
|
246
|
-
|
|
247
|
-
if (workbench?.rendering) return true;
|
|
297
|
+
if (document.querySelector("ef-workbench")?.rendering) return true;
|
|
248
298
|
if (window.EF_FRAMEGEN?.renderOptions) return true;
|
|
249
299
|
return false;
|
|
250
300
|
}
|
|
251
|
-
/**
|
|
252
|
-
* Check if EF_FRAMEGEN has explicitly started frame rendering (not just initialization)
|
|
253
|
-
*/
|
|
254
301
|
isFrameRenderingActive() {
|
|
255
302
|
if (!window.EF_FRAMEGEN?.renderOptions) return false;
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
const currentTime = this.rootTimegroup?.currentTimeMs || 0;
|
|
259
|
-
return currentTime >= renderStartTime;
|
|
303
|
+
const renderStartTime = window.EF_FRAMEGEN.renderOptions.encoderOptions.fromMs;
|
|
304
|
+
return (this.rootTimegroup?.currentTimeMs || 0) >= renderStartTime;
|
|
260
305
|
}
|
|
261
|
-
/**
|
|
262
|
-
* Legacy getter for fragment index task
|
|
263
|
-
* Still used by EFCaptions - maps to unified video seek task
|
|
264
|
-
*/
|
|
265
306
|
get fragmentIndexTask() {
|
|
266
307
|
return this.unifiedVideoSeekTask;
|
|
267
308
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
309
|
+
async waitForFrameReady() {
|
|
310
|
+
await this.updateComplete;
|
|
311
|
+
await this.frameTask.run();
|
|
312
|
+
}
|
|
271
313
|
disconnectedCallback() {
|
|
272
314
|
super.disconnectedCallback();
|
|
273
315
|
this.delayedLoadingState.clearAllLoading();
|
|
274
316
|
}
|
|
317
|
+
didBecomeRoot() {
|
|
318
|
+
super.didBecomeRoot();
|
|
319
|
+
}
|
|
320
|
+
didBecomeChild() {
|
|
321
|
+
super.didBecomeChild();
|
|
322
|
+
}
|
|
275
323
|
};
|
|
276
|
-
|
|
324
|
+
__decorate([property({
|
|
277
325
|
type: Number,
|
|
278
326
|
attribute: "video-buffer-duration"
|
|
279
327
|
})], EFVideo.prototype, "videoBufferDurationMs", void 0);
|
|
280
|
-
|
|
328
|
+
__decorate([property({
|
|
281
329
|
type: Number,
|
|
282
330
|
attribute: "max-video-buffer-fetches"
|
|
283
331
|
})], EFVideo.prototype, "maxVideoBufferFetches", void 0);
|
|
284
|
-
|
|
332
|
+
__decorate([property({
|
|
285
333
|
type: Boolean,
|
|
286
334
|
attribute: "enable-video-buffering"
|
|
287
335
|
})], EFVideo.prototype, "enableVideoBuffering", void 0);
|
|
288
|
-
|
|
289
|
-
EFVideo =
|
|
336
|
+
__decorate([state()], EFVideo.prototype, "loadingState", void 0);
|
|
337
|
+
EFVideo = __decorate([customElement("ef-video")], EFVideo);
|
|
290
338
|
export { EFVideo };
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
2
|
+
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.94.0/helpers/decorate.js";
|
|
2
3
|
import { EFTemporal } from "./EFTemporal.js";
|
|
3
|
-
import { TargetController } from "./TargetController.js";
|
|
4
4
|
import { TWMixin } from "../gui/TWMixin2.js";
|
|
5
|
+
import { TargetController } from "./TargetController.js";
|
|
5
6
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
6
7
|
import { Task } from "@lit/task";
|
|
7
8
|
import { LitElement, css, html } from "lit";
|
|
8
9
|
import { customElement, property, state } from "lit/decorators.js";
|
|
9
|
-
import _decorate from "@oxc-project/runtime/helpers/decorate";
|
|
10
10
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
11
11
|
import { CSSStyleObserver } from "@bramus/style-observer";
|
|
12
|
-
|
|
12
|
+
var EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
13
13
|
constructor(..._args) {
|
|
14
14
|
super(..._args);
|
|
15
15
|
this.canvasRef = createRef();
|
|
@@ -38,8 +38,7 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
38
38
|
if (!frequencyData || !byteTimeData) return;
|
|
39
39
|
ctx.save();
|
|
40
40
|
if (this.color === "currentColor") {
|
|
41
|
-
const
|
|
42
|
-
const currentColor = computedStyle.color;
|
|
41
|
+
const currentColor = getComputedStyle(this).color;
|
|
43
42
|
ctx.strokeStyle = currentColor;
|
|
44
43
|
ctx.fillStyle = currentColor;
|
|
45
44
|
} else {
|
|
@@ -150,13 +149,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
150
149
|
const totalBars = frequencyData.length;
|
|
151
150
|
const paddingInner = this.barSpacing;
|
|
152
151
|
const paddingOuter = .01;
|
|
153
|
-
const
|
|
154
|
-
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
152
|
+
const barWidth = waveWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
155
153
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
156
154
|
const path = new Path2D();
|
|
157
155
|
frequencyData.forEach((value, i) => {
|
|
158
|
-
const
|
|
159
|
-
const barHeight = normalizedValue * waveHeight;
|
|
156
|
+
const barHeight = value / 255 * waveHeight;
|
|
160
157
|
const y = (waveHeight - barHeight) / 2;
|
|
161
158
|
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
162
159
|
path.rect(x, y, barWidth, barHeight);
|
|
@@ -191,13 +188,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
191
188
|
const totalBars = frequencyData.length;
|
|
192
189
|
const paddingInner = this.barSpacing;
|
|
193
190
|
const paddingOuter = .01;
|
|
194
|
-
const
|
|
195
|
-
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
191
|
+
const barWidth = waveWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
196
192
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
197
193
|
const path = new Path2D();
|
|
198
194
|
frequencyData.forEach((value, i) => {
|
|
199
|
-
const
|
|
200
|
-
const height = normalizedValue * waveHeight;
|
|
195
|
+
const height = value / 255 * waveHeight;
|
|
201
196
|
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
202
197
|
const y = (waveHeight - height) / 2;
|
|
203
198
|
path.roundRect(x, y, barWidth, height, barWidth / 2);
|
|
@@ -276,14 +271,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
276
271
|
frequencyData.forEach((value, i) => {
|
|
277
272
|
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
278
273
|
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
279
|
-
const
|
|
280
|
-
const y = (waveHeight - barHeight) / 2;
|
|
274
|
+
const y = (waveHeight - normalizedValue * waveHeight) / 2;
|
|
281
275
|
if (i === 0) path.moveTo(x, y);
|
|
282
276
|
else {
|
|
283
277
|
const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
|
|
284
|
-
const
|
|
285
|
-
const prevBarHeight = prevValue * waveHeight;
|
|
286
|
-
const prevY = (waveHeight - prevBarHeight) / 2;
|
|
278
|
+
const prevY = (waveHeight - Math.min((frequencyData[i - 1] ?? 0) / 255 * 2, 1) * waveHeight) / 2;
|
|
287
279
|
const xc = (prevX + x) / 2;
|
|
288
280
|
const yc = (prevY + y) / 2;
|
|
289
281
|
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
@@ -292,14 +284,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
292
284
|
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
293
285
|
const normalizedValue = Math.min((frequencyData[i] ?? 0) / 255 * 2, 1);
|
|
294
286
|
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
295
|
-
const
|
|
296
|
-
const y = (waveHeight + barHeight) / 2;
|
|
287
|
+
const y = (waveHeight + normalizedValue * waveHeight) / 2;
|
|
297
288
|
if (i === frequencyData.length - 1) path.lineTo(x, y);
|
|
298
289
|
else {
|
|
299
290
|
const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
|
|
300
|
-
const
|
|
301
|
-
const nextBarHeight = nextValue * waveHeight;
|
|
302
|
-
const nextY = (waveHeight + nextBarHeight) / 2;
|
|
291
|
+
const nextY = (waveHeight + Math.min((frequencyData[i + 1] ?? 0) / 255 * 2, 1) * waveHeight) / 2;
|
|
303
292
|
const xc = (nextX + x) / 2;
|
|
304
293
|
const yc = (nextY + y) / 2;
|
|
305
294
|
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
@@ -326,14 +315,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
326
315
|
frequencyData.forEach((value, i) => {
|
|
327
316
|
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
328
317
|
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
329
|
-
const
|
|
330
|
-
const y = (waveHeight - barHeight * 2) / 2;
|
|
318
|
+
const y = (waveHeight - normalizedValue * (waveHeight / 2) * 2) / 2;
|
|
331
319
|
if (i === 0) path.moveTo(x, y);
|
|
332
320
|
else {
|
|
333
321
|
const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
|
|
334
|
-
const
|
|
335
|
-
const prevBarHeight = prevValue * (waveHeight / 2);
|
|
336
|
-
const prevY = (waveHeight - prevBarHeight * 2) / 2;
|
|
322
|
+
const prevY = (waveHeight - (frequencyData[i - 1] ?? 0) / 255 * (waveHeight / 2) * 2) / 2;
|
|
337
323
|
const xc = (prevX + x) / 2;
|
|
338
324
|
const yc = (prevY + y) / 2;
|
|
339
325
|
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
@@ -342,14 +328,11 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
342
328
|
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
343
329
|
const normalizedValue = Math.min((frequencyData[i] ?? 0) / 255 * 2, 1);
|
|
344
330
|
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
345
|
-
const
|
|
346
|
-
const y = (waveHeight + barHeight * 2) / 2;
|
|
331
|
+
const y = (waveHeight + normalizedValue * (waveHeight / 2) * 2) / 2;
|
|
347
332
|
if (i === frequencyData.length - 1) path.lineTo(x, y);
|
|
348
333
|
else {
|
|
349
334
|
const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
|
|
350
|
-
const
|
|
351
|
-
const nextBarHeight = nextValue * (waveHeight / 2);
|
|
352
|
-
const nextY = (waveHeight + nextBarHeight * 2) / 2;
|
|
335
|
+
const nextY = (waveHeight + (frequencyData[i + 1] ?? 0) / 255 * (waveHeight / 2) * 2) / 2;
|
|
353
336
|
const xc = (nextX + x) / 2;
|
|
354
337
|
const yc = (nextY + y) / 2;
|
|
355
338
|
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
@@ -370,23 +353,23 @@ let EFWaveform = class EFWaveform$1 extends EFTemporal(TWMixin(LitElement)) {
|
|
|
370
353
|
if (changedProperties.size > 0) this.frameTask.run();
|
|
371
354
|
}
|
|
372
355
|
};
|
|
373
|
-
|
|
356
|
+
__decorate([property({
|
|
374
357
|
type: String,
|
|
375
358
|
attribute: "mode"
|
|
376
359
|
})], EFWaveform.prototype, "mode", void 0);
|
|
377
|
-
|
|
378
|
-
|
|
360
|
+
__decorate([property({ type: String })], EFWaveform.prototype, "color", void 0);
|
|
361
|
+
__decorate([property({
|
|
379
362
|
type: String,
|
|
380
363
|
reflect: true
|
|
381
364
|
})], EFWaveform.prototype, "target", void 0);
|
|
382
|
-
|
|
365
|
+
__decorate([property({
|
|
383
366
|
type: Number,
|
|
384
367
|
attribute: "bar-spacing"
|
|
385
368
|
})], EFWaveform.prototype, "barSpacing", void 0);
|
|
386
|
-
|
|
387
|
-
|
|
369
|
+
__decorate([state()], EFWaveform.prototype, "targetElement", void 0);
|
|
370
|
+
__decorate([property({
|
|
388
371
|
type: Number,
|
|
389
372
|
attribute: "line-width"
|
|
390
373
|
})], EFWaveform.prototype, "lineWidth", void 0);
|
|
391
|
-
EFWaveform =
|
|
374
|
+
EFWaveform = __decorate([customElement("ef-waveform")], EFWaveform);
|
|
392
375
|
export { EFWaveform };
|
|
@@ -23,8 +23,7 @@ var SampleBuffer = class {
|
|
|
23
23
|
} catch (_error) {}
|
|
24
24
|
}
|
|
25
25
|
peek() {
|
|
26
|
-
|
|
27
|
-
return currentBuffer[0];
|
|
26
|
+
return this.buffer[0];
|
|
28
27
|
}
|
|
29
28
|
find(desiredSeekTimeMs) {
|
|
30
29
|
const currentBuffer = [...this.buffer];
|
|
@@ -32,18 +31,15 @@ var SampleBuffer = class {
|
|
|
32
31
|
const targetTimeMs = roundToMilliseconds(desiredSeekTimeMs);
|
|
33
32
|
for (const sample of currentBuffer) {
|
|
34
33
|
const sampleStartMs = roundToMilliseconds((sample.timestamp || 0) * 1e3);
|
|
35
|
-
const
|
|
36
|
-
const sampleEndMs = roundToMilliseconds(sampleStartMs + sampleDurationMs);
|
|
34
|
+
const sampleEndMs = roundToMilliseconds(sampleStartMs + roundToMilliseconds((sample.duration || 0) * 1e3));
|
|
37
35
|
if (targetTimeMs >= sampleStartMs && targetTimeMs < sampleEndMs) return sample;
|
|
38
36
|
}
|
|
39
|
-
return void 0;
|
|
40
37
|
}
|
|
41
38
|
get length() {
|
|
42
39
|
return this.buffer.length;
|
|
43
40
|
}
|
|
44
41
|
get firstTimestamp() {
|
|
45
|
-
|
|
46
|
-
return currentBuffer[0]?.timestamp || 0;
|
|
42
|
+
return this.buffer[0]?.timestamp || 0;
|
|
47
43
|
}
|
|
48
44
|
getContents() {
|
|
49
45
|
return [...this.buffer];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LitElement } from "lit";
|
|
2
|
-
|
|
2
|
+
var EF_TARGETABLE = Symbol("EF_TARGETABLE");
|
|
3
3
|
var TargetRegistry = class {
|
|
4
4
|
constructor() {
|
|
5
5
|
this.idMap = /* @__PURE__ */ new Map();
|
|
@@ -28,8 +28,8 @@ var TargetRegistry = class {
|
|
|
28
28
|
this.callbacks.delete(id);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
var documentRegistries = /* @__PURE__ */ new WeakMap();
|
|
32
|
+
var getRegistry = (root) => {
|
|
33
33
|
let registry = documentRegistries.get(root);
|
|
34
34
|
if (!registry) {
|
|
35
35
|
registry = new TargetRegistry();
|
|
@@ -103,6 +103,7 @@ var TargetController = class {
|
|
|
103
103
|
this.disconnectFromTarget();
|
|
104
104
|
this.host.targetElement = newTarget ?? null;
|
|
105
105
|
this.connectToTarget();
|
|
106
|
+
this.host.requestUpdate("targetElement");
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
connectToTarget() {
|
|
@@ -118,8 +119,7 @@ var TargetController = class {
|
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
get registry() {
|
|
121
|
-
|
|
122
|
-
return getRegistry(root);
|
|
122
|
+
return getRegistry(this.host.getRootNode());
|
|
123
123
|
}
|
|
124
124
|
hostDisconnected() {
|
|
125
125
|
this.disconnectFromTarget();
|
|
@@ -3,7 +3,7 @@ const durationConverter = {
|
|
|
3
3
|
fromAttribute: (value) => value === null ? null : parseTimeToMs(value),
|
|
4
4
|
toAttribute: (value) => value === null ? null : `${value}s`
|
|
5
5
|
};
|
|
6
|
-
|
|
6
|
+
var positiveDurationConverter = (error) => {
|
|
7
7
|
return {
|
|
8
8
|
fromAttribute: (value) => {
|
|
9
9
|
if (value === null) return null;
|
|
@@ -13,7 +13,7 @@ const positiveDurationConverter = (error) => {
|
|
|
13
13
|
toAttribute: (value) => value === null ? null : `${value}s`
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
positiveDurationConverter("Trimstart & trimend must be a positive value in milliseconds or seconds (1s, 1000ms)");
|
|
17
|
+
positiveDurationConverter("Image duration must be a positive value in milliseconds or seconds (1s, 1000ms)");
|
|
18
|
+
positiveDurationConverter("Sourcein & sourceout must be a positive value in milliseconds or seconds (1s, 1000ms)");
|
|
19
19
|
export { durationConverter };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { EFMedia } from './EFMedia.js';
|
|
2
|
+
interface TemporalAudioHost {
|
|
3
|
+
startTimeMs: number;
|
|
4
|
+
endTimeMs: number;
|
|
5
|
+
durationMs: number;
|
|
6
|
+
getMediaElements(): EFMedia[];
|
|
7
|
+
waitForMediaDurations?(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function renderTemporalAudio(host: TemporalAudioHost, fromMs: number, toMs: number): Promise<AudioBuffer>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
async function renderTemporalAudio(host, fromMs, toMs) {
|
|
2
|
+
const aacFrames = 48e3 * ((toMs - fromMs) / 1e3) / 1024;
|
|
3
|
+
const contextSize = Math.round(aacFrames) * 1024;
|
|
4
|
+
if (contextSize <= 0) throw new Error(`Duration must be greater than 0 when rendering audio. ${contextSize}ms`);
|
|
5
|
+
const audioContext = new OfflineAudioContext(2, contextSize, 48e3);
|
|
6
|
+
if (host.waitForMediaDurations) await host.waitForMediaDurations();
|
|
7
|
+
const abortController = new AbortController();
|
|
8
|
+
await Promise.all(host.getMediaElements().map(async (mediaElement) => {
|
|
9
|
+
if (mediaElement.mute) return;
|
|
10
|
+
const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
|
|
11
|
+
const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
|
|
12
|
+
if (!(mediaStartsBeforeEnd && mediaEndsAfterStart)) return;
|
|
13
|
+
const mediaLocalFromMs = Math.max(0, fromMs - mediaElement.startTimeMs);
|
|
14
|
+
const mediaLocalToMs = Math.min(mediaElement.endTimeMs - mediaElement.startTimeMs, toMs - mediaElement.startTimeMs);
|
|
15
|
+
if (mediaLocalFromMs >= mediaLocalToMs) return;
|
|
16
|
+
const sourceInMs = mediaElement.sourceInMs || mediaElement.trimStartMs || 0;
|
|
17
|
+
const mediaSourceFromMs = mediaLocalFromMs + sourceInMs;
|
|
18
|
+
const mediaSourceToMs = mediaLocalToMs + sourceInMs;
|
|
19
|
+
const audio = await mediaElement.fetchAudioSpanningTime(mediaSourceFromMs, mediaSourceToMs, abortController.signal);
|
|
20
|
+
if (!audio) return;
|
|
21
|
+
const bufferSource = audioContext.createBufferSource();
|
|
22
|
+
bufferSource.buffer = await audioContext.decodeAudioData(await audio.blob.arrayBuffer());
|
|
23
|
+
bufferSource.connect(audioContext.destination);
|
|
24
|
+
const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
|
|
25
|
+
const offsetInBufferMs = mediaSourceFromMs - audio.startMs;
|
|
26
|
+
const safeOffsetMs = Math.max(0, offsetInBufferMs);
|
|
27
|
+
const requestedDurationMs = mediaSourceToMs - mediaSourceFromMs;
|
|
28
|
+
const availableAudioMs = audio.endMs - audio.startMs;
|
|
29
|
+
const actualDurationMs = Math.min(requestedDurationMs, availableAudioMs - safeOffsetMs);
|
|
30
|
+
if (actualDurationMs <= 0) return;
|
|
31
|
+
bufferSource.start(ctxStartMs / 1e3, safeOffsetMs / 1e3, actualDurationMs / 1e3);
|
|
32
|
+
}));
|
|
33
|
+
return audioContext.startRendering();
|
|
34
|
+
}
|
|
35
|
+
export { renderTemporalAudio };
|