@editframe/elements 0.18.27-beta.0 → 0.19.2-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 +10 -0
- package/dist/elements/EFMedia/AssetMediaEngine.js +13 -1
- package/dist/elements/EFMedia/JitMediaEngine.d.ts +10 -0
- package/dist/elements/EFMedia/JitMediaEngine.js +12 -0
- package/dist/elements/EFMedia/audioTasks/makeAudioBufferTask.js +16 -12
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.d.ts +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.js +0 -4
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.d.ts +1 -1
- package/dist/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.js +0 -4
- package/dist/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.js +1 -1
- package/dist/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.js +3 -2
- package/dist/elements/EFMedia/videoTasks/makeVideoBufferTask.js +16 -12
- package/dist/elements/EFMedia.d.ts +2 -3
- package/dist/elements/EFMedia.js +0 -4
- package/dist/elements/EFTemporal.d.ts +9 -6
- package/dist/elements/EFTemporal.js +15 -12
- package/dist/elements/EFTimegroup.browsertest.d.ts +26 -0
- package/dist/elements/EFTimegroup.d.ts +12 -9
- package/dist/elements/EFTimegroup.js +114 -65
- package/dist/elements/EFVideo.d.ts +5 -1
- package/dist/elements/EFVideo.js +16 -8
- package/dist/elements/EFWaveform.js +2 -3
- package/dist/elements/FetchContext.browsertest.d.ts +0 -0
- package/dist/elements/FetchMixin.js +14 -9
- package/dist/elements/TimegroupController.js +2 -1
- package/dist/elements/updateAnimations.browsertest.d.ts +0 -0
- package/dist/elements/updateAnimations.d.ts +19 -9
- package/dist/elements/updateAnimations.js +64 -25
- package/dist/gui/ContextMixin.js +34 -27
- package/dist/gui/EFConfiguration.d.ts +1 -1
- package/dist/gui/EFConfiguration.js +1 -0
- package/dist/gui/EFFilmstrip.d.ts +1 -0
- package/dist/gui/EFFilmstrip.js +12 -14
- package/dist/gui/TWMixin.js +1 -1
- package/dist/style.css +1 -1
- package/dist/transcoding/cache/URLTokenDeduplicator.d.ts +38 -0
- package/dist/transcoding/cache/URLTokenDeduplicator.js +66 -0
- package/dist/transcoding/cache/URLTokenDeduplicator.test.d.ts +1 -0
- package/dist/transcoding/types/index.d.ts +10 -0
- package/package.json +2 -2
- package/src/elements/EFMedia/AssetMediaEngine.ts +16 -2
- package/src/elements/EFMedia/JitMediaEngine.ts +14 -0
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.browsertest.ts +0 -1
- package/src/elements/EFMedia/audioTasks/makeAudioBufferTask.ts +11 -4
- package/src/elements/EFMedia/audioTasks/makeAudioFrequencyAnalysisTask.ts +0 -4
- package/src/elements/EFMedia/audioTasks/makeAudioSeekTask.chunkboundary.regression.browsertest.ts +4 -1
- package/src/elements/EFMedia/audioTasks/makeAudioTimeDomainAnalysisTask.ts +0 -5
- package/src/elements/EFMedia/videoTasks/makeScrubVideoBufferTask.ts +2 -2
- package/src/elements/EFMedia/videoTasks/makeUnifiedVideoSeekTask.ts +7 -3
- package/src/elements/EFMedia/videoTasks/makeVideoBufferTask.ts +11 -4
- package/src/elements/EFMedia.browsertest.ts +13 -4
- package/src/elements/EFMedia.ts +6 -10
- package/src/elements/EFTemporal.ts +21 -26
- package/src/elements/EFTimegroup.browsertest.ts +186 -2
- package/src/elements/EFTimegroup.ts +190 -94
- package/src/elements/EFVideo.browsertest.ts +53 -132
- package/src/elements/EFVideo.ts +26 -13
- package/src/elements/EFWaveform.ts +2 -3
- package/src/elements/FetchContext.browsertest.ts +396 -0
- package/src/elements/FetchMixin.ts +25 -8
- package/src/elements/TimegroupController.ts +2 -1
- package/src/elements/updateAnimations.browsertest.ts +559 -0
- package/src/elements/updateAnimations.ts +113 -50
- package/src/gui/ContextMixin.browsertest.ts +4 -9
- package/src/gui/ContextMixin.ts +52 -33
- package/src/gui/EFConfiguration.ts +1 -1
- package/src/gui/EFFilmstrip.ts +15 -18
- package/src/transcoding/cache/URLTokenDeduplicator.test.ts +182 -0
- package/src/transcoding/cache/URLTokenDeduplicator.ts +101 -0
- package/src/transcoding/types/index.ts +11 -0
- package/test/EFVideo.framegen.browsertest.ts +1 -1
- package/test/setup.ts +2 -0
- package/types.json +1 -1
|
@@ -8,6 +8,7 @@ import "../gui/EFWorkbench.js";
|
|
|
8
8
|
import "../gui/EFPreview.js";
|
|
9
9
|
import "./EFTimegroup.js";
|
|
10
10
|
|
|
11
|
+
import { TaskStatus } from "@lit/task";
|
|
11
12
|
import type { EFTimegroup } from "./EFTimegroup.js";
|
|
12
13
|
|
|
13
14
|
// Helper to wait for task completion but ignore abort errors
|
|
@@ -30,6 +31,10 @@ beforeAll(async () => {
|
|
|
30
31
|
});
|
|
31
32
|
});
|
|
32
33
|
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
localStorage.clear();
|
|
36
|
+
});
|
|
37
|
+
|
|
33
38
|
// Extend the base test with fixtures following EFMedia.browsertest.ts pattern
|
|
34
39
|
const test = baseTest.extend<{
|
|
35
40
|
timegroup: EFTimegroup;
|
|
@@ -49,6 +54,7 @@ const test = baseTest.extend<{
|
|
|
49
54
|
const apiHost = "http://localhost:63315";
|
|
50
55
|
configuration.setAttribute("api-host", apiHost);
|
|
51
56
|
configuration.apiHost = apiHost;
|
|
57
|
+
configuration.signingURL = ""; // Disable URL signing for tests
|
|
52
58
|
document.body.appendChild(configuration);
|
|
53
59
|
await use(configuration);
|
|
54
60
|
},
|
|
@@ -68,18 +74,26 @@ const test = baseTest.extend<{
|
|
|
68
74
|
use(video);
|
|
69
75
|
},
|
|
70
76
|
barsNtoneTimegroup: async ({}, use) => {
|
|
77
|
+
// Clear localStorage to prevent test contamination
|
|
78
|
+
localStorage.removeItem("ef-timegroup-barsNtoneTimegroup");
|
|
79
|
+
|
|
71
80
|
const container = document.createElement("div");
|
|
72
81
|
render(
|
|
73
82
|
html`
|
|
74
83
|
<ef-configuration api-host="http://localhost:63315">
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
84
|
+
<ef-preview>
|
|
85
|
+
<ef-timegroup mode="sequence" id="barsNtoneTimegroup"
|
|
86
|
+
class="relative h-[500px] w-[1000px] overflow-hidden bg-slate-500">
|
|
87
|
+
<ef-video src="bars-n-tone.mp4" id="barsNtoneVideo"></ef-video>
|
|
88
|
+
</ef-timegroup>
|
|
89
|
+
</ef-preview>
|
|
78
90
|
</ef-configuration>
|
|
79
91
|
`,
|
|
80
92
|
container,
|
|
81
93
|
);
|
|
82
94
|
document.body.appendChild(container);
|
|
95
|
+
const configuration = container.querySelector("ef-configuration") as any;
|
|
96
|
+
configuration.signingURL = ""; // Disable URL signing for tests
|
|
83
97
|
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
84
98
|
await timegroup.updateComplete;
|
|
85
99
|
await use(timegroup);
|
|
@@ -91,23 +105,27 @@ const test = baseTest.extend<{
|
|
|
91
105
|
render(
|
|
92
106
|
html`
|
|
93
107
|
<ef-configuration api-host="http://localhost:63315">
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<ef-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
<ef-
|
|
108
|
+
<ef-preview>
|
|
109
|
+
<ef-timegroup mode="sequence"
|
|
110
|
+
class="relative h-[500px] w-[1000px] overflow-hidden bg-slate-500">
|
|
111
|
+
|
|
112
|
+
<ef-timegroup mode="contain" class="absolute w-full h-full">
|
|
113
|
+
<ef-video src="bars-n-tone.mp4" class="size-full object-fit absolute top-0 left-0"></ef-video>
|
|
114
|
+
</ef-timegroup>
|
|
115
|
+
|
|
116
|
+
<ef-timegroup mode="contain" class="absolute w-full h-full">
|
|
117
|
+
<ef-video src="bars-n-tone.mp4" class="size-full object-fit absolute top-0 left-0"></ef-video>
|
|
118
|
+
</ef-timegroup>
|
|
119
|
+
|
|
103
120
|
</ef-timegroup>
|
|
104
|
-
|
|
105
|
-
</ef-timegroup>
|
|
121
|
+
</ef-preview>
|
|
106
122
|
</ef-configuration>
|
|
107
123
|
`,
|
|
108
124
|
container,
|
|
109
125
|
);
|
|
110
126
|
document.body.appendChild(container);
|
|
127
|
+
const configuration = container.querySelector("ef-configuration") as any;
|
|
128
|
+
configuration.signingURL = ""; // Disable URL signing for tests
|
|
111
129
|
const timegroup = container.querySelector("ef-timegroup") as EFTimegroup;
|
|
112
130
|
await timegroup.updateComplete;
|
|
113
131
|
await use(timegroup);
|
|
@@ -814,27 +832,24 @@ describe("EFVideo", () => {
|
|
|
814
832
|
);
|
|
815
833
|
});
|
|
816
834
|
|
|
817
|
-
test("seeks
|
|
835
|
+
test("seeks backward from 8000ms to 2000ms", async ({
|
|
818
836
|
barsNtone,
|
|
819
837
|
barsNtoneTimegroup,
|
|
838
|
+
expect,
|
|
820
839
|
}) => {
|
|
821
|
-
await waitForTaskIgnoringAborts(
|
|
822
|
-
barsNtone.unifiedVideoSeekTask.taskComplete,
|
|
823
|
-
);
|
|
824
|
-
await waitForTaskIgnoringAborts(barsNtone.audioSeekTask.taskComplete);
|
|
825
|
-
// First seek forward
|
|
826
840
|
barsNtoneTimegroup.currentTimeMs = 8000;
|
|
827
|
-
await
|
|
828
|
-
|
|
829
|
-
|
|
841
|
+
await barsNtoneTimegroup.seekTask.taskComplete;
|
|
842
|
+
expect(barsNtone.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
843
|
+
8.066,
|
|
830
844
|
);
|
|
831
845
|
|
|
846
|
+
expect(barsNtoneTimegroup.seekTask.status).toBe(TaskStatus.COMPLETE);
|
|
832
847
|
// Then seek backward
|
|
833
848
|
barsNtoneTimegroup.currentTimeMs = 2000;
|
|
834
|
-
|
|
835
|
-
await
|
|
836
|
-
|
|
837
|
-
|
|
849
|
+
expect(barsNtoneTimegroup.seekTask.status).toBe(TaskStatus.PENDING);
|
|
850
|
+
await barsNtoneTimegroup.seekTask.taskComplete;
|
|
851
|
+
expect(barsNtone.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
852
|
+
2.066,
|
|
838
853
|
);
|
|
839
854
|
});
|
|
840
855
|
|
|
@@ -842,9 +857,6 @@ describe("EFVideo", () => {
|
|
|
842
857
|
barsNtone,
|
|
843
858
|
barsNtoneTimegroup,
|
|
844
859
|
}) => {
|
|
845
|
-
await waitForTaskIgnoringAborts(
|
|
846
|
-
barsNtone.unifiedVideoSeekTask.taskComplete,
|
|
847
|
-
);
|
|
848
860
|
await waitForTaskIgnoringAborts(barsNtone.audioSeekTask.taskComplete);
|
|
849
861
|
|
|
850
862
|
// Use seek points that are within the actual media duration
|
|
@@ -1013,24 +1025,10 @@ describe("EFVideo", () => {
|
|
|
1013
1025
|
barsNtoneTimegroup,
|
|
1014
1026
|
expect,
|
|
1015
1027
|
}) => {
|
|
1016
|
-
await barsNtoneTimegroup.frameTask.taskComplete;
|
|
1028
|
+
// await barsNtoneTimegroup.frameTask.taskComplete;
|
|
1017
1029
|
barsNtoneTimegroup.currentTimeMs = 7975;
|
|
1018
|
-
await barsNtoneTimegroup.
|
|
1019
|
-
|
|
1020
|
-
"barsNtoneTimegroup.currentTime",
|
|
1021
|
-
barsNtoneTimegroup.currentTime,
|
|
1022
|
-
);
|
|
1023
|
-
console.log("barsNtone.ownCurrentTimeMs", barsNtone.ownCurrentTimeMs);
|
|
1024
|
-
console.log(
|
|
1025
|
-
"barsNtone.currentSourceTimeMs",
|
|
1026
|
-
barsNtone.currentSourceTimeMs,
|
|
1027
|
-
);
|
|
1028
|
-
console.log("barsNtone.desiredSeekTimeMs", barsNtone.desiredSeekTimeMs);
|
|
1029
|
-
console.log(
|
|
1030
|
-
"barsNtone.unifiedVideoSeekResult",
|
|
1031
|
-
barsNtone.unifiedVideoSeekTask.value,
|
|
1032
|
-
);
|
|
1033
|
-
await barsNtoneTimegroup.frameTask.taskComplete;
|
|
1030
|
+
await barsNtoneTimegroup.seekTask.taskComplete;
|
|
1031
|
+
|
|
1034
1032
|
expect(barsNtone.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1035
1033
|
8.033,
|
|
1036
1034
|
);
|
|
@@ -1087,47 +1085,24 @@ describe("EFVideo", () => {
|
|
|
1087
1085
|
});
|
|
1088
1086
|
|
|
1089
1087
|
test("seeks to 1000ms", async ({ timegroup, headMoov480p, expect }) => {
|
|
1090
|
-
await waitForTaskIgnoringAborts(
|
|
1091
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1092
|
-
);
|
|
1093
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1094
|
-
|
|
1095
1088
|
timegroup.currentTimeMs = 1000;
|
|
1096
1089
|
await timegroup.seekTask.taskComplete;
|
|
1097
|
-
|
|
1098
1090
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBe(1);
|
|
1099
1091
|
});
|
|
1100
1092
|
|
|
1101
1093
|
test("seeks to 3000ms", async ({ timegroup, headMoov480p, expect }) => {
|
|
1102
|
-
await waitForTaskIgnoringAborts(
|
|
1103
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1104
|
-
);
|
|
1105
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1106
|
-
|
|
1107
1094
|
timegroup.currentTimeMs = 3000;
|
|
1108
1095
|
await timegroup.seekTask.taskComplete;
|
|
1109
|
-
|
|
1110
1096
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBe(3);
|
|
1111
1097
|
});
|
|
1112
1098
|
|
|
1113
1099
|
test("seeks to 5000ms", async ({ timegroup, headMoov480p, expect }) => {
|
|
1114
|
-
await waitForTaskIgnoringAborts(
|
|
1115
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1116
|
-
);
|
|
1117
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1118
|
-
|
|
1119
1100
|
timegroup.currentTimeMs = 5000;
|
|
1120
1101
|
await timegroup.seekTask.taskComplete;
|
|
1121
|
-
|
|
1122
1102
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBe(5);
|
|
1123
1103
|
});
|
|
1124
1104
|
|
|
1125
1105
|
test("seeks to 7500ms", async ({ timegroup, headMoov480p, expect }) => {
|
|
1126
|
-
await waitForTaskIgnoringAborts(
|
|
1127
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1128
|
-
);
|
|
1129
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1130
|
-
|
|
1131
1106
|
timegroup.currentTimeMs = 7500;
|
|
1132
1107
|
await timegroup.seekTask.taskComplete;
|
|
1133
1108
|
|
|
@@ -1139,11 +1114,6 @@ describe("EFVideo", () => {
|
|
|
1139
1114
|
});
|
|
1140
1115
|
|
|
1141
1116
|
test("seeks to 8500ms", async ({ timegroup, headMoov480p, expect }) => {
|
|
1142
|
-
await waitForTaskIgnoringAborts(
|
|
1143
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1144
|
-
);
|
|
1145
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1146
|
-
|
|
1147
1117
|
timegroup.currentTimeMs = 8500;
|
|
1148
1118
|
await timegroup.seekTask.taskComplete;
|
|
1149
1119
|
|
|
@@ -1158,11 +1128,6 @@ describe("EFVideo", () => {
|
|
|
1158
1128
|
headMoov480p,
|
|
1159
1129
|
expect,
|
|
1160
1130
|
}) => {
|
|
1161
|
-
await waitForTaskIgnoringAborts(
|
|
1162
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1163
|
-
);
|
|
1164
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1165
|
-
|
|
1166
1131
|
timegroup.currentTimeMs = 9000;
|
|
1167
1132
|
await timegroup.seekTask.taskComplete;
|
|
1168
1133
|
|
|
@@ -1174,32 +1139,13 @@ describe("EFVideo", () => {
|
|
|
1174
1139
|
headMoov480p,
|
|
1175
1140
|
expect,
|
|
1176
1141
|
}) => {
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
);
|
|
1180
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1142
|
+
timegroup.currentTime = 7;
|
|
1143
|
+
await expect(timegroup.seekTask.taskComplete).resolves.toBe(7);
|
|
1144
|
+
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBe(7);
|
|
1181
1145
|
|
|
1182
|
-
|
|
1183
|
-
timegroup.
|
|
1184
|
-
|
|
1185
|
-
await waitForTaskIgnoringAborts(
|
|
1186
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1187
|
-
);
|
|
1188
|
-
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1189
|
-
7,
|
|
1190
|
-
1,
|
|
1191
|
-
);
|
|
1192
|
-
|
|
1193
|
-
// Then seek backward
|
|
1194
|
-
timegroup.currentTimeMs = 2000;
|
|
1195
|
-
await timegroup.seekTask.taskComplete;
|
|
1196
|
-
await waitForTaskIgnoringAborts(
|
|
1197
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1198
|
-
);
|
|
1199
|
-
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1200
|
-
2,
|
|
1201
|
-
1,
|
|
1202
|
-
);
|
|
1146
|
+
timegroup.currentTime = 2;
|
|
1147
|
+
await expect(timegroup.seekTask.taskComplete).resolves.toBe(2);
|
|
1148
|
+
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBe(2);
|
|
1203
1149
|
});
|
|
1204
1150
|
|
|
1205
1151
|
test("seeks to multiple points in sequence", async ({
|
|
@@ -1207,20 +1153,12 @@ describe("EFVideo", () => {
|
|
|
1207
1153
|
headMoov480p,
|
|
1208
1154
|
expect,
|
|
1209
1155
|
}) => {
|
|
1210
|
-
await waitForTaskIgnoringAborts(
|
|
1211
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1212
|
-
);
|
|
1213
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1214
|
-
|
|
1215
1156
|
const seekPoints = [1000, 3000, 5000, 2000, 6000, 0];
|
|
1216
1157
|
const expectedTimestamps = [1, 3, 5, 2, 6, 0];
|
|
1217
1158
|
|
|
1218
1159
|
for (let i = 0; i < seekPoints.length; i++) {
|
|
1219
1160
|
timegroup.currentTimeMs = seekPoints[i]!;
|
|
1220
1161
|
await timegroup.seekTask.taskComplete;
|
|
1221
|
-
await waitForTaskIgnoringAborts(
|
|
1222
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1223
|
-
);
|
|
1224
1162
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1225
1163
|
expectedTimestamps[i]!,
|
|
1226
1164
|
1,
|
|
@@ -1233,24 +1171,16 @@ describe("EFVideo", () => {
|
|
|
1233
1171
|
headMoov480p,
|
|
1234
1172
|
expect,
|
|
1235
1173
|
}) => {
|
|
1236
|
-
await waitForTaskIgnoringAborts(
|
|
1237
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1238
|
-
);
|
|
1239
|
-
await waitForTaskIgnoringAborts(headMoov480p.audioSeekTask.taskComplete);
|
|
1240
|
-
|
|
1241
1174
|
const fractionalTimes = [1234.567, 3456.789, 5678.901];
|
|
1242
1175
|
const expectedTimestamps = [1.234567, 3.456789, 5.678901];
|
|
1243
1176
|
|
|
1244
1177
|
for (let i = 0; i < fractionalTimes.length; i++) {
|
|
1245
1178
|
timegroup.currentTimeMs = fractionalTimes[i]!;
|
|
1246
1179
|
await timegroup.seekTask.taskComplete;
|
|
1247
|
-
await waitForTaskIgnoringAborts(
|
|
1248
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1249
|
-
);
|
|
1250
1180
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1251
1181
|
expectedTimestamps[i]!,
|
|
1252
1182
|
1,
|
|
1253
|
-
);
|
|
1183
|
+
);
|
|
1254
1184
|
}
|
|
1255
1185
|
});
|
|
1256
1186
|
|
|
@@ -1259,10 +1189,8 @@ describe("EFVideo", () => {
|
|
|
1259
1189
|
headMoov480p,
|
|
1260
1190
|
expect,
|
|
1261
1191
|
}) => {
|
|
1192
|
+
timegroup.currentTimeMs = 0;
|
|
1262
1193
|
await timegroup.seekTask.taskComplete;
|
|
1263
|
-
await waitForTaskIgnoringAborts(
|
|
1264
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1265
|
-
);
|
|
1266
1194
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1267
1195
|
0,
|
|
1268
1196
|
1,
|
|
@@ -1270,9 +1198,6 @@ describe("EFVideo", () => {
|
|
|
1270
1198
|
|
|
1271
1199
|
timegroup.currentTimeMs = 1000;
|
|
1272
1200
|
await timegroup.seekTask.taskComplete;
|
|
1273
|
-
await waitForTaskIgnoringAborts(
|
|
1274
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1275
|
-
);
|
|
1276
1201
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1277
1202
|
1,
|
|
1278
1203
|
1,
|
|
@@ -1280,9 +1205,6 @@ describe("EFVideo", () => {
|
|
|
1280
1205
|
|
|
1281
1206
|
timegroup.currentTimeMs = 4000;
|
|
1282
1207
|
await timegroup.seekTask.taskComplete;
|
|
1283
|
-
await waitForTaskIgnoringAborts(
|
|
1284
|
-
headMoov480p.unifiedVideoSeekTask.taskComplete,
|
|
1285
|
-
);
|
|
1286
1208
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBeCloseTo(
|
|
1287
1209
|
4,
|
|
1288
1210
|
1,
|
|
@@ -1294,7 +1216,6 @@ describe("EFVideo", () => {
|
|
|
1294
1216
|
headMoov480p,
|
|
1295
1217
|
expect,
|
|
1296
1218
|
}) => {
|
|
1297
|
-
await timegroup.waitForMediaDurations();
|
|
1298
1219
|
timegroup.currentTimeMs = 1000;
|
|
1299
1220
|
await timegroup.seekTask.taskComplete;
|
|
1300
1221
|
expect(headMoov480p.unifiedVideoSeekTask.value?.timestamp).toBe(1);
|
package/src/elements/EFVideo.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { customElement, property, state } from "lit/decorators.js";
|
|
|
5
5
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
6
6
|
|
|
7
7
|
import { DelayedLoadingState } from "../DelayedLoadingState.js";
|
|
8
|
-
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
9
8
|
import { TWMixin } from "../gui/TWMixin.js";
|
|
10
9
|
import { makeScrubVideoBufferTask } from "./EFMedia/videoTasks/makeScrubVideoBufferTask.ts";
|
|
11
10
|
import { makeScrubVideoInitSegmentFetchTask } from "./EFMedia/videoTasks/makeScrubVideoInitSegmentFetchTask.ts";
|
|
@@ -155,6 +154,15 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
155
154
|
);
|
|
156
155
|
}
|
|
157
156
|
|
|
157
|
+
protected updated(
|
|
158
|
+
changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>,
|
|
159
|
+
): void {
|
|
160
|
+
super.updated(changedProperties);
|
|
161
|
+
|
|
162
|
+
// No need to clear canvas - displayFrame() overwrites it completely
|
|
163
|
+
// and clearing creates blank frame gaps during transitions
|
|
164
|
+
}
|
|
165
|
+
|
|
158
166
|
render() {
|
|
159
167
|
return html`
|
|
160
168
|
<canvas ${ref(this.canvasRef)}></canvas>
|
|
@@ -189,27 +197,20 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
189
197
|
}
|
|
190
198
|
|
|
191
199
|
frameTask = new Task(this, {
|
|
192
|
-
autoRun:
|
|
200
|
+
autoRun: false,
|
|
193
201
|
args: () => [this.desiredSeekTimeMs] as const,
|
|
194
202
|
onError: (error) => {
|
|
195
203
|
console.error("frameTask error", error);
|
|
196
204
|
},
|
|
197
205
|
onComplete: () => {},
|
|
198
|
-
task: async ([_desiredSeekTimeMs]
|
|
206
|
+
task: async ([_desiredSeekTimeMs]) => {
|
|
207
|
+
this.unifiedVideoSeekTask.run();
|
|
199
208
|
await this.unifiedVideoSeekTask.taskComplete;
|
|
209
|
+
this.paintTask.run();
|
|
200
210
|
await this.paintTask.taskComplete;
|
|
201
|
-
if (signal.aborted) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
211
|
},
|
|
205
212
|
});
|
|
206
213
|
|
|
207
|
-
protected updated(
|
|
208
|
-
changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>,
|
|
209
|
-
): void {
|
|
210
|
-
super.updated(changedProperties);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
214
|
/**
|
|
214
215
|
* Start a delayed loading operation for testing
|
|
215
216
|
*/
|
|
@@ -244,6 +245,7 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
244
245
|
}
|
|
245
246
|
|
|
246
247
|
paintTask = new Task(this, {
|
|
248
|
+
autoRun: false,
|
|
247
249
|
args: () => [this.desiredSeekTimeMs] as const,
|
|
248
250
|
onError: (error) => {
|
|
249
251
|
console.error("paintTask error", error);
|
|
@@ -301,6 +303,18 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
301
303
|
},
|
|
302
304
|
});
|
|
303
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Clear the canvas when element becomes inactive
|
|
308
|
+
*/
|
|
309
|
+
clearCanvas(): void {
|
|
310
|
+
if (!this.canvasElement) return;
|
|
311
|
+
|
|
312
|
+
const ctx = this.canvasElement.getContext("2d");
|
|
313
|
+
if (ctx) {
|
|
314
|
+
ctx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
304
318
|
/**
|
|
305
319
|
* Display a video frame on the canvas
|
|
306
320
|
*/
|
|
@@ -342,7 +356,6 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
342
356
|
);
|
|
343
357
|
}
|
|
344
358
|
|
|
345
|
-
log("trace: drawing frame to canvas", frame.timestamp / 1000);
|
|
346
359
|
ctx.drawImage(
|
|
347
360
|
frame,
|
|
348
361
|
0,
|
|
@@ -3,7 +3,6 @@ import { Task } from "@lit/task";
|
|
|
3
3
|
import { css, html, LitElement, type PropertyValueMap } from "lit";
|
|
4
4
|
import { customElement, property, state } from "lit/decorators.js";
|
|
5
5
|
import { createRef, type Ref, ref } from "lit/directives/ref.js";
|
|
6
|
-
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
7
6
|
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
8
7
|
import { TWMixin } from "../gui/TWMixin.js";
|
|
9
8
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
@@ -38,7 +37,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
38
37
|
private mutationObserver?: MutationObserver;
|
|
39
38
|
|
|
40
39
|
render() {
|
|
41
|
-
return html`<canvas ${ref(this.canvasRef)}></canvas
|
|
40
|
+
return html`<canvas ${ref(this.canvasRef)}></canvas>`;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
@property({
|
|
@@ -465,7 +464,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
465
464
|
}
|
|
466
465
|
|
|
467
466
|
frameTask = new Task(this, {
|
|
468
|
-
autoRun:
|
|
467
|
+
autoRun: false,
|
|
469
468
|
args: () => {
|
|
470
469
|
return [
|
|
471
470
|
this.targetElement,
|