@editframe/elements 0.26.2-beta.0 → 0.26.4-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/elements/EFTimegroup.js +7 -2
- package/dist/elements/EFTimegroup.js.map +1 -1
- package/package.json +2 -2
- package/scripts/build-css.js +3 -3
- package/tsdown.config.ts +1 -1
- package/types.json +1 -1
- package/src/elements/ContextProxiesController.ts +0 -124
- package/src/elements/CrossUpdateController.ts +0 -22
- package/src/elements/EFAudio.browsertest.ts +0 -706
- package/src/elements/EFAudio.ts +0 -56
- package/src/elements/EFCaptions.browsertest.ts +0 -1960
- package/src/elements/EFCaptions.ts +0 -823
- package/src/elements/EFImage.browsertest.ts +0 -120
- package/src/elements/EFImage.ts +0 -113
- package/src/elements/EFMedia/AssetIdMediaEngine.test.ts +0 -224
- package/src/elements/EFMedia/AssetIdMediaEngine.ts +0 -110
- package/src/elements/EFMedia/AssetMediaEngine.browsertest.ts +0 -140
- package/src/elements/EFMedia/AssetMediaEngine.ts +0 -385
- package/src/elements/EFMedia/BaseMediaEngine.browsertest.ts +0 -400
- package/src/elements/EFMedia/BaseMediaEngine.ts +0 -505
- package/src/elements/EFMedia/BufferedSeekingInput.browsertest.ts +0 -386
- package/src/elements/EFMedia/BufferedSeekingInput.ts +0 -430
- package/src/elements/EFMedia/JitMediaEngine.browsertest.ts +0 -226
- package/src/elements/EFMedia/JitMediaEngine.ts +0 -256
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +0 -679
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +0 -117
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +0 -246
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.browsertest.ts +0 -59
- package/src/elements/EFMedia/audioTasks/makeAudioInitSegmentFetchTask.ts +0 -27
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.browsertest.ts +0 -55
- package/src/elements/EFMedia/audioTasks/makeAudioInputTask.ts +0 -53
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +0 -207
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.ts +0 -72
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentFetchTask.ts +0 -32
- package/src/elements/EFMedia/audioTasks/makeAudioSegmentIdTask.ts +0 -29
- package/src/elements/EFMedia/audioTasks/makeAudioTasksVideoOnly.browsertest.ts +0 -95
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +0 -184
- package/src/elements/EFMedia/shared/AudioSpanUtils.ts +0 -129
- package/src/elements/EFMedia/shared/BufferUtils.ts +0 -342
- package/src/elements/EFMedia/shared/GlobalInputCache.ts +0 -77
- package/src/elements/EFMedia/shared/MediaTaskUtils.ts +0 -44
- package/src/elements/EFMedia/shared/PrecisionUtils.ts +0 -46
- package/src/elements/EFMedia/shared/RenditionHelpers.browsertest.ts +0 -246
- package/src/elements/EFMedia/shared/RenditionHelpers.ts +0 -56
- package/src/elements/EFMedia/shared/ThumbnailExtractor.ts +0 -227
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +0 -167
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +0 -88
- package/src/elements/EFMedia/videoTasks/MainVideoInputCache.ts +0 -76
- package/src/elements/EFMedia/videoTasks/ScrubInputCache.ts +0 -61
- package/src/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.ts +0 -114
- package/src/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.ts +0 -35
- package/src/elements/EFMedia/videoTasks/makeScrubVideoInputTask.ts +0 -52
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +0 -124
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.ts +0 -44
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.ts +0 -32
- package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +0 -370
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +0 -109
- package/src/elements/EFMedia.browsertest.ts +0 -872
- package/src/elements/EFMedia.ts +0 -341
- package/src/elements/EFSourceMixin.ts +0 -60
- package/src/elements/EFSurface.browsertest.ts +0 -151
- package/src/elements/EFSurface.ts +0 -142
- package/src/elements/EFTemporal.browsertest.ts +0 -215
- package/src/elements/EFTemporal.ts +0 -800
- package/src/elements/EFThumbnailStrip.browsertest.ts +0 -585
- package/src/elements/EFThumbnailStrip.media-engine.browsertest.ts +0 -714
- package/src/elements/EFThumbnailStrip.ts +0 -906
- package/src/elements/EFTimegroup.browsertest.ts +0 -870
- package/src/elements/EFTimegroup.ts +0 -878
- package/src/elements/EFVideo.browsertest.ts +0 -1482
- package/src/elements/EFVideo.ts +0 -564
- package/src/elements/EFWaveform.ts +0 -547
- package/src/elements/FetchContext.browsertest.ts +0 -401
- package/src/elements/FetchMixin.ts +0 -38
- package/src/elements/SampleBuffer.ts +0 -94
- package/src/elements/TargetController.browsertest.ts +0 -230
- package/src/elements/TargetController.ts +0 -224
- package/src/elements/TimegroupController.ts +0 -26
- package/src/elements/durationConverter.ts +0 -35
- package/src/elements/parseTimeToMs.ts +0 -9
- package/src/elements/printTaskStatus.ts +0 -16
- package/src/elements/renderTemporalAudio.ts +0 -108
- package/src/elements/updateAnimations.browsertest.ts +0 -1884
- package/src/elements/updateAnimations.ts +0 -217
- package/src/elements/util.ts +0 -24
- package/src/gui/ContextMixin.browsertest.ts +0 -860
- package/src/gui/ContextMixin.ts +0 -562
- package/src/gui/Controllable.browsertest.ts +0 -258
- package/src/gui/Controllable.ts +0 -41
- package/src/gui/EFConfiguration.ts +0 -40
- package/src/gui/EFControls.browsertest.ts +0 -389
- package/src/gui/EFControls.ts +0 -195
- package/src/gui/EFDial.browsertest.ts +0 -84
- package/src/gui/EFDial.ts +0 -172
- package/src/gui/EFFilmstrip.browsertest.ts +0 -712
- package/src/gui/EFFilmstrip.ts +0 -1349
- package/src/gui/EFFitScale.ts +0 -152
- package/src/gui/EFFocusOverlay.ts +0 -79
- package/src/gui/EFPause.browsertest.ts +0 -202
- package/src/gui/EFPause.ts +0 -73
- package/src/gui/EFPlay.browsertest.ts +0 -202
- package/src/gui/EFPlay.ts +0 -73
- package/src/gui/EFPreview.ts +0 -74
- package/src/gui/EFResizableBox.browsertest.ts +0 -79
- package/src/gui/EFResizableBox.ts +0 -898
- package/src/gui/EFScrubber.ts +0 -151
- package/src/gui/EFTimeDisplay.browsertest.ts +0 -237
- package/src/gui/EFTimeDisplay.ts +0 -55
- package/src/gui/EFToggleLoop.ts +0 -35
- package/src/gui/EFTogglePlay.ts +0 -70
- package/src/gui/EFWorkbench.ts +0 -115
- package/src/gui/PlaybackController.ts +0 -527
- package/src/gui/TWMixin.css +0 -6
- package/src/gui/TWMixin.ts +0 -61
- package/src/gui/TargetOrContextMixin.ts +0 -185
- package/src/gui/currentTimeContext.ts +0 -5
- package/src/gui/durationContext.ts +0 -3
- package/src/gui/efContext.ts +0 -6
- package/src/gui/fetchContext.ts +0 -5
- package/src/gui/focusContext.ts +0 -7
- package/src/gui/focusedElementContext.ts +0 -5
- package/src/gui/playingContext.ts +0 -5
- package/src/otel/BridgeSpanExporter.ts +0 -150
- package/src/otel/setupBrowserTracing.ts +0 -73
- package/src/otel/tracingHelpers.ts +0 -251
- package/src/transcoding/cache/RequestDeduplicator.test.ts +0 -170
- package/src/transcoding/cache/RequestDeduplicator.ts +0 -65
- package/src/transcoding/cache/URLTokenDeduplicator.test.ts +0 -182
- package/src/transcoding/cache/URLTokenDeduplicator.ts +0 -101
- package/src/transcoding/types/index.ts +0 -312
- package/src/transcoding/utils/MediaUtils.ts +0 -63
- package/src/transcoding/utils/UrlGenerator.ts +0 -68
- package/src/transcoding/utils/constants.ts +0 -36
- package/src/utils/LRUCache.test.ts +0 -274
- package/src/utils/LRUCache.ts +0 -696
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AudioRendition,
|
|
3
|
-
MediaEngine,
|
|
4
|
-
RenditionId,
|
|
5
|
-
ThumbnailResult,
|
|
6
|
-
VideoRendition,
|
|
7
|
-
} from "../../transcoding/types";
|
|
8
|
-
import type { ManifestResponse } from "../../transcoding/types/index.js";
|
|
9
|
-
import type { UrlGenerator } from "../../transcoding/utils/UrlGenerator";
|
|
10
|
-
import type { EFMedia } from "../EFMedia.js";
|
|
11
|
-
import { BaseMediaEngine } from "./BaseMediaEngine";
|
|
12
|
-
import { ThumbnailExtractor } from "./shared/ThumbnailExtractor.js";
|
|
13
|
-
|
|
14
|
-
export class JitMediaEngine extends BaseMediaEngine implements MediaEngine {
|
|
15
|
-
private urlGenerator: UrlGenerator;
|
|
16
|
-
private data: ManifestResponse = {} as ManifestResponse;
|
|
17
|
-
private thumbnailExtractor: ThumbnailExtractor;
|
|
18
|
-
|
|
19
|
-
static async fetch(host: EFMedia, urlGenerator: UrlGenerator, url: string) {
|
|
20
|
-
const engine = new JitMediaEngine(host, urlGenerator);
|
|
21
|
-
const data = await engine.fetchManifest(url);
|
|
22
|
-
engine.data = data;
|
|
23
|
-
return engine;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
constructor(host: EFMedia, urlGenerator: UrlGenerator) {
|
|
27
|
-
super(host);
|
|
28
|
-
this.urlGenerator = urlGenerator;
|
|
29
|
-
this.thumbnailExtractor = new ThumbnailExtractor(this);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get durationMs() {
|
|
33
|
-
return this.data.durationMs;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
get src() {
|
|
37
|
-
return this.data.sourceUrl;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
get audioRendition(): AudioRendition | undefined {
|
|
41
|
-
if (!this.data.audioRenditions || this.data.audioRenditions.length === 0) {
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const rendition = this.data.audioRenditions[0];
|
|
46
|
-
if (!rendition) return undefined;
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
id: rendition.id as RenditionId,
|
|
50
|
-
trackId: undefined,
|
|
51
|
-
src: this.data.sourceUrl,
|
|
52
|
-
segmentDurationMs: rendition.segmentDurationMs,
|
|
53
|
-
segmentDurationsMs: rendition.segmentDurationsMs,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
get videoRendition(): VideoRendition | undefined {
|
|
58
|
-
if (!this.data.videoRenditions || this.data.videoRenditions.length === 0) {
|
|
59
|
-
return undefined;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const rendition = this.data.videoRenditions[0];
|
|
63
|
-
if (!rendition) return undefined;
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
id: rendition.id as RenditionId,
|
|
67
|
-
trackId: undefined,
|
|
68
|
-
src: this.data.sourceUrl,
|
|
69
|
-
segmentDurationMs: rendition.segmentDurationMs,
|
|
70
|
-
segmentDurationsMs: rendition.segmentDurationsMs,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
get templates() {
|
|
75
|
-
return this.data.endpoints;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async fetchInitSegment(
|
|
79
|
-
rendition: { id?: RenditionId; trackId: number | undefined; src: string },
|
|
80
|
-
signal: AbortSignal,
|
|
81
|
-
) {
|
|
82
|
-
if (!rendition.id) {
|
|
83
|
-
throw new Error("Rendition ID is required for JIT metadata");
|
|
84
|
-
}
|
|
85
|
-
const url = this.urlGenerator.generateSegmentUrl(
|
|
86
|
-
"init",
|
|
87
|
-
rendition.id,
|
|
88
|
-
this,
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
// Use unified fetch method
|
|
92
|
-
return this.fetchMedia(url, signal);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async fetchMediaSegment(
|
|
96
|
-
segmentId: number,
|
|
97
|
-
rendition: { id?: RenditionId; trackId: number | undefined; src: string },
|
|
98
|
-
) {
|
|
99
|
-
if (!rendition.id) {
|
|
100
|
-
throw new Error("Rendition ID is required for JIT metadata");
|
|
101
|
-
}
|
|
102
|
-
const url = this.urlGenerator.generateSegmentUrl(
|
|
103
|
-
segmentId,
|
|
104
|
-
rendition.id,
|
|
105
|
-
this,
|
|
106
|
-
);
|
|
107
|
-
return this.fetchMedia(url);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
computeSegmentId(
|
|
111
|
-
desiredSeekTimeMs: number,
|
|
112
|
-
rendition: VideoRendition | AudioRendition,
|
|
113
|
-
) {
|
|
114
|
-
// Don't request segments beyond the actual file duration
|
|
115
|
-
// Note: seeking to exactly durationMs should be allowed (it's the last moment of the file)
|
|
116
|
-
if (desiredSeekTimeMs > this.durationMs) {
|
|
117
|
-
return undefined;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Use actual segment durations if available (more accurate)
|
|
121
|
-
if (
|
|
122
|
-
rendition.segmentDurationsMs &&
|
|
123
|
-
rendition.segmentDurationsMs.length > 0
|
|
124
|
-
) {
|
|
125
|
-
let cumulativeTime = 0;
|
|
126
|
-
|
|
127
|
-
for (let i = 0; i < rendition.segmentDurationsMs.length; i++) {
|
|
128
|
-
const segmentDuration = rendition.segmentDurationsMs[i];
|
|
129
|
-
if (segmentDuration === undefined) {
|
|
130
|
-
throw new Error("Segment duration is required for JIT metadata");
|
|
131
|
-
}
|
|
132
|
-
const segmentStartMs = cumulativeTime;
|
|
133
|
-
const segmentEndMs = cumulativeTime + segmentDuration;
|
|
134
|
-
|
|
135
|
-
// Check if the desired seek time falls within this segment
|
|
136
|
-
// Special case: for the last segment, include the exact end time
|
|
137
|
-
const isLastSegment = i === rendition.segmentDurationsMs.length - 1;
|
|
138
|
-
const includesEndTime =
|
|
139
|
-
isLastSegment && desiredSeekTimeMs === this.durationMs;
|
|
140
|
-
|
|
141
|
-
if (
|
|
142
|
-
desiredSeekTimeMs >= segmentStartMs &&
|
|
143
|
-
(desiredSeekTimeMs < segmentEndMs || includesEndTime)
|
|
144
|
-
) {
|
|
145
|
-
return i + 1; // Convert 0-based to 1-based segment ID
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
cumulativeTime += segmentDuration;
|
|
149
|
-
|
|
150
|
-
// If we've reached or exceeded file duration, stop
|
|
151
|
-
if (cumulativeTime >= this.durationMs) {
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// If we didn't find a segment, return undefined
|
|
157
|
-
return undefined;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Fall back to fixed duration calculation for backward compatibility
|
|
161
|
-
if (!rendition.segmentDurationMs) {
|
|
162
|
-
throw new Error("Segment duration is required for JIT metadata");
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const segmentIndex = Math.floor(
|
|
166
|
-
desiredSeekTimeMs / rendition.segmentDurationMs,
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
// Calculate the actual segment start time
|
|
170
|
-
const segmentStartMs = segmentIndex * rendition.segmentDurationMs;
|
|
171
|
-
|
|
172
|
-
// If this segment would start at or beyond file duration, it doesn't exist
|
|
173
|
-
if (segmentStartMs >= this.durationMs) {
|
|
174
|
-
return undefined;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return segmentIndex + 1; // Convert 0-based to 1-based
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
getScrubVideoRendition(): VideoRendition | undefined {
|
|
181
|
-
if (!this.data.videoRenditions) return undefined;
|
|
182
|
-
|
|
183
|
-
const scrubManifestRendition = this.data.videoRenditions.find(
|
|
184
|
-
(r) => r.id === "scrub",
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
if (!scrubManifestRendition) return this.videoRendition; // Fallback to main
|
|
188
|
-
|
|
189
|
-
return {
|
|
190
|
-
id: scrubManifestRendition.id as any,
|
|
191
|
-
trackId: undefined,
|
|
192
|
-
src: this.src,
|
|
193
|
-
segmentDurationMs: scrubManifestRendition.segmentDurationMs,
|
|
194
|
-
segmentDurationsMs: scrubManifestRendition.segmentDurationsMs,
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Get preferred buffer configuration for JIT transcoding
|
|
200
|
-
* Uses higher buffering since transcoding introduces latency
|
|
201
|
-
*/
|
|
202
|
-
getBufferConfig() {
|
|
203
|
-
return {
|
|
204
|
-
// Buffer more aggressively for JIT transcoding to smooth over latency
|
|
205
|
-
videoBufferDurationMs: 8000,
|
|
206
|
-
audioBufferDurationMs: 8000,
|
|
207
|
-
maxVideoBufferFetches: 3,
|
|
208
|
-
maxAudioBufferFetches: 3,
|
|
209
|
-
bufferThresholdMs: 30000, // Timeline-aware buffering threshold
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Extract thumbnail canvases using same rendition priority as video playback for frame alignment
|
|
215
|
-
*/
|
|
216
|
-
async extractThumbnails(
|
|
217
|
-
timestamps: number[],
|
|
218
|
-
): Promise<(ThumbnailResult | null)[]> {
|
|
219
|
-
// Use same rendition priority as video: try main rendition first for frame alignment
|
|
220
|
-
let rendition: VideoRendition;
|
|
221
|
-
try {
|
|
222
|
-
const mainRendition = this.getVideoRendition();
|
|
223
|
-
if (mainRendition) {
|
|
224
|
-
rendition = mainRendition;
|
|
225
|
-
} else {
|
|
226
|
-
const scrubRendition = this.getScrubVideoRendition();
|
|
227
|
-
if (scrubRendition) {
|
|
228
|
-
rendition = scrubRendition;
|
|
229
|
-
} else {
|
|
230
|
-
throw new Error("No video rendition available");
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
} catch (error) {
|
|
234
|
-
console.warn(
|
|
235
|
-
"JitMediaEngine: No video rendition available for thumbnails",
|
|
236
|
-
error,
|
|
237
|
-
);
|
|
238
|
-
return timestamps.map(() => null);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Use shared thumbnail extraction logic
|
|
242
|
-
return this.thumbnailExtractor.extractThumbnails(
|
|
243
|
-
timestamps,
|
|
244
|
-
rendition,
|
|
245
|
-
this.durationMs,
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
convertToSegmentRelativeTimestamps(
|
|
250
|
-
globalTimestamps: number[],
|
|
251
|
-
_segmentId: number,
|
|
252
|
-
_rendition: VideoRendition,
|
|
253
|
-
): number[] {
|
|
254
|
-
return globalTimestamps.map((timestamp) => timestamp / 1000);
|
|
255
|
-
}
|
|
256
|
-
}
|