@editframe/elements 0.18.23-beta.0 → 0.18.27-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/EFMedia/AssetMediaEngine.d.ts +2 -1
- package/dist/elements/EFMedia/AssetMediaEngine.js +3 -0
- package/dist/elements/EFMedia/BaseMediaEngine.d.ts +9 -0
- package/dist/elements/EFMedia/BaseMediaEngine.js +27 -0
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +1 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +12 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +11 -5
- package/dist/elements/EFMedia/shared/BufferUtils.d.ts +19 -18
- package/dist/elements/EFMedia/shared/BufferUtils.js +24 -44
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.d.ts +8 -0
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.js +5 -5
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.d.ts +25 -0
- package/dist/elements/EFMedia/videoTasks/ScrubInputCache.js +42 -0
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.d.ts +8 -0
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +70 -0
- package/dist/elements/EFMedia/videoTasks/{makeVideoInitSegmentFetchTask.d.ts → makeScrubVideoInitSegmentFetchTask.d.ts} +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.js +21 -0
- package/dist/elements/EFMedia/videoTasks/{makeVideoInputTask.d.ts → makeScrubVideoInputTask.d.ts} +1 -1
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoInputTask.js +27 -0
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.d.ts +6 -0
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.js +52 -0
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.js +23 -0
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoSegmentIdTask.d.ts +4 -0
- package/dist/elements/EFMedia/videoTasks/{makeVideoSegmentIdTask.js → makeScrubVideoSegmentIdTask.js} +9 -4
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.d.ts +6 -0
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +112 -0
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +11 -5
- package/dist/elements/EFMedia.d.ts +0 -10
- package/dist/elements/EFMedia.js +1 -17
- package/dist/elements/EFVideo.d.ts +11 -9
- package/dist/elements/EFVideo.js +31 -23
- package/dist/gui/EFConfiguration.d.ts +1 -0
- package/dist/gui/EFConfiguration.js +5 -0
- package/dist/gui/EFFilmstrip.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/transcoding/types/index.d.ts +11 -0
- package/package.json +2 -2
- package/src/elements/EFCaptions.ts +1 -1
- package/src/elements/EFImage.ts +1 -1
- package/src/elements/EFMedia/AssetMediaEngine.ts +6 -0
- package/src/elements/EFMedia/BaseMediaEngine.ts +54 -0
- package/src/elements/EFMedia/JitMediaEngine.ts +18 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +185 -59
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +19 -6
- package/src/elements/EFMedia/shared/BufferUtils.ts +71 -85
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.browsertest.ts +151 -112
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.ts +12 -5
- package/src/elements/EFMedia/videoTasks/ScrubInputCache.ts +61 -0
- package/src/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.ts +113 -0
- package/src/elements/EFMedia/videoTasks/{makeVideoInitSegmentFetchTask.ts → makeScrubVideoInitSegmentFetchTask.ts} +15 -3
- package/src/elements/EFMedia/videoTasks/{makeVideoInputTask.ts → makeScrubVideoInputTask.ts} +11 -10
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSeekTask.ts +118 -0
- package/src/elements/EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.ts +44 -0
- package/src/elements/EFMedia/videoTasks/{makeVideoSegmentIdTask.ts → makeScrubVideoSegmentIdTask.ts} +14 -6
- package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +258 -0
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +19 -5
- package/src/elements/EFMedia.browsertest.ts +74 -11
- package/src/elements/EFMedia.ts +1 -23
- package/src/elements/EFVideo.browsertest.ts +204 -80
- package/src/elements/EFVideo.ts +38 -26
- package/src/elements/TargetController.browsertest.ts +1 -1
- package/src/gui/EFConfiguration.ts +4 -1
- package/src/gui/EFFilmstrip.ts +4 -4
- package/src/gui/EFFocusOverlay.ts +1 -1
- package/src/gui/EFPreview.ts +3 -4
- package/src/gui/EFScrubber.ts +1 -1
- package/src/gui/EFTimeDisplay.ts +1 -1
- package/src/gui/EFToggleLoop.ts +1 -1
- package/src/gui/EFTogglePlay.ts +1 -1
- package/src/gui/EFWorkbench.ts +1 -1
- package/src/transcoding/types/index.ts +16 -0
- package/test/__cache__/GET__api_v1_transcode_scrub_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__6ff5127ebeda578a679474347fbd6137/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_scrub_1_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__6ff5127ebeda578a679474347fbd6137/metadata.json +16 -0
- package/test/__cache__/GET__api_v1_transcode_scrub_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__f6d4793fc9ff854ee9a738917fb64a53/data.bin +0 -0
- package/test/__cache__/GET__api_v1_transcode_scrub_init_m4s_url_http_3A_2F_2Fweb_3A3000_2Fhead_moov_480p_mp4__f6d4793fc9ff854ee9a738917fb64a53/metadata.json +16 -0
- package/test/cache-integration-verification.browsertest.ts +84 -0
- package/types.json +1 -1
- package/dist/elements/EFMedia/tasks/makeMediaEngineTask.test.d.ts +0 -1
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.d.ts +0 -9
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.d.ts +0 -9
- package/dist/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.js +0 -16
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.d.ts +0 -9
- package/dist/elements/EFMedia/videoTasks/makeVideoInputTask.js +0 -27
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.d.ts +0 -7
- package/dist/elements/EFMedia/videoTasks/makeVideoSeekTask.js +0 -34
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.d.ts +0 -9
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.d.ts +0 -4
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.js +0 -28
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.d.ts +0 -9
- package/dist/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.d.ts +0 -4
- package/src/elements/EFMedia/tasks/makeMediaEngineTask.test.ts +0 -233
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.browsertest.ts +0 -555
- package/src/elements/EFMedia/videoTasks/makeVideoInitSegmentFetchTask.browsertest.ts +0 -59
- package/src/elements/EFMedia/videoTasks/makeVideoInputTask.browsertest.ts +0 -55
- package/src/elements/EFMedia/videoTasks/makeVideoSeekTask.ts +0 -65
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.browsertest.ts +0 -57
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentFetchTask.ts +0 -43
- package/src/elements/EFMedia/videoTasks/makeVideoSegmentIdTask.browsertest.ts +0 -56
package/src/elements/EFVideo.ts
CHANGED
|
@@ -7,12 +7,14 @@ import { createRef, ref } from "lit/directives/ref.js";
|
|
|
7
7
|
import { DelayedLoadingState } from "../DelayedLoadingState.js";
|
|
8
8
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
9
9
|
import { TWMixin } from "../gui/TWMixin.js";
|
|
10
|
+
import { makeScrubVideoBufferTask } from "./EFMedia/videoTasks/makeScrubVideoBufferTask.ts";
|
|
11
|
+
import { makeScrubVideoInitSegmentFetchTask } from "./EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.ts";
|
|
12
|
+
import { makeScrubVideoInputTask } from "./EFMedia/videoTasks/makeScrubVideoInputTask.ts";
|
|
13
|
+
import { makeScrubVideoSeekTask } from "./EFMedia/videoTasks/makeScrubVideoSeekTask.ts";
|
|
14
|
+
import { makeScrubVideoSegmentFetchTask } from "./EFMedia/videoTasks/makeScrubVideoSegmentFetchTask.ts";
|
|
15
|
+
import { makeScrubVideoSegmentIdTask } from "./EFMedia/videoTasks/makeScrubVideoSegmentIdTask.ts";
|
|
16
|
+
import { makeUnifiedVideoSeekTask } from "./EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts";
|
|
10
17
|
import { makeVideoBufferTask } from "./EFMedia/videoTasks/makeVideoBufferTask.ts";
|
|
11
|
-
import { makeVideoInitSegmentFetchTask } from "./EFMedia/videoTasks/makeVideoInitSegmentFetchTask.ts";
|
|
12
|
-
import { makeVideoInputTask } from "./EFMedia/videoTasks/makeVideoInputTask.ts";
|
|
13
|
-
import { makeVideoSeekTask } from "./EFMedia/videoTasks/makeVideoSeekTask.ts";
|
|
14
|
-
import { makeVideoSegmentFetchTask } from "./EFMedia/videoTasks/makeVideoSegmentFetchTask.ts";
|
|
15
|
-
import { makeVideoSegmentIdTask } from "./EFMedia/videoTasks/makeVideoSegmentIdTask.ts";
|
|
16
18
|
import { EFMedia } from "./EFMedia.js";
|
|
17
19
|
|
|
18
20
|
// EF_FRAMEGEN is a global instance created in EF_FRAMEGEN.ts
|
|
@@ -98,7 +100,7 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
98
100
|
* @domAttribute "video-buffer-duration"
|
|
99
101
|
*/
|
|
100
102
|
@property({ type: Number, attribute: "video-buffer-duration" })
|
|
101
|
-
videoBufferDurationMs =
|
|
103
|
+
videoBufferDurationMs = 10000; // 10 seconds - reasonable for JIT encoding
|
|
102
104
|
|
|
103
105
|
/**
|
|
104
106
|
* Maximum number of concurrent video segment fetches for buffering
|
|
@@ -114,13 +116,17 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
114
116
|
@property({ type: Boolean, attribute: "enable-video-buffering" })
|
|
115
117
|
enableVideoBuffering = true;
|
|
116
118
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
119
|
+
// Unified video system - single smart seek task that routes to scrub or main
|
|
120
|
+
unifiedVideoSeekTask = makeUnifiedVideoSeekTask(this);
|
|
121
|
+
videoBufferTask = makeVideoBufferTask(this); // Keep for main video buffering
|
|
122
|
+
|
|
123
|
+
// Scrub video preloading system
|
|
124
|
+
scrubVideoBufferTask = makeScrubVideoBufferTask(this);
|
|
125
|
+
scrubVideoInputTask = makeScrubVideoInputTask(this);
|
|
126
|
+
scrubVideoSeekTask = makeScrubVideoSeekTask(this);
|
|
127
|
+
scrubVideoSegmentIdTask = makeScrubVideoSegmentIdTask(this);
|
|
128
|
+
scrubVideoSegmentFetchTask = makeScrubVideoSegmentFetchTask(this);
|
|
129
|
+
scrubVideoInitSegmentFetchTask = makeScrubVideoInitSegmentFetchTask(this);
|
|
124
130
|
|
|
125
131
|
/**
|
|
126
132
|
* Delayed loading state manager for user feedback
|
|
@@ -190,7 +196,7 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
190
196
|
},
|
|
191
197
|
onComplete: () => {},
|
|
192
198
|
task: async ([_desiredSeekTimeMs], { signal }) => {
|
|
193
|
-
await this.
|
|
199
|
+
await this.unifiedVideoSeekTask.taskComplete;
|
|
194
200
|
await this.paintTask.taskComplete;
|
|
195
201
|
if (signal.aborted) {
|
|
196
202
|
return;
|
|
@@ -244,18 +250,24 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
244
250
|
},
|
|
245
251
|
onComplete: () => {},
|
|
246
252
|
task: async ([_seekToMs], { signal }) => {
|
|
247
|
-
await this.videoSeekTask.taskComplete;
|
|
248
253
|
// Check if we're in production rendering mode vs preview mode
|
|
249
254
|
const isProductionRendering = this.isInProductionRenderingMode();
|
|
250
255
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
videoFrame.
|
|
256
|
+
// Unified video system: smart routing to scrub or main, with background upgrades
|
|
257
|
+
try {
|
|
258
|
+
await this.unifiedVideoSeekTask.taskComplete;
|
|
259
|
+
const videoSample = this.unifiedVideoSeekTask.value;
|
|
260
|
+
|
|
261
|
+
if (videoSample) {
|
|
262
|
+
const videoFrame = videoSample.toVideoFrame();
|
|
263
|
+
try {
|
|
264
|
+
this.displayFrame(videoFrame, _seekToMs);
|
|
265
|
+
} finally {
|
|
266
|
+
videoFrame.close();
|
|
267
|
+
}
|
|
258
268
|
}
|
|
269
|
+
} catch (error) {
|
|
270
|
+
console.warn("Unified video pipeline error:", error);
|
|
259
271
|
}
|
|
260
272
|
|
|
261
273
|
// EF_FRAMEGEN-aware rendering mode detection
|
|
@@ -292,7 +304,7 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
292
304
|
/**
|
|
293
305
|
* Display a video frame on the canvas
|
|
294
306
|
*/
|
|
295
|
-
|
|
307
|
+
displayFrame(frame: VideoFrame, seekToMs: number): number {
|
|
296
308
|
log("trace: displayFrame start", { seekToMs, frameFormat: frame.format });
|
|
297
309
|
if (!this.canvasElement) {
|
|
298
310
|
log("trace: displayFrame aborted - no canvas element");
|
|
@@ -387,11 +399,11 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
387
399
|
}
|
|
388
400
|
|
|
389
401
|
/**
|
|
390
|
-
* Legacy getter for fragment index task
|
|
391
|
-
* Still used by EFCaptions
|
|
402
|
+
* Legacy getter for fragment index task
|
|
403
|
+
* Still used by EFCaptions - maps to unified video seek task
|
|
392
404
|
*/
|
|
393
405
|
get fragmentIndexTask() {
|
|
394
|
-
return this.
|
|
406
|
+
return this.unifiedVideoSeekTask;
|
|
395
407
|
}
|
|
396
408
|
|
|
397
409
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { html, LitElement } from "lit";
|
|
2
2
|
import { customElement, property, state } from "lit/decorators.js";
|
|
3
3
|
import { afterEach, describe, expect, test } from "vitest";
|
|
4
4
|
import { EFTargetable, TargetController } from "./TargetController.ts";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext, provide } from "@lit/context";
|
|
2
|
-
import {
|
|
2
|
+
import { css, html, LitElement } from "lit";
|
|
3
3
|
import { customElement, property } from "lit/decorators.js";
|
|
4
4
|
|
|
5
5
|
export const efConfigurationContext = createContext<EFConfiguration | null>(
|
|
@@ -25,6 +25,9 @@ export class EFConfiguration extends LitElement {
|
|
|
25
25
|
@property({ type: String, attribute: "signing-url" })
|
|
26
26
|
signingURL?: string;
|
|
27
27
|
|
|
28
|
+
@property({ type: String, attribute: "media-engine" })
|
|
29
|
+
mediaEngine?: "cloud" | "local" = "cloud";
|
|
30
|
+
|
|
28
31
|
render() {
|
|
29
32
|
return html`<slot></slot>`;
|
|
30
33
|
}
|
package/src/gui/EFFilmstrip.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { consume } from "@lit/context";
|
|
2
2
|
import {
|
|
3
|
+
css,
|
|
4
|
+
html,
|
|
3
5
|
LitElement,
|
|
6
|
+
nothing,
|
|
4
7
|
type PropertyValueMap,
|
|
5
8
|
type ReactiveController,
|
|
6
9
|
type TemplateResult,
|
|
7
|
-
css,
|
|
8
|
-
html,
|
|
9
|
-
nothing,
|
|
10
10
|
} from "lit";
|
|
11
11
|
import {
|
|
12
12
|
customElement,
|
|
@@ -29,10 +29,10 @@ import { msToTimeCode } from "../msToTimeCode.js";
|
|
|
29
29
|
import { targetTimegroupContext } from "./ContextMixin.ts";
|
|
30
30
|
import type { EFPreview } from "./EFPreview.js";
|
|
31
31
|
import type { EFWorkbench } from "./EFWorkbench.js";
|
|
32
|
-
import { TWMixin } from "./TWMixin.js";
|
|
33
32
|
import { type FocusContext, focusContext } from "./focusContext.js";
|
|
34
33
|
import { focusedElementContext } from "./focusedElementContext.js";
|
|
35
34
|
import { loopContext, playingContext } from "./playingContext.js";
|
|
35
|
+
import { TWMixin } from "./TWMixin.js";
|
|
36
36
|
|
|
37
37
|
class ElementFilmstripController implements ReactiveController {
|
|
38
38
|
constructor(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { consume } from "@lit/context";
|
|
2
|
-
import {
|
|
2
|
+
import { css, html, LitElement } from "lit";
|
|
3
3
|
import { customElement } from "lit/decorators.js";
|
|
4
4
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
5
5
|
import { focusedElementContext } from "./focusedElementContext.js";
|
package/src/gui/EFPreview.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { LitElement, css, html } from "lit";
|
|
2
|
-
import { customElement } from "lit/decorators.js";
|
|
3
|
-
|
|
4
1
|
import { provide } from "@lit/context";
|
|
2
|
+
import { css, html, LitElement } from "lit";
|
|
3
|
+
import { customElement } from "lit/decorators.js";
|
|
5
4
|
import { ContextMixin } from "./ContextMixin.js";
|
|
6
|
-
import { TWMixin } from "./TWMixin.js";
|
|
7
5
|
import { focusedElementContext } from "./focusedElementContext.js";
|
|
6
|
+
import { TWMixin } from "./TWMixin.js";
|
|
8
7
|
|
|
9
8
|
@customElement("ef-preview")
|
|
10
9
|
export class EFPreview extends ContextMixin(TWMixin(LitElement)) {
|
package/src/gui/EFScrubber.ts
CHANGED
package/src/gui/EFTimeDisplay.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { consume } from "@lit/context";
|
|
2
|
-
import {
|
|
2
|
+
import { css, html, LitElement } from "lit";
|
|
3
3
|
import { customElement } from "lit/decorators.js";
|
|
4
4
|
import type { ContextMixinInterface } from "./ContextMixin.js";
|
|
5
5
|
import { efContext } from "./efContext.js";
|
package/src/gui/EFToggleLoop.ts
CHANGED
package/src/gui/EFTogglePlay.ts
CHANGED
package/src/gui/EFWorkbench.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LitElement, type PropertyValueMap
|
|
1
|
+
import { css, html, LitElement, type PropertyValueMap } from "lit";
|
|
2
2
|
import { customElement, eventOptions, property } from "lit/decorators.js";
|
|
3
3
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
4
4
|
|
|
@@ -237,6 +237,22 @@ export interface MediaEngine {
|
|
|
237
237
|
*/
|
|
238
238
|
getAudioRendition: () => AudioRendition;
|
|
239
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Check if a segment is cached for a given rendition
|
|
242
|
+
*/
|
|
243
|
+
isSegmentCached: (
|
|
244
|
+
segmentId: number,
|
|
245
|
+
rendition: AudioRendition | VideoRendition,
|
|
246
|
+
) => boolean;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get scrub video rendition if available, otherwise return undefined
|
|
250
|
+
* Each engine implements this based on their capabilities:
|
|
251
|
+
* - JitMediaEngine: looks for "scrub" rendition in manifest
|
|
252
|
+
* - AssetMediaEngine: returns regular video rendition (no separate scrub)
|
|
253
|
+
*/
|
|
254
|
+
getScrubVideoRendition(): VideoRendition | undefined;
|
|
255
|
+
|
|
240
256
|
/**
|
|
241
257
|
* Calculate audio segments needed for a time range
|
|
242
258
|
* Each media engine implements this based on their segment structure
|
|
Binary file
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"statusCode": 200,
|
|
3
|
+
"headers": {
|
|
4
|
+
"access-control-allow-headers": "Origin, X-Requested-With, Content-Type, Accept, Authorization, Range",
|
|
5
|
+
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
6
|
+
"access-control-allow-origin": "*",
|
|
7
|
+
"access-control-expose-headers": "Content-Length, Content-Range, X-Cache, X-Actual-Start-Time, X-Actual-Duration, X-Transcode-Time-Ms, X-Total-Server-Time-Ms",
|
|
8
|
+
"cache-control": "public, max-age=3600",
|
|
9
|
+
"content-length": "645445",
|
|
10
|
+
"content-type": "video/iso.segment",
|
|
11
|
+
"x-powered-by": "Express"
|
|
12
|
+
},
|
|
13
|
+
"url": "/api/v1/transcode/scrub/1.m4s?url=http%3A%2F%2Fweb%3A3000%2Fhead-moov-480p.mp4",
|
|
14
|
+
"method": "GET",
|
|
15
|
+
"range": null
|
|
16
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"statusCode": 200,
|
|
3
|
+
"headers": {
|
|
4
|
+
"access-control-allow-headers": "Origin, X-Requested-With, Content-Type, Accept, Authorization, Range",
|
|
5
|
+
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
6
|
+
"access-control-allow-origin": "*",
|
|
7
|
+
"access-control-expose-headers": "Content-Length, Content-Range, X-Cache, X-Actual-Start-Time, X-Actual-Duration, X-Transcode-Time-Ms, X-Total-Server-Time-Ms",
|
|
8
|
+
"cache-control": "public, max-age=3600",
|
|
9
|
+
"content-length": "754",
|
|
10
|
+
"content-type": "video/iso.segment",
|
|
11
|
+
"x-powered-by": "Express"
|
|
12
|
+
},
|
|
13
|
+
"url": "/api/v1/transcode/scrub/init.m4s?url=http%3A%2F%2Fweb%3A3000%2Fhead-moov-480p.mp4",
|
|
14
|
+
"method": "GET",
|
|
15
|
+
"range": null
|
|
16
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { customElement } from "lit/decorators.js";
|
|
2
|
+
import { EFMedia } from "../src/elements/EFMedia.ts";
|
|
3
|
+
import { test as baseTest } from "./useMSW.js";
|
|
4
|
+
|
|
5
|
+
@customElement("test-cache-integration")
|
|
6
|
+
class TestCacheIntegration extends EFMedia {}
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLElementTagNameMap {
|
|
10
|
+
"test-cache-integration": TestCacheIntegration;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const test = baseTest.extend<{
|
|
15
|
+
element: TestCacheIntegration;
|
|
16
|
+
}>({
|
|
17
|
+
element: async ({}, use) => {
|
|
18
|
+
const element = document.createElement("test-cache-integration");
|
|
19
|
+
document.body.appendChild(element);
|
|
20
|
+
await use(element);
|
|
21
|
+
element.remove();
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("buffer cache integration stores and serves segment data", async ({
|
|
26
|
+
element,
|
|
27
|
+
expect,
|
|
28
|
+
}) => {
|
|
29
|
+
// Setup element with real media source
|
|
30
|
+
element.src = "bars-n-tone2.mp4";
|
|
31
|
+
element.enableAudioBuffering = true;
|
|
32
|
+
element.audioBufferDurationMs = 3000;
|
|
33
|
+
element.maxAudioBufferFetches = 2;
|
|
34
|
+
element.desiredSeekTimeMs = 0;
|
|
35
|
+
|
|
36
|
+
// Track network requests to verify cache effectiveness
|
|
37
|
+
const originalFetch = window.fetch;
|
|
38
|
+
const networkRequests: string[] = [];
|
|
39
|
+
|
|
40
|
+
window.fetch = (input: RequestInfo | URL, init?: RequestInit) => {
|
|
41
|
+
const url = input.toString();
|
|
42
|
+
if (url.includes("audio")) {
|
|
43
|
+
networkRequests.push(url);
|
|
44
|
+
console.debug("Network request:", url);
|
|
45
|
+
}
|
|
46
|
+
return originalFetch(input, init);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
// Allow initial buffering
|
|
51
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
52
|
+
|
|
53
|
+
const bufferState = element.audioBufferTask.value;
|
|
54
|
+
console.log("Buffer state after initial buffering:", {
|
|
55
|
+
cachedSegmentsCount: bufferState?.cachedSegments.size || 0,
|
|
56
|
+
cachedDataCount: bufferState?.cachedSegmentData.size || 0,
|
|
57
|
+
activeRequestsCount: bufferState?.activeRequests.size || 0,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (bufferState && bufferState.cachedSegments.size > 0) {
|
|
61
|
+
const initialNetworkRequests = networkRequests.length;
|
|
62
|
+
|
|
63
|
+
// Trigger segment fetch for potentially cached segment
|
|
64
|
+
element.desiredSeekTimeMs = 1000;
|
|
65
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
66
|
+
|
|
67
|
+
// Check if cache integration is working
|
|
68
|
+
const finalNetworkRequests = networkRequests.length;
|
|
69
|
+
|
|
70
|
+
console.log("Cache integration test results:", {
|
|
71
|
+
initialNetworkRequests,
|
|
72
|
+
finalNetworkRequests,
|
|
73
|
+
cacheHit: finalNetworkRequests === initialNetworkRequests,
|
|
74
|
+
cachedSegments: Array.from(bufferState.cachedSegments),
|
|
75
|
+
cachedData: Array.from(bufferState.cachedSegmentData.keys()),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// The test verifies that segment data is being cached
|
|
79
|
+
expect(bufferState.cachedSegmentData.size).toBeGreaterThan(0);
|
|
80
|
+
}
|
|
81
|
+
} finally {
|
|
82
|
+
window.fetch = originalFetch;
|
|
83
|
+
}
|
|
84
|
+
});
|