@editframe/elements 0.33.0-beta → 0.34.6-beta
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/EF_FRAMEGEN.js +5 -3
- package/dist/EF_FRAMEGEN.js.map +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.94.0 → _@oxc-project_runtime@0.95.0}/helpers/decorate.js +1 -1
- package/dist/canvas/EFCanvas.d.ts +7 -4
- package/dist/canvas/EFCanvas.js +1 -1
- package/dist/canvas/EFCanvasItem.d.ts +4 -4
- package/dist/canvas/EFCanvasItem.js +1 -1
- package/dist/canvas/overlays/SelectionOverlay.d.ts +95 -0
- package/dist/canvas/overlays/SelectionOverlay.js +1 -1
- package/dist/canvas/selection/SelectionController.js +7 -11
- package/dist/canvas/selection/SelectionController.js.map +1 -1
- package/dist/elements/EFAudio.d.ts +25 -7
- package/dist/elements/EFAudio.js +31 -61
- package/dist/elements/EFAudio.js.map +1 -1
- package/dist/elements/EFCaptions.d.ts +65 -52
- package/dist/elements/EFCaptions.js +186 -400
- package/dist/elements/EFCaptions.js.map +1 -1
- package/dist/elements/EFImage.d.ts +34 -6
- package/dist/elements/EFImage.js +114 -79
- package/dist/elements/EFImage.js.map +1 -1
- package/dist/elements/EFMedia/AssetIdMediaEngine.js +17 -17
- package/dist/elements/EFMedia/AssetIdMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/AssetMediaEngine.js +41 -25
- package/dist/elements/EFMedia/AssetMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BaseMediaEngine.js +4 -4
- package/dist/elements/EFMedia/BaseMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js +1 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.js.map +1 -1
- package/dist/elements/EFMedia/JitMediaEngine.js +31 -17
- package/dist/elements/EFMedia/JitMediaEngine.js.map +1 -1
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js +3 -3
- package/dist/elements/EFMedia/shared/AudioSpanUtils.js.map +1 -1
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +17 -9
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js.map +1 -1
- package/dist/elements/EFMedia.d.ts +66 -20
- package/dist/elements/EFMedia.js +412 -30
- package/dist/elements/EFMedia.js.map +1 -1
- package/dist/elements/EFPanZoom.d.ts +4 -4
- package/dist/elements/EFPanZoom.js +1 -1
- package/dist/elements/EFSourceMixin.js +43 -15
- package/dist/elements/EFSourceMixin.js.map +1 -1
- package/dist/elements/EFSurface.d.ts +23 -10
- package/dist/elements/EFSurface.js +64 -22
- package/dist/elements/EFSurface.js.map +1 -1
- package/dist/elements/EFTemporal.d.ts +8 -2
- package/dist/elements/EFTemporal.js +42 -31
- package/dist/elements/EFTemporal.js.map +1 -1
- package/dist/elements/EFText.d.ts +5 -4
- package/dist/elements/EFText.js +11 -2
- package/dist/elements/EFText.js.map +1 -1
- package/dist/elements/EFTextSegment.d.ts +4 -4
- package/dist/elements/EFTextSegment.js +1 -1
- package/dist/elements/EFThumbnailStrip.d.ts +4 -4
- package/dist/elements/EFThumbnailStrip.js +1 -1
- package/dist/elements/EFTimegroup.d.ts +22 -8
- package/dist/elements/EFTimegroup.js +203 -115
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/dist/elements/EFVideo.d.ts +57 -20
- package/dist/elements/EFVideo.js +324 -72
- package/dist/elements/EFVideo.js.map +1 -1
- package/dist/elements/EFWaveform.d.ts +33 -7
- package/dist/elements/EFWaveform.js +103 -59
- package/dist/elements/EFWaveform.js.map +1 -1
- package/dist/elements/renderTemporalAudio.js +14 -3
- package/dist/elements/renderTemporalAudio.js.map +1 -1
- package/dist/getRenderInfo.d.ts +2 -2
- package/dist/gui/ContextMixin.js +1 -1
- package/dist/gui/Controllable.d.ts +2 -0
- package/dist/gui/EFActiveRootTemporal.d.ts +4 -4
- package/dist/gui/EFActiveRootTemporal.js +1 -1
- package/dist/gui/EFConfiguration.d.ts +4 -4
- package/dist/gui/EFConfiguration.js +1 -1
- package/dist/gui/EFControls.d.ts +2 -2
- package/dist/gui/EFControls.js +1 -1
- package/dist/gui/EFDial.d.ts +4 -4
- package/dist/gui/EFDial.js +1 -1
- package/dist/gui/EFFilmstrip.d.ts +3 -2
- package/dist/gui/EFFilmstrip.js +1 -1
- package/dist/gui/EFFitScale.js +1 -1
- package/dist/gui/EFFocusOverlay.d.ts +4 -4
- package/dist/gui/EFFocusOverlay.js +1 -1
- package/dist/gui/EFOverlayItem.d.ts +4 -4
- package/dist/gui/EFOverlayItem.js +1 -1
- package/dist/gui/EFOverlayLayer.d.ts +4 -4
- package/dist/gui/EFOverlayLayer.js +1 -1
- package/dist/gui/EFPause.d.ts +4 -4
- package/dist/gui/EFPause.js +1 -1
- package/dist/gui/EFPlay.d.ts +4 -4
- package/dist/gui/EFPlay.js +1 -1
- package/dist/gui/EFPreview.d.ts +4 -4
- package/dist/gui/EFPreview.js +1 -1
- package/dist/gui/EFResizableBox.d.ts +4 -4
- package/dist/gui/EFResizableBox.js +1 -1
- package/dist/gui/EFScrubber.d.ts +4 -4
- package/dist/gui/EFScrubber.js +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +4 -4
- package/dist/gui/EFTimeDisplay.js +1 -1
- package/dist/gui/EFTimelineRuler.d.ts +4 -4
- package/dist/gui/EFTimelineRuler.js +1 -1
- package/dist/gui/EFToggleLoop.d.ts +4 -4
- package/dist/gui/EFToggleLoop.js +1 -1
- package/dist/gui/EFTogglePlay.d.ts +4 -4
- package/dist/gui/EFTogglePlay.js +1 -1
- package/dist/gui/EFTransformHandles.d.ts +4 -4
- package/dist/gui/EFTransformHandles.js +1 -1
- package/dist/gui/EFWorkbench.d.ts +5 -4
- package/dist/gui/EFWorkbench.js +1 -1
- package/dist/gui/PlaybackController.d.ts +10 -2
- package/dist/gui/PlaybackController.js +52 -30
- package/dist/gui/PlaybackController.js.map +1 -1
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/gui/TargetOrContextMixin.js +1 -1
- package/dist/gui/hierarchy/EFHierarchy.d.ts +4 -4
- package/dist/gui/hierarchy/EFHierarchy.js +1 -1
- package/dist/gui/hierarchy/EFHierarchyItem.d.ts +3 -3
- package/dist/gui/hierarchy/EFHierarchyItem.js +1 -1
- package/dist/gui/timeline/EFTimeline.d.ts +6 -2
- package/dist/gui/timeline/EFTimeline.js +1 -1
- package/dist/gui/timeline/EFTimelineRow.d.ts +57 -0
- package/dist/gui/timeline/EFTimelineRow.js +1 -1
- package/dist/gui/timeline/TrimHandles.d.ts +4 -4
- package/dist/gui/timeline/TrimHandles.js +1 -1
- package/dist/gui/timeline/tracks/AudioTrack.d.ts +2 -0
- package/dist/gui/timeline/tracks/AudioTrack.js +1 -1
- package/dist/gui/timeline/tracks/CaptionsTrack.d.ts +58 -0
- package/dist/gui/timeline/tracks/CaptionsTrack.js +1 -1
- package/dist/gui/timeline/tracks/HTMLTrack.d.ts +13 -0
- package/dist/gui/timeline/tracks/HTMLTrack.js +1 -1
- package/dist/gui/timeline/tracks/ImageTrack.d.ts +14 -0
- package/dist/gui/timeline/tracks/ImageTrack.js +1 -1
- package/dist/gui/timeline/tracks/TextTrack.d.ts +26 -0
- package/dist/gui/timeline/tracks/TextTrack.js +1 -1
- package/dist/gui/timeline/tracks/TimegroupTrack.d.ts +47 -0
- package/dist/gui/timeline/tracks/TimegroupTrack.js +4 -12
- package/dist/gui/timeline/tracks/TimegroupTrack.js.map +1 -1
- package/dist/gui/timeline/tracks/TrackItem.d.ts +81 -0
- package/dist/gui/timeline/tracks/TrackItem.js +1 -1
- package/dist/gui/timeline/tracks/VideoTrack.d.ts +25 -0
- package/dist/gui/timeline/tracks/VideoTrack.js +1 -1
- package/dist/gui/timeline/tracks/WaveformTrack.d.ts +14 -0
- package/dist/gui/timeline/tracks/WaveformTrack.js +1 -1
- package/dist/gui/timeline/tracks/ensureTrackItemInit.d.ts +1 -0
- package/dist/gui/timeline/tracks/preloadTracks.d.ts +9 -0
- package/dist/gui/tree/EFTree.d.ts +5 -4
- package/dist/gui/tree/EFTree.js +1 -1
- package/dist/gui/tree/EFTreeItem.d.ts +4 -4
- package/dist/gui/tree/EFTreeItem.js +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/preview/AdaptiveResolutionTracker.js +6 -14
- package/dist/preview/AdaptiveResolutionTracker.js.map +1 -1
- package/dist/preview/FrameController.d.ts +123 -0
- package/dist/preview/FrameController.js +216 -0
- package/dist/preview/FrameController.js.map +1 -0
- package/dist/preview/RenderContext.d.ts +1 -0
- package/dist/preview/RenderContext.js +193 -0
- package/dist/preview/RenderContext.js.map +1 -0
- package/dist/preview/encoding/canvasEncoder.js +166 -0
- package/dist/preview/encoding/canvasEncoder.js.map +1 -0
- package/dist/preview/encoding/mainThreadEncoder.js +39 -0
- package/dist/preview/encoding/mainThreadEncoder.js.map +1 -0
- package/dist/preview/encoding/types.d.ts +1 -0
- package/dist/preview/encoding/workerEncoder.js +58 -0
- package/dist/preview/encoding/workerEncoder.js.map +1 -0
- package/dist/preview/logger.js +41 -0
- package/dist/preview/logger.js.map +1 -0
- package/dist/preview/previewTypes.js +11 -10
- package/dist/preview/previewTypes.js.map +1 -1
- package/dist/preview/renderTimegroupPreview.js +259 -236
- package/dist/preview/renderTimegroupPreview.js.map +1 -1
- package/dist/preview/renderTimegroupToCanvas.d.ts +5 -0
- package/dist/preview/renderTimegroupToCanvas.js +100 -489
- package/dist/preview/renderTimegroupToCanvas.js.map +1 -1
- package/dist/preview/renderTimegroupToVideo.d.ts +1 -0
- package/dist/preview/renderTimegroupToVideo.js +80 -22
- package/dist/preview/renderTimegroupToVideo.js.map +1 -1
- package/dist/preview/renderers.js.map +1 -1
- package/dist/preview/rendering/inlineImages.js +56 -0
- package/dist/preview/rendering/inlineImages.js.map +1 -0
- package/dist/preview/rendering/renderToImage.d.ts +1 -0
- package/dist/preview/rendering/renderToImage.js +120 -0
- package/dist/preview/rendering/renderToImage.js.map +1 -0
- package/dist/preview/rendering/renderToImageForeignObject.js +135 -0
- package/dist/preview/rendering/renderToImageForeignObject.js.map +1 -0
- package/dist/preview/rendering/renderToImageNative.d.ts +1 -0
- package/dist/preview/rendering/renderToImageNative.js +129 -0
- package/dist/preview/rendering/renderToImageNative.js.map +1 -0
- package/dist/preview/rendering/svgSerializer.js +43 -0
- package/dist/preview/rendering/svgSerializer.js.map +1 -0
- package/dist/preview/rendering/types.d.ts +2 -0
- package/dist/preview/statsTrackingStrategy.js +3 -1
- package/dist/preview/statsTrackingStrategy.js.map +1 -1
- package/dist/preview/workers/WorkerPool.js +8 -57
- package/dist/preview/workers/WorkerPool.js.map +1 -1
- package/dist/render/EFRenderAPI.d.ts +35 -0
- package/dist/render/EFRenderAPI.js +1 -0
- package/dist/render/EFRenderAPI.js.map +1 -1
- package/dist/sandbox/PlaybackControls.d.ts +1 -0
- package/dist/sandbox/ScenarioRunner.d.ts +1 -0
- package/dist/sandbox/defineSandbox.d.ts +1 -0
- package/dist/sandbox/index.d.ts +3 -0
- package/dist/style.css +3 -0
- package/dist/transcoding/types/index.d.ts +6 -3
- package/package.json +2 -3
- package/test/EFVideo.framegen.browsertest.ts +8 -1
- package/test/profilingPlugin.ts +1 -3
- package/test/setup.ts +23 -1
- package/dist/EF_INTERACTIVE.js +0 -7
- package/dist/EF_INTERACTIVE.js.map +0 -1
- package/dist/elements/EFMedia/BufferedSeekingInput.d.ts +0 -50
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.d.ts +0 -12
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +0 -104
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +0 -168
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js +0 -46
- package/dist/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js +0 -49
- package/dist/elements/EFMedia/audioTasks/makeAudioInputTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js +0 -30
- package/dist/elements/EFMedia/audioTasks/makeAudioSeekTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js +0 -49
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js +0 -47
- package/dist/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.js.map +0 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +0 -140
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js.map +0 -1
- package/dist/elements/EFMedia/shared/BufferUtils.d.ts +0 -13
- package/dist/elements/EFMedia/shared/BufferUtils.js +0 -86
- package/dist/elements/EFMedia/shared/BufferUtils.js.map +0 -1
- package/dist/elements/EFMedia/shared/MediaTaskUtils.d.ts +0 -17
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +0 -90
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +0 -80
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +0 -49
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +0 -58
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +0 -71
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +0 -52
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js +0 -50
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +0 -109
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js.map +0 -1
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.d.ts +0 -12
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +0 -97
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js.map +0 -1
- package/dist/elements/SampleBuffer.d.ts +0 -19
|
@@ -8,25 +8,33 @@ var JitMediaEngine = class JitMediaEngine extends BaseMediaEngine {
|
|
|
8
8
|
const data = await engine.fetchManifest(url, signal);
|
|
9
9
|
signal?.throwIfAborted();
|
|
10
10
|
engine.data = data;
|
|
11
|
+
engine.durationMs = data.durationMs;
|
|
12
|
+
engine.src = data.sourceUrl;
|
|
13
|
+
engine.templates = data.endpoints;
|
|
11
14
|
return engine;
|
|
12
15
|
}
|
|
13
16
|
constructor(host, urlGenerator) {
|
|
14
17
|
super(host);
|
|
15
18
|
this.data = {};
|
|
19
|
+
this.durationMs = 0;
|
|
20
|
+
this.src = "";
|
|
16
21
|
this.urlGenerator = urlGenerator;
|
|
17
22
|
this.thumbnailExtractor = new ThumbnailExtractor(this);
|
|
18
23
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
get src() {
|
|
23
|
-
return this.data.sourceUrl;
|
|
24
|
-
}
|
|
24
|
+
#cachedVideoRendition = null;
|
|
25
|
+
#cachedAudioRendition = null;
|
|
25
26
|
get audioRendition() {
|
|
26
|
-
if (
|
|
27
|
+
if (this.#cachedAudioRendition !== null) return this.#cachedAudioRendition;
|
|
28
|
+
if (!this.data.audioRenditions || this.data.audioRenditions.length === 0) {
|
|
29
|
+
this.#cachedAudioRendition = void 0;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
27
32
|
const rendition = this.data.audioRenditions[0];
|
|
28
|
-
if (!rendition)
|
|
29
|
-
|
|
33
|
+
if (!rendition) {
|
|
34
|
+
this.#cachedAudioRendition = void 0;
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.#cachedAudioRendition = {
|
|
30
38
|
id: rendition.id,
|
|
31
39
|
trackId: void 0,
|
|
32
40
|
src: this.data.sourceUrl,
|
|
@@ -34,12 +42,20 @@ var JitMediaEngine = class JitMediaEngine extends BaseMediaEngine {
|
|
|
34
42
|
segmentDurationsMs: rendition.segmentDurationsMs,
|
|
35
43
|
startTimeOffsetMs: rendition.startTimeOffsetMs
|
|
36
44
|
};
|
|
45
|
+
return this.#cachedAudioRendition;
|
|
37
46
|
}
|
|
38
47
|
get videoRendition() {
|
|
39
|
-
if (
|
|
48
|
+
if (this.#cachedVideoRendition !== null) return this.#cachedVideoRendition;
|
|
49
|
+
if (!this.data.videoRenditions || this.data.videoRenditions.length === 0) {
|
|
50
|
+
this.#cachedVideoRendition = void 0;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
40
53
|
const rendition = this.data.videoRenditions[0];
|
|
41
|
-
if (!rendition)
|
|
42
|
-
|
|
54
|
+
if (!rendition) {
|
|
55
|
+
this.#cachedVideoRendition = void 0;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
this.#cachedVideoRendition = {
|
|
43
59
|
id: rendition.id,
|
|
44
60
|
trackId: void 0,
|
|
45
61
|
src: this.data.sourceUrl,
|
|
@@ -47,9 +63,7 @@ var JitMediaEngine = class JitMediaEngine extends BaseMediaEngine {
|
|
|
47
63
|
segmentDurationsMs: rendition.segmentDurationsMs,
|
|
48
64
|
startTimeOffsetMs: rendition.startTimeOffsetMs
|
|
49
65
|
};
|
|
50
|
-
|
|
51
|
-
get templates() {
|
|
52
|
-
return this.data.endpoints;
|
|
66
|
+
return this.#cachedVideoRendition;
|
|
53
67
|
}
|
|
54
68
|
async fetchInitSegment(rendition, signal) {
|
|
55
69
|
if (!rendition.id) throw new Error("Rendition ID is required for JIT metadata");
|
|
@@ -85,7 +99,7 @@ var JitMediaEngine = class JitMediaEngine extends BaseMediaEngine {
|
|
|
85
99
|
getScrubVideoRendition() {
|
|
86
100
|
if (!this.data.videoRenditions) return void 0;
|
|
87
101
|
const scrubManifestRendition = this.data.videoRenditions.find((r) => r.id === "scrub");
|
|
88
|
-
if (!scrubManifestRendition) return this.
|
|
102
|
+
if (!scrubManifestRendition) return this.getVideoRenditionInternal();
|
|
89
103
|
return {
|
|
90
104
|
id: scrubManifestRendition.id,
|
|
91
105
|
trackId: void 0,
|
|
@@ -113,7 +127,7 @@ var JitMediaEngine = class JitMediaEngine extends BaseMediaEngine {
|
|
|
113
127
|
async extractThumbnails(timestamps, signal) {
|
|
114
128
|
let rendition;
|
|
115
129
|
try {
|
|
116
|
-
const mainRendition = this.
|
|
130
|
+
const mainRendition = this.getVideoRenditionInternal();
|
|
117
131
|
if (mainRendition) rendition = mainRendition;
|
|
118
132
|
else {
|
|
119
133
|
const scrubRendition = this.getScrubVideoRendition();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JitMediaEngine.js","names":["rendition: VideoRendition"],"sources":["../../../src/elements/EFMedia/JitMediaEngine.ts"],"sourcesContent":["import type {\n AudioRendition,\n MediaEngine,\n RenditionId,\n ThumbnailResult,\n VideoRendition,\n} from \"../../transcoding/types\";\nimport type { ManifestResponse } from \"../../transcoding/types/index.js\";\nimport type { UrlGenerator } from \"../../transcoding/utils/UrlGenerator\";\nimport type { EFMedia } from \"../EFMedia.js\";\nimport { BaseMediaEngine } from \"./BaseMediaEngine\";\nimport { ThumbnailExtractor } from \"./shared/ThumbnailExtractor.js\";\n\nexport class JitMediaEngine extends BaseMediaEngine implements MediaEngine {\n private urlGenerator: UrlGenerator;\n private data: ManifestResponse = {} as ManifestResponse;\n private thumbnailExtractor: ThumbnailExtractor;\n\n static async fetch(host: EFMedia, urlGenerator: UrlGenerator, url: string, signal?: AbortSignal) {\n const engine = new JitMediaEngine(host, urlGenerator);\n const data = await engine.fetchManifest(url, signal);\n \n // Check for abort after potentially slow network operation\n signal?.throwIfAborted();\n \n engine.data = data;\n return engine;\n }\n\n constructor(host: EFMedia, urlGenerator: UrlGenerator) {\n super(host);\n this.urlGenerator = urlGenerator;\n this.thumbnailExtractor = new ThumbnailExtractor(this);\n }\n\n get durationMs() {\n return this.data.durationMs;\n }\n\n get src() {\n return this.data.sourceUrl;\n }\n\n get audioRendition(): AudioRendition | undefined {\n if (!this.data.audioRenditions || this.data.audioRenditions.length === 0) {\n return undefined;\n }\n\n const rendition = this.data.audioRenditions[0];\n if (!rendition) return undefined;\n\n return {\n id: rendition.id as RenditionId,\n trackId: undefined,\n src: this.data.sourceUrl,\n segmentDurationMs: rendition.segmentDurationMs,\n segmentDurationsMs: rendition.segmentDurationsMs,\n startTimeOffsetMs: rendition.startTimeOffsetMs,\n };\n }\n\n get videoRendition(): VideoRendition | undefined {\n if (!this.data.videoRenditions || this.data.videoRenditions.length === 0) {\n return undefined;\n }\n\n const rendition = this.data.videoRenditions[0];\n if (!rendition) return undefined;\n\n return {\n id: rendition.id as RenditionId,\n trackId: undefined,\n src: this.data.sourceUrl,\n segmentDurationMs: rendition.segmentDurationMs,\n segmentDurationsMs: rendition.segmentDurationsMs,\n startTimeOffsetMs: rendition.startTimeOffsetMs,\n };\n }\n\n get templates() {\n return this.data.endpoints;\n }\n\n async fetchInitSegment(\n rendition: { id?: RenditionId; trackId: number | undefined; src: string },\n signal?: AbortSignal,\n ) {\n if (!rendition.id) {\n throw new Error(\"Rendition ID is required for JIT metadata\");\n }\n const url = this.urlGenerator.generateSegmentUrl(\n \"init\",\n rendition.id,\n this,\n );\n\n // Use unified fetch method\n return this.fetchMedia(url, signal);\n }\n\n async fetchMediaSegment(\n segmentId: number,\n rendition: { id?: RenditionId; trackId: number | undefined; src: string },\n signal?: AbortSignal,\n ) {\n if (!rendition.id) {\n throw new Error(\"Rendition ID is required for JIT metadata\");\n }\n const url = this.urlGenerator.generateSegmentUrl(\n segmentId,\n rendition.id,\n this,\n );\n return this.fetchMedia(url, signal);\n }\n\n computeSegmentId(\n desiredSeekTimeMs: number,\n rendition: VideoRendition | AudioRendition,\n ) {\n // Don't request segments beyond the actual file duration\n // Note: seeking to exactly durationMs should be allowed (it's the last moment of the file)\n if (desiredSeekTimeMs > this.durationMs) {\n return undefined;\n }\n\n // Use actual segment durations if available (more accurate)\n if (\n rendition.segmentDurationsMs &&\n rendition.segmentDurationsMs.length > 0\n ) {\n let cumulativeTime = 0;\n\n for (let i = 0; i < rendition.segmentDurationsMs.length; i++) {\n const segmentDuration = rendition.segmentDurationsMs[i];\n if (segmentDuration === undefined) {\n throw new Error(\"Segment duration is required for JIT metadata\");\n }\n const segmentStartMs = cumulativeTime;\n const segmentEndMs = cumulativeTime + segmentDuration;\n\n // Check if the desired seek time falls within this segment\n // Special case: for the last segment, include the exact end time\n const isLastSegment = i === rendition.segmentDurationsMs.length - 1;\n const includesEndTime =\n isLastSegment && desiredSeekTimeMs === this.durationMs;\n\n if (\n desiredSeekTimeMs >= segmentStartMs &&\n (desiredSeekTimeMs < segmentEndMs || includesEndTime)\n ) {\n return i + 1; // Convert 0-based to 1-based segment ID\n }\n\n cumulativeTime += segmentDuration;\n\n // If we've reached or exceeded file duration, stop\n if (cumulativeTime >= this.durationMs) {\n break;\n }\n }\n\n // If we didn't find a segment, return undefined\n return undefined;\n }\n\n // Fall back to fixed duration calculation for backward compatibility\n if (!rendition.segmentDurationMs) {\n throw new Error(\"Segment duration is required for JIT metadata\");\n }\n\n const segmentIndex = Math.floor(\n desiredSeekTimeMs / rendition.segmentDurationMs,\n );\n\n // Calculate the actual segment start time\n const segmentStartMs = segmentIndex * rendition.segmentDurationMs;\n\n // If this segment would start at or beyond file duration, it doesn't exist\n if (segmentStartMs >= this.durationMs) {\n return undefined;\n }\n\n return segmentIndex + 1; // Convert 0-based to 1-based\n }\n\n getScrubVideoRendition(): VideoRendition | undefined {\n if (!this.data.videoRenditions) return undefined;\n\n const scrubManifestRendition = this.data.videoRenditions.find(\n (r) => r.id === \"scrub\",\n );\n\n if (!scrubManifestRendition) return this.videoRendition; // Fallback to main\n\n return {\n id: scrubManifestRendition.id as any,\n trackId: undefined,\n src: this.src,\n segmentDurationMs: scrubManifestRendition.segmentDurationMs,\n segmentDurationsMs: scrubManifestRendition.segmentDurationsMs,\n };\n }\n\n /**\n * Get preferred buffer configuration for JIT transcoding\n * Uses higher buffering since transcoding introduces latency\n */\n getBufferConfig() {\n return {\n // Buffer more aggressively for JIT transcoding to smooth over latency\n videoBufferDurationMs: 8000,\n audioBufferDurationMs: 8000,\n maxVideoBufferFetches: 3,\n maxAudioBufferFetches: 3,\n bufferThresholdMs: 30000, // Timeline-aware buffering threshold\n };\n }\n\n /**\n * Extract thumbnail canvases using same rendition priority as video playback for frame alignment\n */\n async extractThumbnails(\n timestamps: number[],\n signal?: AbortSignal,\n ): Promise<(ThumbnailResult | null)[]> {\n // Use same rendition priority as video: try main rendition first for frame alignment\n let rendition: VideoRendition;\n try {\n const mainRendition = this.getVideoRendition();\n if (mainRendition) {\n rendition = mainRendition;\n } else {\n const scrubRendition = this.getScrubVideoRendition();\n if (scrubRendition) {\n rendition = scrubRendition;\n } else {\n throw new Error(\"No video rendition available\");\n }\n }\n } catch (error) {\n console.warn(\n \"JitMediaEngine: No video rendition available for thumbnails\",\n error,\n );\n return timestamps.map(() => null);\n }\n\n // Use shared thumbnail extraction logic\n return this.thumbnailExtractor.extractThumbnails(\n timestamps,\n rendition,\n this.durationMs,\n signal,\n );\n }\n\n convertToSegmentRelativeTimestamps(\n globalTimestamps: number[],\n _segmentId: number,\n _rendition: VideoRendition,\n ): number[] {\n return globalTimestamps.map((timestamp) => timestamp / 1000);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JitMediaEngine.js","names":["#cachedAudioRendition","#cachedVideoRendition","rendition: VideoRendition"],"sources":["../../../src/elements/EFMedia/JitMediaEngine.ts"],"sourcesContent":["import type {\n AudioRendition,\n MediaEngine,\n RenditionId,\n ThumbnailResult,\n VideoRendition,\n} from \"../../transcoding/types\";\nimport type { ManifestResponse } from \"../../transcoding/types/index.js\";\nimport type { UrlGenerator } from \"../../transcoding/utils/UrlGenerator\";\nimport type { EFMedia } from \"../EFMedia.js\";\nimport { BaseMediaEngine } from \"./BaseMediaEngine\";\nimport { ThumbnailExtractor } from \"./shared/ThumbnailExtractor.js\";\n\nexport class JitMediaEngine extends BaseMediaEngine implements MediaEngine {\n private urlGenerator: UrlGenerator;\n private data: ManifestResponse = {} as ManifestResponse;\n private thumbnailExtractor: ThumbnailExtractor;\n\n static async fetch(host: EFMedia, urlGenerator: UrlGenerator, url: string, signal?: AbortSignal) {\n const engine = new JitMediaEngine(host, urlGenerator);\n const data = await engine.fetchManifest(url, signal);\n \n // Check for abort after potentially slow network operation\n signal?.throwIfAborted();\n \n engine.data = data;\n // Set MediaEngine interface properties\n engine.durationMs = data.durationMs;\n engine.src = data.sourceUrl;\n engine.templates = data.endpoints;\n return engine;\n }\n\n // MediaEngine interface properties\n durationMs = 0;\n src = \"\";\n templates!: { initSegment: string; mediaSegment: string };\n\n constructor(host: EFMedia, urlGenerator: UrlGenerator) {\n super(host);\n this.urlGenerator = urlGenerator;\n this.thumbnailExtractor = new ThumbnailExtractor(this);\n }\n\n // Cache renditions to avoid recomputing on every access\n #cachedVideoRendition: VideoRendition | undefined | null = null;\n #cachedAudioRendition: AudioRendition | undefined | null = null;\n\n get audioRendition(): AudioRendition | undefined {\n if (this.#cachedAudioRendition !== null) {\n return this.#cachedAudioRendition;\n }\n if (!this.data.audioRenditions || this.data.audioRenditions.length === 0) {\n this.#cachedAudioRendition = undefined;\n return undefined;\n }\n\n const rendition = this.data.audioRenditions[0];\n if (!rendition) {\n this.#cachedAudioRendition = undefined;\n return undefined;\n }\n\n this.#cachedAudioRendition = {\n id: rendition.id as RenditionId,\n trackId: undefined,\n src: this.data.sourceUrl,\n segmentDurationMs: rendition.segmentDurationMs,\n segmentDurationsMs: rendition.segmentDurationsMs,\n startTimeOffsetMs: rendition.startTimeOffsetMs,\n };\n return this.#cachedAudioRendition;\n }\n\n get videoRendition(): VideoRendition | undefined {\n if (this.#cachedVideoRendition !== null) {\n return this.#cachedVideoRendition;\n }\n if (!this.data.videoRenditions || this.data.videoRenditions.length === 0) {\n this.#cachedVideoRendition = undefined;\n return undefined;\n }\n\n const rendition = this.data.videoRenditions[0];\n if (!rendition) {\n this.#cachedVideoRendition = undefined;\n return undefined;\n }\n\n this.#cachedVideoRendition = {\n id: rendition.id as RenditionId,\n trackId: undefined,\n src: this.data.sourceUrl,\n segmentDurationMs: rendition.segmentDurationMs,\n segmentDurationsMs: rendition.segmentDurationsMs,\n startTimeOffsetMs: rendition.startTimeOffsetMs,\n };\n return this.#cachedVideoRendition;\n }\n\n\n\n async fetchInitSegment(\n rendition: { id?: RenditionId; trackId: number | undefined; src: string },\n signal?: AbortSignal,\n ) {\n if (!rendition.id) {\n throw new Error(\"Rendition ID is required for JIT metadata\");\n }\n const url = this.urlGenerator.generateSegmentUrl(\n \"init\",\n rendition.id,\n this,\n );\n\n // Use unified fetch method\n return this.fetchMedia(url, signal);\n }\n\n async fetchMediaSegment(\n segmentId: number,\n rendition: { id?: RenditionId; trackId: number | undefined; src: string },\n signal?: AbortSignal,\n ) {\n if (!rendition.id) {\n throw new Error(\"Rendition ID is required for JIT metadata\");\n }\n const url = this.urlGenerator.generateSegmentUrl(\n segmentId,\n rendition.id,\n this,\n );\n return this.fetchMedia(url, signal);\n }\n\n computeSegmentId(\n desiredSeekTimeMs: number,\n rendition: VideoRendition | AudioRendition,\n ) {\n // Don't request segments beyond the actual file duration\n // Note: seeking to exactly durationMs should be allowed (it's the last moment of the file)\n if (desiredSeekTimeMs > this.durationMs) {\n return undefined;\n }\n\n // Use actual segment durations if available (more accurate)\n if (\n rendition.segmentDurationsMs &&\n rendition.segmentDurationsMs.length > 0\n ) {\n let cumulativeTime = 0;\n\n for (let i = 0; i < rendition.segmentDurationsMs.length; i++) {\n const segmentDuration = rendition.segmentDurationsMs[i];\n if (segmentDuration === undefined) {\n throw new Error(\"Segment duration is required for JIT metadata\");\n }\n const segmentStartMs = cumulativeTime;\n const segmentEndMs = cumulativeTime + segmentDuration;\n\n // Check if the desired seek time falls within this segment\n // Special case: for the last segment, include the exact end time\n const isLastSegment = i === rendition.segmentDurationsMs.length - 1;\n const includesEndTime =\n isLastSegment && desiredSeekTimeMs === this.durationMs;\n\n if (\n desiredSeekTimeMs >= segmentStartMs &&\n (desiredSeekTimeMs < segmentEndMs || includesEndTime)\n ) {\n return i + 1; // Convert 0-based to 1-based segment ID\n }\n\n cumulativeTime += segmentDuration;\n\n // If we've reached or exceeded file duration, stop\n if (cumulativeTime >= this.durationMs) {\n break;\n }\n }\n\n // If we didn't find a segment, return undefined\n return undefined;\n }\n\n // Fall back to fixed duration calculation for backward compatibility\n if (!rendition.segmentDurationMs) {\n throw new Error(\"Segment duration is required for JIT metadata\");\n }\n\n const segmentIndex = Math.floor(\n desiredSeekTimeMs / rendition.segmentDurationMs,\n );\n\n // Calculate the actual segment start time\n const segmentStartMs = segmentIndex * rendition.segmentDurationMs;\n\n // If this segment would start at or beyond file duration, it doesn't exist\n if (segmentStartMs >= this.durationMs) {\n return undefined;\n }\n\n return segmentIndex + 1; // Convert 0-based to 1-based\n }\n\n getScrubVideoRendition(): VideoRendition | undefined {\n if (!this.data.videoRenditions) return undefined;\n\n const scrubManifestRendition = this.data.videoRenditions.find(\n (r) => r.id === \"scrub\",\n );\n\n if (!scrubManifestRendition) return this.getVideoRenditionInternal(); // Fallback to main\n\n return {\n id: scrubManifestRendition.id as any,\n trackId: undefined,\n src: this.src,\n segmentDurationMs: scrubManifestRendition.segmentDurationMs,\n segmentDurationsMs: scrubManifestRendition.segmentDurationsMs,\n };\n }\n\n /**\n * Get preferred buffer configuration for JIT transcoding\n * Uses higher buffering since transcoding introduces latency\n */\n getBufferConfig() {\n return {\n // Buffer more aggressively for JIT transcoding to smooth over latency\n videoBufferDurationMs: 8000,\n audioBufferDurationMs: 8000,\n maxVideoBufferFetches: 3,\n maxAudioBufferFetches: 3,\n bufferThresholdMs: 30000, // Timeline-aware buffering threshold\n };\n }\n\n /**\n * Extract thumbnail canvases using same rendition priority as video playback for frame alignment\n */\n async extractThumbnails(\n timestamps: number[],\n signal?: AbortSignal,\n ): Promise<(ThumbnailResult | null)[]> {\n // Use same rendition priority as video: try main rendition first for frame alignment\n let rendition: VideoRendition;\n try {\n const mainRendition = this.getVideoRenditionInternal();\n if (mainRendition) {\n rendition = mainRendition;\n } else {\n const scrubRendition = this.getScrubVideoRendition();\n if (scrubRendition) {\n rendition = scrubRendition;\n } else {\n throw new Error(\"No video rendition available\");\n }\n }\n } catch (error) {\n console.warn(\n \"JitMediaEngine: No video rendition available for thumbnails\",\n error,\n );\n return timestamps.map(() => null);\n }\n\n // Use shared thumbnail extraction logic\n return this.thumbnailExtractor.extractThumbnails(\n timestamps,\n rendition,\n this.durationMs,\n signal,\n );\n }\n\n convertToSegmentRelativeTimestamps(\n globalTimestamps: number[],\n _segmentId: number,\n _rendition: VideoRendition,\n ): number[] {\n return globalTimestamps.map((timestamp) => timestamp / 1000);\n }\n}\n"],"mappings":"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"}
|
|
@@ -29,11 +29,11 @@ const createAudioSpanBlob = (initSegment, mediaSegments) => {
|
|
|
29
29
|
*/
|
|
30
30
|
const fetchAudioSpanningTime = async (host, fromMs, toMs, signal) => {
|
|
31
31
|
if (fromMs >= toMs || fromMs < 0) throw new Error(`Invalid time range: fromMs=${fromMs}, toMs=${toMs}`);
|
|
32
|
-
const mediaEngine = await host.
|
|
33
|
-
signal?.throwIfAborted();
|
|
34
|
-
const initSegment = await host.audioInitSegmentFetchTask.taskComplete;
|
|
32
|
+
const mediaEngine = await host.getMediaEngine(signal);
|
|
35
33
|
signal?.throwIfAborted();
|
|
36
34
|
if (!mediaEngine?.audioRendition) return;
|
|
35
|
+
const initSegment = await mediaEngine.fetchInitSegment(mediaEngine.audioRendition, signal);
|
|
36
|
+
signal?.throwIfAborted();
|
|
37
37
|
if (!initSegment) return;
|
|
38
38
|
const segmentRanges = mediaEngine.calculateAudioSegmentRange(fromMs, toMs, mediaEngine.audioRendition, host.intrinsicDurationMs || 1e4);
|
|
39
39
|
if (segmentRanges.length === 0) throw new Error(`No segments found for time range ${fromMs}-${toMs}ms`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioSpanUtils.js","names":[],"sources":["../../../../src/elements/EFMedia/shared/AudioSpanUtils.ts"],"sourcesContent":["import type {\n AudioSpan,\n MediaEngine,\n SegmentTimeRange,\n} from \"../../../transcoding/types\";\nimport type { EFMedia } from \"../../EFMedia\";\n\n/**\n * Fetch audio segment data using MediaEngine\n * Pure function with explicit dependencies\n */\nconst fetchAudioSegmentData = async (\n segmentIds: number[],\n mediaEngine: MediaEngine,\n signal?: AbortSignal,\n): Promise<Map<number, ArrayBuffer>> => {\n const audioRendition = mediaEngine.audioRendition;\n if (!audioRendition) {\n throw new Error(\"Audio rendition not available\");\n }\n\n const segmentData = new Map<number, ArrayBuffer>();\n\n // Fetch all segments - MediaEngine handles deduplication internally\n const fetchPromises = segmentIds.map(async (segmentId) => {\n const arrayBuffer = await mediaEngine.fetchMediaSegment(\n segmentId,\n audioRendition,\n signal,\n );\n return [segmentId, arrayBuffer] as [number, ArrayBuffer];\n });\n\n const fetchedSegments = await Promise.all(fetchPromises);\n signal?.throwIfAborted();\n\n for (const [segmentId, arrayBuffer] of fetchedSegments) {\n segmentData.set(segmentId, arrayBuffer);\n }\n\n return segmentData;\n};\n\n/**\n * Create audio span blob from init segment and media segments\n * Pure function for blob creation\n */\nconst createAudioSpanBlob = (\n initSegment: ArrayBuffer,\n mediaSegments: ArrayBuffer[],\n): Blob => {\n const chunks = [initSegment, ...mediaSegments];\n return new Blob(chunks, { type: \"audio/mp4\" });\n};\n\n/**\n * Fetch audio spanning a time range\n * Main function that orchestrates segment calculation, fetching, and blob creation\n */\nexport const fetchAudioSpanningTime = async (\n host: EFMedia,\n fromMs: number,\n toMs: number,\n signal?: AbortSignal,\n): Promise<AudioSpan | undefined> => {\n // Validate inputs\n if (fromMs >= toMs || fromMs < 0) {\n throw new Error(`Invalid time range: fromMs=${fromMs}, toMs=${toMs}`);\n }\n\n // Get
|
|
1
|
+
{"version":3,"file":"AudioSpanUtils.js","names":[],"sources":["../../../../src/elements/EFMedia/shared/AudioSpanUtils.ts"],"sourcesContent":["import type {\n AudioSpan,\n MediaEngine,\n SegmentTimeRange,\n} from \"../../../transcoding/types\";\nimport type { EFMedia } from \"../../EFMedia\";\n\n/**\n * Fetch audio segment data using MediaEngine\n * Pure function with explicit dependencies\n */\nconst fetchAudioSegmentData = async (\n segmentIds: number[],\n mediaEngine: MediaEngine,\n signal?: AbortSignal,\n): Promise<Map<number, ArrayBuffer>> => {\n const audioRendition = mediaEngine.audioRendition;\n if (!audioRendition) {\n throw new Error(\"Audio rendition not available\");\n }\n\n const segmentData = new Map<number, ArrayBuffer>();\n\n // Fetch all segments - MediaEngine handles deduplication internally\n const fetchPromises = segmentIds.map(async (segmentId) => {\n const arrayBuffer = await mediaEngine.fetchMediaSegment(\n segmentId,\n audioRendition,\n signal,\n );\n return [segmentId, arrayBuffer] as [number, ArrayBuffer];\n });\n\n const fetchedSegments = await Promise.all(fetchPromises);\n signal?.throwIfAborted();\n\n for (const [segmentId, arrayBuffer] of fetchedSegments) {\n segmentData.set(segmentId, arrayBuffer);\n }\n\n return segmentData;\n};\n\n/**\n * Create audio span blob from init segment and media segments\n * Pure function for blob creation\n */\nconst createAudioSpanBlob = (\n initSegment: ArrayBuffer,\n mediaSegments: ArrayBuffer[],\n): Blob => {\n const chunks = [initSegment, ...mediaSegments];\n return new Blob(chunks, { type: \"audio/mp4\" });\n};\n\n/**\n * Fetch audio spanning a time range\n * Main function that orchestrates segment calculation, fetching, and blob creation\n */\nexport const fetchAudioSpanningTime = async (\n host: EFMedia,\n fromMs: number,\n toMs: number,\n signal?: AbortSignal,\n): Promise<AudioSpan | undefined> => {\n // Validate inputs\n if (fromMs >= toMs || fromMs < 0) {\n throw new Error(`Invalid time range: fromMs=${fromMs}, toMs=${toMs}`);\n }\n\n // Get media engine using the new async method\n const mediaEngine = await host.getMediaEngine(signal);\n signal?.throwIfAborted();\n\n // Return undefined if no audio rendition available\n if (!mediaEngine?.audioRendition) {\n return undefined;\n }\n\n // Fetch the init segment directly from media engine\n const initSegment = await mediaEngine.fetchInitSegment(\n mediaEngine.audioRendition,\n signal!,\n );\n signal?.throwIfAborted();\n\n if (!initSegment) {\n return undefined;\n }\n\n // Calculate segments needed using the media engine's method\n const segmentRanges = mediaEngine.calculateAudioSegmentRange(\n fromMs,\n toMs,\n mediaEngine.audioRendition,\n host.intrinsicDurationMs || 10000,\n );\n\n if (segmentRanges.length === 0) {\n throw new Error(`No segments found for time range ${fromMs}-${toMs}ms`);\n }\n\n // Fetch segment data\n const segmentIds = segmentRanges.map((r: SegmentTimeRange) => r.segmentId);\n const segmentData = await fetchAudioSegmentData(\n segmentIds,\n mediaEngine,\n signal,\n );\n\n // Create ordered array of segments\n const orderedSegments = segmentIds.map((id: number) => {\n const segment = segmentData.get(id);\n if (!segment) {\n throw new Error(`Missing segment data for segment ID ${id}`);\n }\n return segment;\n });\n\n // Create blob\n const blob = createAudioSpanBlob(initSegment, orderedSegments);\n\n // Calculate actual time boundaries\n const actualStartMs = Math.min(\n ...segmentRanges.map((r: SegmentTimeRange) => r.startMs),\n );\n const actualEndMs = Math.max(\n ...segmentRanges.map((r: SegmentTimeRange) => r.endMs),\n );\n\n return {\n startMs: actualStartMs,\n endMs: actualEndMs,\n blob,\n };\n};\n"],"mappings":";;;;;AAWA,MAAM,wBAAwB,OAC5B,YACA,aACA,WACsC;CACtC,MAAM,iBAAiB,YAAY;AACnC,KAAI,CAAC,eACH,OAAM,IAAI,MAAM,gCAAgC;CAGlD,MAAM,8BAAc,IAAI,KAA0B;CAGlD,MAAM,gBAAgB,WAAW,IAAI,OAAO,cAAc;AAMxD,SAAO,CAAC,WALY,MAAM,YAAY,kBACpC,WACA,gBACA,OACD,CAC8B;GAC/B;CAEF,MAAM,kBAAkB,MAAM,QAAQ,IAAI,cAAc;AACxD,SAAQ,gBAAgB;AAExB,MAAK,MAAM,CAAC,WAAW,gBAAgB,gBACrC,aAAY,IAAI,WAAW,YAAY;AAGzC,QAAO;;;;;;AAOT,MAAM,uBACJ,aACA,kBACS;CACT,MAAM,SAAS,CAAC,aAAa,GAAG,cAAc;AAC9C,QAAO,IAAI,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;;;;;;AAOhD,MAAa,yBAAyB,OACpC,MACA,QACA,MACA,WACmC;AAEnC,KAAI,UAAU,QAAQ,SAAS,EAC7B,OAAM,IAAI,MAAM,8BAA8B,OAAO,SAAS,OAAO;CAIvE,MAAM,cAAc,MAAM,KAAK,eAAe,OAAO;AACrD,SAAQ,gBAAgB;AAGxB,KAAI,CAAC,aAAa,eAChB;CAIF,MAAM,cAAc,MAAM,YAAY,iBACpC,YAAY,gBACZ,OACD;AACD,SAAQ,gBAAgB;AAExB,KAAI,CAAC,YACH;CAIF,MAAM,gBAAgB,YAAY,2BAChC,QACA,MACA,YAAY,gBACZ,KAAK,uBAAuB,IAC7B;AAED,KAAI,cAAc,WAAW,EAC3B,OAAM,IAAI,MAAM,oCAAoC,OAAO,GAAG,KAAK,IAAI;CAIzE,MAAM,aAAa,cAAc,KAAK,MAAwB,EAAE,UAAU;CAC1E,MAAM,cAAc,MAAM,sBACxB,YACA,aACA,OACD;CAYD,MAAM,OAAO,oBAAoB,aATT,WAAW,KAAK,OAAe;EACrD,MAAM,UAAU,YAAY,IAAI,GAAG;AACnC,MAAI,CAAC,QACH,OAAM,IAAI,MAAM,uCAAuC,KAAK;AAE9D,SAAO;GACP,CAG4D;AAU9D,QAAO;EACL,SARoB,KAAK,IACzB,GAAG,cAAc,KAAK,MAAwB,EAAE,QAAQ,CACzD;EAOC,OANkB,KAAK,IACvB,GAAG,cAAc,KAAK,MAAwB,EAAE,MAAM,CACvD;EAKC;EACD"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Cache for scrub BufferedSeekingInput instances.
|
|
4
4
|
*
|
|
5
|
-
* For JIT media (segmented scrub tracks), caches by segment ID.
|
|
5
|
+
* For JIT media (segmented scrub tracks), caches by src + segment ID.
|
|
6
6
|
* For Asset media (single-file scrub tracks), caches by URL so all segments
|
|
7
7
|
* share the same BufferedSeekingInput instance.
|
|
8
8
|
*
|
|
@@ -16,16 +16,23 @@ var ScrubInputCache = class {
|
|
|
16
16
|
#pendingByUrl = /* @__PURE__ */ new Map();
|
|
17
17
|
#maxCacheSize = 5;
|
|
18
18
|
/**
|
|
19
|
+
* Create a cache key that uniquely identifies a segment for a specific video
|
|
20
|
+
*/
|
|
21
|
+
#getCacheKey(src, segmentId) {
|
|
22
|
+
return `${src}:${segmentId}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
19
25
|
* Get or create BufferedSeekingInput for a scrub segment.
|
|
20
26
|
*
|
|
21
27
|
* Uses promise deduplication to prevent race conditions when multiple
|
|
22
28
|
* concurrent requests arrive for the same segment.
|
|
23
29
|
*
|
|
30
|
+
* @param src - The source URL of the video (required to distinguish between videos)
|
|
24
31
|
* @param segmentId - The segment ID
|
|
25
32
|
* @param createInputFn - Factory function to create the input
|
|
26
33
|
* @param scrubUrl - Optional URL for single-file scrub tracks (all segments share same input)
|
|
27
34
|
*/
|
|
28
|
-
async getOrCreateInput(segmentId, createInputFn, scrubUrl) {
|
|
35
|
+
async getOrCreateInput(src, segmentId, createInputFn, scrubUrl) {
|
|
29
36
|
if (scrubUrl) {
|
|
30
37
|
const cached$1 = this.#urlCache.get(scrubUrl);
|
|
31
38
|
if (cached$1) return cached$1;
|
|
@@ -42,14 +49,15 @@ var ScrubInputCache = class {
|
|
|
42
49
|
this.#pendingByUrl.set(scrubUrl, promise$1);
|
|
43
50
|
return promise$1;
|
|
44
51
|
}
|
|
45
|
-
const
|
|
52
|
+
const cacheKey = this.#getCacheKey(src, segmentId);
|
|
53
|
+
const cached = this.#cache.get(cacheKey);
|
|
46
54
|
if (cached) return cached;
|
|
47
|
-
const pending = this.#pendingBySegment.get(
|
|
55
|
+
const pending = this.#pendingBySegment.get(cacheKey);
|
|
48
56
|
if (pending) return pending;
|
|
49
57
|
const promise = createInputFn().then((input) => {
|
|
50
|
-
this.#pendingBySegment.delete(
|
|
58
|
+
this.#pendingBySegment.delete(cacheKey);
|
|
51
59
|
if (input) {
|
|
52
|
-
this.#cache.set(
|
|
60
|
+
this.#cache.set(cacheKey, input);
|
|
53
61
|
if (this.#cache.size > this.#maxCacheSize) {
|
|
54
62
|
const oldestKey = this.#cache.keys().next().value;
|
|
55
63
|
if (oldestKey !== void 0) this.#cache.delete(oldestKey);
|
|
@@ -57,10 +65,10 @@ var ScrubInputCache = class {
|
|
|
57
65
|
}
|
|
58
66
|
return input;
|
|
59
67
|
}).catch((error) => {
|
|
60
|
-
this.#pendingBySegment.delete(
|
|
68
|
+
this.#pendingBySegment.delete(cacheKey);
|
|
61
69
|
throw error;
|
|
62
70
|
});
|
|
63
|
-
this.#pendingBySegment.set(
|
|
71
|
+
this.#pendingBySegment.set(cacheKey, promise);
|
|
64
72
|
return promise;
|
|
65
73
|
}
|
|
66
74
|
/**
|
|
@@ -80,7 +88,7 @@ var ScrubInputCache = class {
|
|
|
80
88
|
size: this.#cache.size,
|
|
81
89
|
urlCacheSize: this.#urlCache.size,
|
|
82
90
|
pendingCount: this.#pendingBySegment.size + this.#pendingByUrl.size,
|
|
83
|
-
|
|
91
|
+
cacheKeys: Array.from(this.#cache.keys())
|
|
84
92
|
};
|
|
85
93
|
}
|
|
86
94
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrubInputCache.js","names":["cached","#urlCache","pending","#pendingByUrl","promise","#cache","#pendingBySegment","#maxCacheSize"],"sources":["../../../../src/elements/EFMedia/videoTasks/ScrubInputCache.ts"],"sourcesContent":["import type { BufferedSeekingInput } from \"../BufferedSeekingInput\";\n\n/**\n * Cache for scrub BufferedSeekingInput instances.\n * \n * For JIT media (segmented scrub tracks), caches by segment ID.\n * For Asset media (single-file scrub tracks), caches by URL so all segments\n * share the same BufferedSeekingInput instance.\n * \n * Uses promise deduplication to prevent race conditions when multiple\n * concurrent requests arrive for the same segment.\n */\nexport class ScrubInputCache {\n #cache = new Map<
|
|
1
|
+
{"version":3,"file":"ScrubInputCache.js","names":["cached","#urlCache","pending","#pendingByUrl","promise","#getCacheKey","#cache","#pendingBySegment","#maxCacheSize"],"sources":["../../../../src/elements/EFMedia/videoTasks/ScrubInputCache.ts"],"sourcesContent":["import type { BufferedSeekingInput } from \"../BufferedSeekingInput\";\n\n/**\n * Cache for scrub BufferedSeekingInput instances.\n * \n * For JIT media (segmented scrub tracks), caches by src + segment ID.\n * For Asset media (single-file scrub tracks), caches by URL so all segments\n * share the same BufferedSeekingInput instance.\n * \n * Uses promise deduplication to prevent race conditions when multiple\n * concurrent requests arrive for the same segment.\n */\nexport class ScrubInputCache {\n // Changed from Map<number> to Map<string> to include src in key\n #cache = new Map<string, BufferedSeekingInput>();\n #urlCache = new Map<string, BufferedSeekingInput>();\n #pendingBySegment = new Map<string, Promise<BufferedSeekingInput | undefined>>();\n #pendingByUrl = new Map<string, Promise<BufferedSeekingInput | undefined>>();\n #maxCacheSize = 5;\n\n /**\n * Create a cache key that uniquely identifies a segment for a specific video\n */\n #getCacheKey(src: string, segmentId: number): string {\n return `${src}:${segmentId}`;\n }\n\n /**\n * Get or create BufferedSeekingInput for a scrub segment.\n * \n * Uses promise deduplication to prevent race conditions when multiple\n * concurrent requests arrive for the same segment.\n * \n * @param src - The source URL of the video (required to distinguish between videos)\n * @param segmentId - The segment ID\n * @param createInputFn - Factory function to create the input\n * @param scrubUrl - Optional URL for single-file scrub tracks (all segments share same input)\n */\n async getOrCreateInput(\n src: string,\n segmentId: number,\n createInputFn: () => Promise<BufferedSeekingInput | undefined>,\n scrubUrl?: string,\n ): Promise<BufferedSeekingInput | undefined> {\n // For single-file scrub tracks (AssetMediaEngine), use URL-based caching\n // This ensures all segments share the same BufferedSeekingInput\n if (scrubUrl) {\n // Check completed cache\n const cached = this.#urlCache.get(scrubUrl);\n if (cached) {\n return cached;\n }\n\n // Check pending requests (deduplication)\n const pending = this.#pendingByUrl.get(scrubUrl);\n if (pending) {\n return pending;\n }\n\n // Create promise and cache immediately\n const promise = createInputFn().then((input) => {\n this.#pendingByUrl.delete(scrubUrl);\n if (input) {\n this.#urlCache.set(scrubUrl, input);\n }\n return input;\n }).catch((error) => {\n this.#pendingByUrl.delete(scrubUrl);\n throw error;\n });\n\n this.#pendingByUrl.set(scrubUrl, promise);\n return promise;\n }\n\n // For segmented scrub tracks (JIT), use src + segment-based caching\n const cacheKey = this.#getCacheKey(src, segmentId);\n const cached = this.#cache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n // Check pending requests (deduplication)\n const pending = this.#pendingBySegment.get(cacheKey);\n if (pending) {\n return pending;\n }\n\n // Create promise and cache immediately\n const promise = createInputFn().then((input) => {\n this.#pendingBySegment.delete(cacheKey);\n \n if (input) {\n this.#cache.set(cacheKey, input);\n\n // Evict oldest entries if cache is too large\n if (this.#cache.size > this.#maxCacheSize) {\n const oldestKey = this.#cache.keys().next().value;\n if (oldestKey !== undefined) {\n this.#cache.delete(oldestKey);\n }\n }\n }\n \n return input;\n }).catch((error) => {\n this.#pendingBySegment.delete(cacheKey);\n throw error;\n });\n\n this.#pendingBySegment.set(cacheKey, promise);\n return promise;\n }\n\n /**\n * Clear the entire cache (called when video changes)\n */\n clear() {\n this.#cache.clear();\n this.#urlCache.clear();\n this.#pendingBySegment.clear();\n this.#pendingByUrl.clear();\n }\n\n /**\n * Get cache statistics\n */\n getStats() {\n return {\n size: this.#cache.size,\n urlCacheSize: this.#urlCache.size,\n pendingCount: this.#pendingBySegment.size + this.#pendingByUrl.size,\n cacheKeys: Array.from(this.#cache.keys()),\n };\n }\n}\n"],"mappings":";;;;;;;;;;;AAYA,IAAa,kBAAb,MAA6B;CAE3B,yBAAS,IAAI,KAAmC;CAChD,4BAAY,IAAI,KAAmC;CACnD,oCAAoB,IAAI,KAAwD;CAChF,gCAAgB,IAAI,KAAwD;CAC5E,gBAAgB;;;;CAKhB,aAAa,KAAa,WAA2B;AACnD,SAAO,GAAG,IAAI,GAAG;;;;;;;;;;;;;CAcnB,MAAM,iBACJ,KACA,WACA,eACA,UAC2C;AAG3C,MAAI,UAAU;GAEZ,MAAMA,WAAS,MAAKC,SAAU,IAAI,SAAS;AAC3C,OAAID,SACF,QAAOA;GAIT,MAAME,YAAU,MAAKC,aAAc,IAAI,SAAS;AAChD,OAAID,UACF,QAAOA;GAIT,MAAME,YAAU,eAAe,CAAC,MAAM,UAAU;AAC9C,UAAKD,aAAc,OAAO,SAAS;AACnC,QAAI,MACF,OAAKF,SAAU,IAAI,UAAU,MAAM;AAErC,WAAO;KACP,CAAC,OAAO,UAAU;AAClB,UAAKE,aAAc,OAAO,SAAS;AACnC,UAAM;KACN;AAEF,SAAKA,aAAc,IAAI,UAAUC,UAAQ;AACzC,UAAOA;;EAIT,MAAM,WAAW,MAAKC,YAAa,KAAK,UAAU;EAClD,MAAM,SAAS,MAAKC,MAAO,IAAI,SAAS;AACxC,MAAI,OACF,QAAO;EAIT,MAAM,UAAU,MAAKC,iBAAkB,IAAI,SAAS;AACpD,MAAI,QACF,QAAO;EAIT,MAAM,UAAU,eAAe,CAAC,MAAM,UAAU;AAC9C,SAAKA,iBAAkB,OAAO,SAAS;AAEvC,OAAI,OAAO;AACT,UAAKD,MAAO,IAAI,UAAU,MAAM;AAGhC,QAAI,MAAKA,MAAO,OAAO,MAAKE,cAAe;KACzC,MAAM,YAAY,MAAKF,MAAO,MAAM,CAAC,MAAM,CAAC;AAC5C,SAAI,cAAc,OAChB,OAAKA,MAAO,OAAO,UAAU;;;AAKnC,UAAO;IACP,CAAC,OAAO,UAAU;AAClB,SAAKC,iBAAkB,OAAO,SAAS;AACvC,SAAM;IACN;AAEF,QAAKA,iBAAkB,IAAI,UAAU,QAAQ;AAC7C,SAAO;;;;;CAMT,QAAQ;AACN,QAAKD,MAAO,OAAO;AACnB,QAAKL,SAAU,OAAO;AACtB,QAAKM,iBAAkB,OAAO;AAC9B,QAAKJ,aAAc,OAAO;;;;;CAM5B,WAAW;AACT,SAAO;GACL,MAAM,MAAKG,MAAO;GAClB,cAAc,MAAKL,SAAU;GAC7B,cAAc,MAAKM,iBAAkB,OAAO,MAAKJ,aAAc;GAC/D,WAAW,MAAM,KAAK,MAAKG,MAAO,MAAM,CAAC;GAC1C"}
|
|
@@ -2,23 +2,46 @@ import { EFFramegen } from "../EF_FRAMEGEN.js";
|
|
|
2
2
|
import { EFSourceMixinInterface } from "./EFSourceMixin.js";
|
|
3
3
|
import { TemporalMixinInterface } from "./EFTemporal.js";
|
|
4
4
|
import { FetchMixinInterface } from "./FetchMixin.js";
|
|
5
|
-
import { BufferedSeekingInput } from "./EFMedia/BufferedSeekingInput.js";
|
|
6
|
-
import { InputTask } from "./EFMedia/shared/MediaTaskUtils.js";
|
|
7
|
-
import { AudioSpan, MediaEngine } from "../transcoding/types/index.js";
|
|
8
|
-
import { AudioBufferState } from "./EFMedia/audioTasks/makeAudioBufferTask.js";
|
|
9
5
|
import { ControllableInterface } from "../gui/Controllable.js";
|
|
6
|
+
import { AudioSpan, MediaEngine } from "../transcoding/types/index.js";
|
|
10
7
|
import { UrlGenerator } from "../transcoding/utils/UrlGenerator.js";
|
|
11
|
-
import * as _lit_task0 from "@lit/task";
|
|
12
8
|
import * as lit1 from "lit";
|
|
13
9
|
import { LitElement, PropertyValueMap } from "lit";
|
|
14
|
-
import * as mediabunny0 from "mediabunny";
|
|
15
10
|
|
|
16
11
|
//#region src/elements/EFMedia.d.ts
|
|
17
12
|
declare global {
|
|
18
13
|
var EF_FRAMEGEN: EFFramegen;
|
|
19
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Simple async value wrapper that mimics Lit Task interface.
|
|
17
|
+
* Used for backwards compatibility with code expecting task-like objects.
|
|
18
|
+
*/
|
|
19
|
+
declare class AsyncValue<T> {
|
|
20
|
+
#private;
|
|
21
|
+
get value(): T | undefined;
|
|
22
|
+
get error(): Error | undefined;
|
|
23
|
+
get status(): number;
|
|
24
|
+
get taskComplete(): Promise<T | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Set the value (marks status as complete)
|
|
27
|
+
*/
|
|
28
|
+
setValue(value: T): void;
|
|
29
|
+
/**
|
|
30
|
+
* Set an error (marks status as error)
|
|
31
|
+
*/
|
|
32
|
+
setError(error: Error): void;
|
|
33
|
+
/**
|
|
34
|
+
* Start a new async operation
|
|
35
|
+
*/
|
|
36
|
+
startPending(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Run an async function and update status accordingly
|
|
39
|
+
*/
|
|
40
|
+
run(fn: () => Promise<T>): Promise<T | undefined>;
|
|
41
|
+
}
|
|
20
42
|
declare const EFMedia_base: (new (...args: any[]) => EFSourceMixinInterface) & (new (...args: any[]) => TemporalMixinInterface) & (new (...args: any[]) => FetchMixinInterface) & typeof LitElement;
|
|
21
43
|
declare class EFMedia extends EFMedia_base {
|
|
44
|
+
#private;
|
|
22
45
|
get efContext(): ControllableInterface | null;
|
|
23
46
|
static readonly VIDEO_SAMPLE_BUFFER_SIZE = 30;
|
|
24
47
|
static readonly AUDIO_SAMPLE_BUFFER_SIZE = 120;
|
|
@@ -75,25 +98,48 @@ declare class EFMedia extends EFMedia_base {
|
|
|
75
98
|
* @domAttribute "interpolate-frequencies"
|
|
76
99
|
*/
|
|
77
100
|
interpolateFrequencies: boolean;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
getFreqWeights(): Float32Array;
|
|
102
|
+
getShouldInterpolateFrequencies(): boolean;
|
|
103
|
+
getUrlGenerator(): UrlGenerator;
|
|
104
|
+
/**
|
|
105
|
+
* Async wrapper that mimics Task interface for backwards compatibility.
|
|
106
|
+
* Code expecting mediaEngineTask.value, .taskComplete, .error, .status will still work.
|
|
107
|
+
*/
|
|
108
|
+
mediaEngineTask: AsyncValue<MediaEngine>;
|
|
109
|
+
/**
|
|
110
|
+
* Get or create the MediaEngine for this element.
|
|
111
|
+
* Uses caching based on src/assetId to avoid redundant fetches.
|
|
112
|
+
*/
|
|
113
|
+
getMediaEngine(signal?: AbortSignal): Promise<MediaEngine | undefined>;
|
|
114
|
+
/**
|
|
115
|
+
* Async wrapper for frequency data - mimics Task interface for EFWaveform compatibility
|
|
116
|
+
*/
|
|
117
|
+
frequencyDataTask: AsyncValue<Uint8Array | null>;
|
|
118
|
+
/**
|
|
119
|
+
* Async wrapper for time domain data - mimics Task interface for EFWaveform compatibility
|
|
120
|
+
*/
|
|
121
|
+
byteTimeDomainTask: AsyncValue<Uint8Array | null>;
|
|
122
|
+
/**
|
|
123
|
+
* Get frequency data for audio visualization at a given time.
|
|
124
|
+
*/
|
|
125
|
+
getFrequencyData(timeMs: number, signal?: AbortSignal): Promise<Uint8Array | null>;
|
|
126
|
+
/**
|
|
127
|
+
* Get time domain data for audio visualization at a given time.
|
|
128
|
+
*/
|
|
129
|
+
getTimeDomainData(timeMs: number, signal?: AbortSignal): Promise<Uint8Array | null>;
|
|
130
|
+
audioSegmentIdTask: AsyncValue<number | undefined>;
|
|
131
|
+
audioInitSegmentFetchTask: AsyncValue<ArrayBuffer | undefined>;
|
|
132
|
+
audioSegmentFetchTask: AsyncValue<ArrayBuffer | undefined>;
|
|
133
|
+
audioInputTask: AsyncValue<any>;
|
|
134
|
+
audioSeekTask: AsyncValue<any>;
|
|
135
|
+
audioBufferTask: AsyncValue<any>;
|
|
90
136
|
/**
|
|
91
137
|
* The unique identifier for the media asset.
|
|
92
138
|
* This property can be set programmatically or via the "asset-id" attribute.
|
|
93
139
|
* @domAttribute "asset-id"
|
|
94
140
|
*/
|
|
95
141
|
assetId: string | null;
|
|
96
|
-
get intrinsicDurationMs(): number;
|
|
142
|
+
get intrinsicDurationMs(): number | undefined;
|
|
97
143
|
protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
|
|
98
144
|
get hasOwnDuration(): boolean;
|
|
99
145
|
private _desiredSeekTimeMs;
|
|
@@ -125,5 +171,5 @@ declare class EFMedia extends EFMedia_base {
|
|
|
125
171
|
renderAudio(fromMs: number, toMs: number): Promise<AudioBuffer>;
|
|
126
172
|
}
|
|
127
173
|
//#endregion
|
|
128
|
-
export { EFMedia };
|
|
174
|
+
export { AsyncValue, EFMedia };
|
|
129
175
|
//# sourceMappingURL=EFMedia.d.ts.map
|