@editframe/elements 0.5.0-beta.8 → 0.6.0-beta.1

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.
Files changed (109) hide show
  1. package/dist/lib/av/EncodedAsset.cjs +561 -0
  2. package/dist/{editor/util/EncodedAsset/EncodedAsset.mjs → lib/av/EncodedAsset.js} +40 -33
  3. package/dist/lib/av/MP4File.cjs +182 -0
  4. package/dist/{editor/util/MP4File.mjs → lib/av/MP4File.js} +55 -51
  5. package/dist/lib/av/msToTimeCode.cjs +15 -0
  6. package/dist/lib/util/awaitMicrotask.cjs +8 -0
  7. package/dist/lib/util/memoize.cjs +14 -0
  8. package/dist/{util/memoize.mjs → lib/util/memoize.js} +1 -2
  9. package/dist/packages/elements/src/EF_FRAMEGEN.cjs +197 -0
  10. package/dist/packages/elements/src/EF_FRAMEGEN.d.ts +45 -0
  11. package/dist/packages/elements/src/EF_FRAMEGEN.js +197 -0
  12. package/dist/packages/elements/src/EF_INTERACTIVE.cjs +4 -0
  13. package/dist/packages/elements/src/EF_INTERACTIVE.d.ts +1 -0
  14. package/dist/packages/elements/src/elements/CrossUpdateController.cjs +16 -0
  15. package/dist/packages/elements/src/elements/CrossUpdateController.d.ts +9 -0
  16. package/dist/packages/elements/src/elements/EFAudio.cjs +53 -0
  17. package/dist/packages/elements/src/elements/EFAudio.d.ts +10 -0
  18. package/dist/{elements/src/elements/EFAudio.mjs → packages/elements/src/elements/EFAudio.js} +2 -5
  19. package/dist/packages/elements/src/elements/EFCaptions.cjs +171 -0
  20. package/dist/packages/elements/src/elements/EFCaptions.d.ts +39 -0
  21. package/dist/{elements/src/elements/EFCaptions.mjs → packages/elements/src/elements/EFCaptions.js} +18 -20
  22. package/dist/packages/elements/src/elements/EFImage.cjs +79 -0
  23. package/dist/packages/elements/src/elements/EFImage.d.ts +14 -0
  24. package/dist/{elements/src/elements/EFImage.mjs → packages/elements/src/elements/EFImage.js} +8 -7
  25. package/dist/packages/elements/src/elements/EFMedia.cjs +334 -0
  26. package/dist/packages/elements/src/elements/EFMedia.d.ts +61 -0
  27. package/dist/{elements/src/elements/EFMedia.mjs → packages/elements/src/elements/EFMedia.js} +40 -38
  28. package/dist/packages/elements/src/elements/EFSourceMixin.cjs +55 -0
  29. package/dist/packages/elements/src/elements/EFSourceMixin.d.ts +12 -0
  30. package/dist/{elements/src/elements/EFSourceMixin.mjs → packages/elements/src/elements/EFSourceMixin.js} +6 -8
  31. package/dist/packages/elements/src/elements/EFTemporal.cjs +198 -0
  32. package/dist/packages/elements/src/elements/EFTemporal.d.ts +36 -0
  33. package/dist/{elements/src/elements/EFTemporal.mjs → packages/elements/src/elements/EFTemporal.js} +6 -22
  34. package/dist/packages/elements/src/elements/EFTimegroup.browsertest.d.ts +12 -0
  35. package/{src/elements/EFTimegroup.ts → dist/packages/elements/src/elements/EFTimegroup.cjs} +162 -213
  36. package/dist/packages/elements/src/elements/EFTimegroup.d.ts +39 -0
  37. package/dist/{elements/src/elements/EFTimegroup.mjs → packages/elements/src/elements/EFTimegroup.js} +55 -65
  38. package/{src/elements/EFTimeline.ts → dist/packages/elements/src/elements/EFTimeline.cjs} +5 -3
  39. package/dist/packages/elements/src/elements/EFTimeline.d.ts +3 -0
  40. package/dist/{elements/src/elements/EFTimeline.mjs → packages/elements/src/elements/EFTimeline.js} +5 -2
  41. package/dist/packages/elements/src/elements/EFVideo.cjs +110 -0
  42. package/dist/packages/elements/src/elements/EFVideo.d.ts +14 -0
  43. package/dist/{elements/src/elements/EFVideo.mjs → packages/elements/src/elements/EFVideo.js} +10 -32
  44. package/dist/packages/elements/src/elements/EFWaveform.cjs +235 -0
  45. package/dist/packages/elements/src/elements/EFWaveform.d.ts +28 -0
  46. package/dist/{elements/src/elements/EFWaveform.mjs → packages/elements/src/elements/EFWaveform.js} +15 -16
  47. package/dist/packages/elements/src/elements/FetchMixin.cjs +28 -0
  48. package/dist/packages/elements/src/elements/FetchMixin.d.ts +8 -0
  49. package/dist/{elements/src/elements/FetchMixin.mjs → packages/elements/src/elements/FetchMixin.js} +5 -7
  50. package/dist/packages/elements/src/elements/TimegroupController.cjs +20 -0
  51. package/dist/packages/elements/src/elements/TimegroupController.d.ts +14 -0
  52. package/dist/packages/elements/src/elements/durationConverter.cjs +8 -0
  53. package/dist/packages/elements/src/elements/durationConverter.d.ts +4 -0
  54. package/dist/{elements/src/elements/durationConverter.mjs → packages/elements/src/elements/durationConverter.js} +1 -1
  55. package/dist/packages/elements/src/elements/parseTimeToMs.cjs +12 -0
  56. package/dist/packages/elements/src/elements/parseTimeToMs.d.ts +1 -0
  57. package/dist/packages/elements/src/elements/parseTimeToMs.js +12 -0
  58. package/dist/packages/elements/src/elements/util.cjs +11 -0
  59. package/dist/packages/elements/src/elements/util.d.ts +4 -0
  60. package/dist/{elements/src/elements/util.mjs → packages/elements/src/elements/util.js} +1 -1
  61. package/dist/packages/elements/src/gui/EFFilmstrip.cjs +675 -0
  62. package/dist/packages/elements/src/gui/EFFilmstrip.d.ts +138 -0
  63. package/dist/{elements/src/gui/EFFilmstrip.mjs → packages/elements/src/gui/EFFilmstrip.js} +57 -55
  64. package/dist/packages/elements/src/gui/EFWorkbench.cjs +199 -0
  65. package/dist/packages/elements/src/gui/EFWorkbench.d.ts +44 -0
  66. package/dist/{elements/src/gui/EFWorkbench.mjs → packages/elements/src/gui/EFWorkbench.js} +27 -49
  67. package/{src/gui/TWMixin.ts → dist/packages/elements/src/gui/TWMixin.cjs} +11 -10
  68. package/dist/packages/elements/src/gui/TWMixin.css.cjs +3 -0
  69. package/dist/packages/elements/src/gui/TWMixin.css.js +4 -0
  70. package/dist/packages/elements/src/gui/TWMixin.d.ts +3 -0
  71. package/dist/{elements/src/gui/TWMixin.mjs → packages/elements/src/gui/TWMixin.js} +4 -3
  72. package/dist/packages/elements/src/index.cjs +47 -0
  73. package/dist/packages/elements/src/index.d.ts +10 -0
  74. package/dist/packages/elements/src/index.js +23 -0
  75. package/dist/style.css +13 -4
  76. package/package.json +23 -4
  77. package/dist/elements/src/EF_FRAMEGEN.mjs +0 -130
  78. package/dist/elements/src/elements/parseTimeToMs.mjs +0 -13
  79. package/dist/elements/src/elements.mjs +0 -12
  80. package/dist/elements/src/gui/TWMixin.css.mjs +0 -4
  81. package/dist/util/awaitAnimationFrame.mjs +0 -11
  82. package/docker-compose.yaml +0 -17
  83. package/src/EF_FRAMEGEN.ts +0 -208
  84. package/src/EF_INTERACTIVE.ts +0 -2
  85. package/src/elements/CrossUpdateController.ts +0 -18
  86. package/src/elements/EFAudio.ts +0 -42
  87. package/src/elements/EFCaptions.ts +0 -202
  88. package/src/elements/EFImage.ts +0 -70
  89. package/src/elements/EFMedia.ts +0 -395
  90. package/src/elements/EFSourceMixin.ts +0 -57
  91. package/src/elements/EFTemporal.ts +0 -246
  92. package/src/elements/EFTimegroup.browsertest.ts +0 -360
  93. package/src/elements/EFVideo.ts +0 -114
  94. package/src/elements/EFWaveform.ts +0 -407
  95. package/src/elements/FetchMixin.ts +0 -18
  96. package/src/elements/TimegroupController.ts +0 -25
  97. package/src/elements/buildLitFixture.ts +0 -13
  98. package/src/elements/durationConverter.ts +0 -6
  99. package/src/elements/parseTimeToMs.ts +0 -10
  100. package/src/elements/util.ts +0 -24
  101. package/src/gui/EFFilmstrip.ts +0 -702
  102. package/src/gui/EFWorkbench.ts +0 -242
  103. package/src/gui/TWMixin.css +0 -3
  104. package/src/util.d.ts +0 -1
  105. /package/dist/{editor/msToTimeCode.mjs → lib/av/msToTimeCode.js} +0 -0
  106. /package/dist/{util/awaitMicrotask.mjs → lib/util/awaitMicrotask.js} +0 -0
  107. /package/dist/{elements/src/EF_INTERACTIVE.mjs → packages/elements/src/EF_INTERACTIVE.js} +0 -0
  108. /package/dist/{elements/src/elements/CrossUpdateController.mjs → packages/elements/src/elements/CrossUpdateController.js} +0 -0
  109. /package/dist/{elements/src/elements/TimegroupController.mjs → packages/elements/src/elements/TimegroupController.js} +0 -0
@@ -0,0 +1,334 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const lit = require("lit");
4
+ const EFTemporal = require("./EFTemporal.cjs");
5
+ const decorators_js = require("lit/decorators.js");
6
+ const deepEquals_js = require("@lit/task/deep-equals.js");
7
+ const task = require("@lit/task");
8
+ const MP4File = require("../../../../lib/av/MP4File.cjs");
9
+ const util = require("./util.cjs");
10
+ const EncodedAsset = require("../../../../lib/av/EncodedAsset.cjs");
11
+ const FetchMixin = require("./FetchMixin.cjs");
12
+ const EFWorkbench = require("../gui/EFWorkbench.cjs");
13
+ const context = require("@lit/context");
14
+ const EFSourceMixin = require("./EFSourceMixin.cjs");
15
+ const EF_INTERACTIVE = require("../EF_INTERACTIVE.cjs");
16
+ var __defProp = Object.defineProperty;
17
+ var __decorateClass = (decorators, target, key, kind) => {
18
+ var result = void 0;
19
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
20
+ if (decorator = decorators[i])
21
+ result = decorator(target, key, result) || result;
22
+ if (result) __defProp(target, key, result);
23
+ return result;
24
+ };
25
+ const deepGetMediaElements = (element, medias = []) => {
26
+ for (const child of Array.from(element.children)) {
27
+ if (child instanceof EFMedia) {
28
+ medias.push(child);
29
+ } else {
30
+ deepGetMediaElements(child, medias);
31
+ }
32
+ }
33
+ return medias;
34
+ };
35
+ class EFMedia extends EFSourceMixin.EFSourceMixin(EFTemporal.EFTemporal(FetchMixin.FetchMixin(lit.LitElement)), {
36
+ assetType: "isobmff_files"
37
+ }) {
38
+ constructor() {
39
+ super(...arguments);
40
+ this.currentTimeMs = 0;
41
+ this.trackFragmentIndexLoader = new task.Task(this, {
42
+ args: () => [this.fragmentIndexPath(), this.fetch],
43
+ task: async ([fragmentIndexPath, fetch], { signal }) => {
44
+ const response = await fetch(fragmentIndexPath, { signal });
45
+ return await response.json();
46
+ },
47
+ onComplete: () => {
48
+ this.requestUpdate("ownCurrentTimeMs");
49
+ this.parentTimegroup?.requestUpdate("ownCurrentTimeMs");
50
+ }
51
+ });
52
+ this.initSegmentsLoader = new task.Task(this, {
53
+ autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
54
+ args: () => [this.trackFragmentIndexLoader.value, this.src, this.fetch],
55
+ task: async ([fragmentIndex, _src, fetch], { signal }) => {
56
+ if (!fragmentIndex) {
57
+ return;
58
+ }
59
+ return await Promise.all(
60
+ Object.entries(fragmentIndex).map(async ([trackId, track]) => {
61
+ const start = track.initSegment.offset;
62
+ const end = track.initSegment.offset + track.initSegment.size - 1;
63
+ const response = await fetch(this.fragmentTrackPath(trackId), {
64
+ signal,
65
+ headers: { Range: `bytes=${start}-${end}` }
66
+ });
67
+ const buffer = await response.arrayBuffer();
68
+ buffer.fileStart = 0;
69
+ const mp4File = new MP4File.MP4File();
70
+ mp4File.appendBuffer(buffer, true);
71
+ mp4File.flush();
72
+ await mp4File.readyPromise;
73
+ return { trackId, buffer, mp4File };
74
+ })
75
+ );
76
+ }
77
+ });
78
+ this.seekTask = new task.Task(this, {
79
+ autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
80
+ args: () => [
81
+ this.desiredSeekTimeMs,
82
+ this.trackFragmentIndexLoader.value,
83
+ this.initSegmentsLoader.value
84
+ ],
85
+ task: async ([seekToMs, fragmentIndex, initSegments], { signal: _signal }) => {
86
+ if (fragmentIndex === void 0) {
87
+ return;
88
+ }
89
+ if (initSegments === void 0) {
90
+ return;
91
+ }
92
+ const result = {};
93
+ for (const index of Object.values(fragmentIndex)) {
94
+ const track = initSegments.find((segment2) => segment2.trackId === String(index.track))?.mp4File.getInfo().tracks[0];
95
+ if (!track) {
96
+ throw new Error("Could not finding matching track");
97
+ }
98
+ const segment = index.segments.toReversed().find((segment2) => {
99
+ return segment2.dts / track.timescale * 1e3 <= seekToMs;
100
+ });
101
+ if (!segment) {
102
+ return;
103
+ }
104
+ result[index.track] = { segment, track };
105
+ }
106
+ return result;
107
+ }
108
+ });
109
+ this.fetchSeekTask = new task.Task(this, {
110
+ autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
111
+ argsEqual: deepEquals_js.deepArrayEquals,
112
+ args: () => [this.initSegmentsLoader.value, this.seekTask.value, this.fetch],
113
+ task: async ([initSegments, seekResult, fetch], { signal }) => {
114
+ if (!initSegments) {
115
+ return;
116
+ }
117
+ if (!seekResult) {
118
+ return;
119
+ }
120
+ const files = {};
121
+ for (const [trackId, { segment, track }] of Object.entries(seekResult)) {
122
+ const start = segment.offset;
123
+ const end = segment.offset + segment.size;
124
+ const response = await fetch(this.fragmentTrackPath(trackId), {
125
+ signal,
126
+ headers: { Range: `bytes=${start}-${end}` }
127
+ });
128
+ const initSegment = Object.values(initSegments).find(
129
+ (initSegment2) => initSegment2.trackId === String(track.id)
130
+ );
131
+ if (!initSegment) {
132
+ throw new Error("Could not find matching init segment");
133
+ }
134
+ const initBuffer = initSegment.buffer;
135
+ const mediaBuffer = await response.arrayBuffer();
136
+ files[trackId] = new File([initBuffer, mediaBuffer], "video.mp4", {
137
+ type: "video/mp4"
138
+ });
139
+ }
140
+ return files;
141
+ }
142
+ });
143
+ this.videoAssetTask = new task.Task(this, {
144
+ autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
145
+ args: () => [this.fetchSeekTask.value],
146
+ task: async ([files], { signal: _signal }) => {
147
+ if (!files) {
148
+ return;
149
+ }
150
+ if (!this.defaultVideoTrackId) {
151
+ return;
152
+ }
153
+ const videoFile = files[this.defaultVideoTrackId];
154
+ if (!videoFile) {
155
+ return;
156
+ }
157
+ for (const frame of this.videoAssetTask.value?.decodedFrames || []) {
158
+ frame.close();
159
+ }
160
+ this.videoAssetTask.value?.videoDecoder?.close();
161
+ return await EncodedAsset.VideoAsset.createFromReadableStream(
162
+ "video.mp4",
163
+ videoFile.stream(),
164
+ videoFile
165
+ );
166
+ }
167
+ });
168
+ this.desiredSeekTimeMs = 0;
169
+ this.#audioContext = new OfflineAudioContext(2, 48e3 / 30, 48e3);
170
+ this.audioBufferTask = new task.Task(this, {
171
+ autoRun: EF_INTERACTIVE.EF_INTERACTIVE,
172
+ args: () => [this.fetchSeekTask.value, this.seekTask.value],
173
+ task: async ([files, segments], { signal: _signal }) => {
174
+ if (!files) {
175
+ return;
176
+ }
177
+ if (!segments) {
178
+ return;
179
+ }
180
+ if (!this.defaultAudioTrackId) {
181
+ return;
182
+ }
183
+ const segment = segments[this.defaultAudioTrackId];
184
+ if (!segment) {
185
+ return;
186
+ }
187
+ const audioFile = files[this.defaultAudioTrackId];
188
+ if (!audioFile) {
189
+ return;
190
+ }
191
+ return {
192
+ buffer: await this.#audioContext.decodeAudioData(
193
+ await audioFile.arrayBuffer()
194
+ ),
195
+ startOffsetMs: segment.segment.cts / segment.track.timescale * 1e3
196
+ };
197
+ }
198
+ });
199
+ }
200
+ static {
201
+ this.styles = [
202
+ lit.css`
203
+ :host {
204
+ display: block;
205
+ position: relative;
206
+ overflow: hidden;
207
+ }
208
+ `
209
+ ];
210
+ }
211
+ fragmentIndexPath() {
212
+ if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
213
+ return `${this.src}/index`;
214
+ }
215
+ return `/@ef-track-fragment-index/${this.getAttribute("src") ?? ""}`;
216
+ }
217
+ fragmentTrackPath(trackId) {
218
+ if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
219
+ return `${this.src.replace("files", "tracks")}/${trackId}`;
220
+ }
221
+ return `/@ef-track/${this.src ?? ""}?trackId=${trackId}`;
222
+ }
223
+ get defaultVideoTrackId() {
224
+ return Object.values(this.trackFragmentIndexLoader.value ?? {}).find(
225
+ (track) => track.type === "video"
226
+ )?.track;
227
+ }
228
+ get defaultAudioTrackId() {
229
+ return Object.values(this.trackFragmentIndexLoader.value ?? {}).find(
230
+ (track) => track.type === "audio"
231
+ )?.track;
232
+ }
233
+ async executeSeek(seekToMs) {
234
+ this.desiredSeekTimeMs = seekToMs;
235
+ }
236
+ updated(changedProperties) {
237
+ if (changedProperties.has("ownCurrentTimeMs")) {
238
+ this.executeSeek(this.ownCurrentTimeMs);
239
+ }
240
+ }
241
+ get hasOwnDuration() {
242
+ return true;
243
+ }
244
+ get durationMs() {
245
+ if (!this.trackFragmentIndexLoader.value) {
246
+ return 0;
247
+ }
248
+ const durations = Object.values(this.trackFragmentIndexLoader.value).map(
249
+ (track) => {
250
+ return track.duration / track.timescale * 1e3;
251
+ }
252
+ );
253
+ if (durations.length === 0) {
254
+ return 0;
255
+ }
256
+ return Math.max(...durations);
257
+ }
258
+ get startTimeMs() {
259
+ return util.getStartTimeMs(this);
260
+ }
261
+ #audioContext;
262
+ async fetchAudioSpanningTime(fromMs, toMs) {
263
+ fromMs -= this.startTimeMs;
264
+ toMs -= this.startTimeMs;
265
+ await this.trackFragmentIndexLoader.taskComplete;
266
+ const audioTrackId = this.defaultAudioTrackId;
267
+ if (!audioTrackId) {
268
+ console.warn("No audio track found");
269
+ return;
270
+ }
271
+ const audioTrackIndex = this.trackFragmentIndexLoader.value?.[audioTrackId];
272
+ if (!audioTrackIndex) {
273
+ console.warn("No audio track found");
274
+ return;
275
+ }
276
+ const start = audioTrackIndex.initSegment.offset;
277
+ const end = audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size - 1;
278
+ const audioInitFragmentRequest = this.fetch(
279
+ this.fragmentTrackPath(String(audioTrackId)),
280
+ {
281
+ headers: { Range: `bytes=${start}-${end}` }
282
+ }
283
+ );
284
+ const fragments = Object.values(audioTrackIndex.segments).filter(
285
+ (segment) => {
286
+ const segmentStartsBeforeEnd = segment.dts <= toMs * audioTrackIndex.timescale / 1e3;
287
+ const segmentEndsAfterStart = segment.dts + segment.duration >= fromMs * audioTrackIndex.timescale / 1e3;
288
+ return segmentStartsBeforeEnd && segmentEndsAfterStart;
289
+ }
290
+ );
291
+ const firstFragment = fragments[0];
292
+ if (!firstFragment) {
293
+ console.warn("No audio fragments found");
294
+ return;
295
+ }
296
+ const lastFragment = fragments[fragments.length - 1];
297
+ if (!lastFragment) {
298
+ console.warn("No audio fragments found");
299
+ return;
300
+ }
301
+ const fragmentStart = firstFragment.offset;
302
+ const fragmentEnd = lastFragment.offset + lastFragment.size - 1;
303
+ const audioFragmentRequest = this.fetch(
304
+ this.fragmentTrackPath(String(audioTrackId)),
305
+ {
306
+ headers: { Range: `bytes=${fragmentStart}-${fragmentEnd}` }
307
+ }
308
+ );
309
+ const initResponse = await audioInitFragmentRequest;
310
+ const dataResponse = await audioFragmentRequest;
311
+ const initBuffer = await initResponse.arrayBuffer();
312
+ const dataBuffer = await dataResponse.arrayBuffer();
313
+ const audioBlob = new Blob([initBuffer, dataBuffer], {
314
+ type: "audio/mp4"
315
+ });
316
+ return {
317
+ blob: audioBlob,
318
+ startMs: firstFragment.dts / audioTrackIndex.timescale * 1e3,
319
+ endMs: lastFragment.dts / audioTrackIndex.timescale * 1e3 + lastFragment.duration / audioTrackIndex.timescale * 1e3
320
+ };
321
+ }
322
+ }
323
+ __decorateClass([
324
+ decorators_js.property({ type: Number })
325
+ ], EFMedia.prototype, "currentTimeMs");
326
+ __decorateClass([
327
+ context.consume({ context: EFWorkbench.apiHostContext, subscribe: true }),
328
+ decorators_js.state()
329
+ ], EFMedia.prototype, "efHost");
330
+ __decorateClass([
331
+ decorators_js.state()
332
+ ], EFMedia.prototype, "desiredSeekTimeMs");
333
+ exports.EFMedia = EFMedia;
334
+ exports.deepGetMediaElements = deepGetMediaElements;
@@ -0,0 +1,61 @@
1
+ import { LitElement, PropertyValueMap } from 'lit';
2
+ import { Task } from '@lit/task';
3
+ import { MP4File } from '../../../../lib/av/MP4File';
4
+ import { TrackFragmentIndex, TrackSegment } from '../../../assets';
5
+ import { VideoAsset } from '../../../../lib/av/EncodedAsset';
6
+
7
+ import type * as MP4Box from "mp4box";
8
+ export declare const deepGetMediaElements: (element: Element, medias?: EFMedia[]) => EFMedia[];
9
+ declare const EFMedia_base: (new (...args: any[]) => import('./EFSourceMixin').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin').FetchMixinInterface) & typeof LitElement;
10
+ export declare class EFMedia extends EFMedia_base {
11
+ #private;
12
+ static styles: import('lit').CSSResult[];
13
+ currentTimeMs: number;
14
+ efHost?: string;
15
+ fragmentIndexPath(): string;
16
+ fragmentTrackPath(trackId: string): string;
17
+ trackFragmentIndexLoader: Task<readonly [string, typeof fetch], Record<number, TrackFragmentIndex>>;
18
+ protected initSegmentsLoader: Task<readonly [Record<number, TrackFragmentIndex> | undefined, string, typeof fetch], {
19
+ trackId: string;
20
+ buffer: MP4Box.MP4ArrayBuffer;
21
+ mp4File: MP4File;
22
+ }[] | undefined>;
23
+ get defaultVideoTrackId(): number | undefined;
24
+ get defaultAudioTrackId(): number | undefined;
25
+ seekTask: Task<readonly [number, Record<number, TrackFragmentIndex> | undefined, {
26
+ trackId: string;
27
+ buffer: MP4Box.MP4ArrayBuffer;
28
+ mp4File: MP4File;
29
+ }[] | undefined], Record<string, {
30
+ segment: TrackSegment;
31
+ track: MP4Box.TrackInfo;
32
+ }> | undefined>;
33
+ fetchSeekTask: Task<readonly [{
34
+ trackId: string;
35
+ buffer: MP4Box.MP4ArrayBuffer;
36
+ mp4File: MP4File;
37
+ }[] | undefined, Record<string, {
38
+ segment: TrackSegment;
39
+ track: MP4Box.TrackInfo;
40
+ }> | undefined, typeof fetch], Record<string, File> | undefined>;
41
+ videoAssetTask: Task<readonly [Record<string, File> | undefined], VideoAsset | undefined>;
42
+ desiredSeekTimeMs: number;
43
+ protected executeSeek(seekToMs: number): Promise<void>;
44
+ protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
45
+ get hasOwnDuration(): boolean;
46
+ get durationMs(): number;
47
+ get startTimeMs(): number;
48
+ audioBufferTask: Task<readonly [Record<string, File> | undefined, Record<string, {
49
+ segment: TrackSegment;
50
+ track: MP4Box.TrackInfo;
51
+ }> | undefined], {
52
+ buffer: AudioBuffer;
53
+ startOffsetMs: number;
54
+ } | undefined>;
55
+ fetchAudioSpanningTime(fromMs: number, toMs: number): Promise<{
56
+ blob: Blob;
57
+ startMs: number;
58
+ endMs: number;
59
+ } | undefined>;
60
+ }
61
+ export {};
@@ -1,29 +1,27 @@
1
1
  import { css, LitElement } from "lit";
2
- import { EFTemporal } from "./EFTemporal.mjs";
2
+ import { EFTemporal } from "./EFTemporal.js";
3
3
  import { property, state } from "lit/decorators.js";
4
4
  import { deepArrayEquals } from "@lit/task/deep-equals.js";
5
5
  import { Task } from "@lit/task";
6
- import { MP4File } from "../../../editor/util/MP4File.mjs";
7
- import { getStartTimeMs } from "./util.mjs";
8
- import { VideoAsset } from "../../../editor/util/EncodedAsset/EncodedAsset.mjs";
9
- import { FetchMixin } from "./FetchMixin.mjs";
10
- import { apiHostContext } from "../gui/EFWorkbench.mjs";
6
+ import { MP4File } from "../../../../lib/av/MP4File.js";
7
+ import { getStartTimeMs } from "./util.js";
8
+ import { VideoAsset } from "../../../../lib/av/EncodedAsset.js";
9
+ import { FetchMixin } from "./FetchMixin.js";
10
+ import { apiHostContext } from "../gui/EFWorkbench.js";
11
11
  import { consume } from "@lit/context";
12
- import { EFSourceMixin } from "./EFSourceMixin.mjs";
13
- import { EF_INTERACTIVE } from "../EF_INTERACTIVE.mjs";
12
+ import { EFSourceMixin } from "./EFSourceMixin.js";
13
+ import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
14
14
  var __defProp = Object.defineProperty;
15
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
16
15
  var __decorateClass = (decorators, target, key, kind) => {
17
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
16
+ var result = void 0;
18
17
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
19
18
  if (decorator = decorators[i])
20
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
21
- if (kind && result)
22
- __defProp(target, key, result);
19
+ result = decorator(target, key, result) || result;
20
+ if (result) __defProp(target, key, result);
23
21
  return result;
24
22
  };
25
23
  const deepGetMediaElements = (element, medias = []) => {
26
- for (const child of element.children) {
24
+ for (const child of Array.from(element.children)) {
27
25
  if (child instanceof EFMedia) {
28
26
  medias.push(child);
29
27
  } else {
@@ -41,7 +39,6 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
41
39
  this.trackFragmentIndexLoader = new Task(this, {
42
40
  args: () => [this.fragmentIndexPath(), this.fetch],
43
41
  task: async ([fragmentIndexPath, fetch], { signal }) => {
44
- console.log("EFMedia trackFragmentIndexLoader");
45
42
  const response = await fetch(fragmentIndexPath, { signal });
46
43
  return await response.json();
47
44
  },
@@ -54,7 +51,6 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
54
51
  autoRun: EF_INTERACTIVE,
55
52
  args: () => [this.trackFragmentIndexLoader.value, this.src, this.fetch],
56
53
  task: async ([fragmentIndex, _src, fetch], { signal }) => {
57
- console.log("EFMedia initSegmentsLoader");
58
54
  if (!fragmentIndex) {
59
55
  return;
60
56
  }
@@ -84,8 +80,7 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
84
80
  this.trackFragmentIndexLoader.value,
85
81
  this.initSegmentsLoader.value
86
82
  ],
87
- task: async ([seekToMs, fragmentIndex, initSegments], { signal }) => {
88
- console.log("EFMedia seekTask");
83
+ task: async ([seekToMs, fragmentIndex, initSegments], { signal: _signal }) => {
89
84
  if (fragmentIndex === void 0) {
90
85
  return;
91
86
  }
@@ -93,7 +88,7 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
93
88
  return;
94
89
  }
95
90
  const result = {};
96
- Object.values(fragmentIndex).forEach((index) => {
91
+ for (const index of Object.values(fragmentIndex)) {
97
92
  const track = initSegments.find((segment2) => segment2.trackId === String(index.track))?.mp4File.getInfo().tracks[0];
98
93
  if (!track) {
99
94
  throw new Error("Could not finding matching track");
@@ -105,7 +100,7 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
105
100
  return;
106
101
  }
107
102
  result[index.track] = { segment, track };
108
- });
103
+ }
109
104
  return result;
110
105
  }
111
106
  });
@@ -114,7 +109,6 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
114
109
  argsEqual: deepArrayEquals,
115
110
  args: () => [this.initSegmentsLoader.value, this.seekTask.value, this.fetch],
116
111
  task: async ([initSegments, seekResult, fetch], { signal }) => {
117
- console.log("EFMedia fetchSeekTask");
118
112
  if (!initSegments) {
119
113
  return;
120
114
  }
@@ -132,6 +126,9 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
132
126
  const initSegment = Object.values(initSegments).find(
133
127
  (initSegment2) => initSegment2.trackId === String(track.id)
134
128
  );
129
+ if (!initSegment) {
130
+ throw new Error("Could not find matching init segment");
131
+ }
135
132
  const initBuffer = initSegment.buffer;
136
133
  const mediaBuffer = await response.arrayBuffer();
137
134
  files[trackId] = new File([initBuffer, mediaBuffer], "video.mp4", {
@@ -144,8 +141,7 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
144
141
  this.videoAssetTask = new Task(this, {
145
142
  autoRun: EF_INTERACTIVE,
146
143
  args: () => [this.fetchSeekTask.value],
147
- task: async ([files], { signal }) => {
148
- console.log("EFMedia videoAssetTask");
144
+ task: async ([files], { signal: _signal }) => {
149
145
  if (!files) {
150
146
  return;
151
147
  }
@@ -156,6 +152,10 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
156
152
  if (!videoFile) {
157
153
  return;
158
154
  }
155
+ for (const frame of this.videoAssetTask.value?.decodedFrames || []) {
156
+ frame.close();
157
+ }
158
+ this.videoAssetTask.value?.videoDecoder?.close();
159
159
  return await VideoAsset.createFromReadableStream(
160
160
  "video.mp4",
161
161
  videoFile.stream(),
@@ -168,8 +168,7 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
168
168
  this.audioBufferTask = new Task(this, {
169
169
  autoRun: EF_INTERACTIVE,
170
170
  args: () => [this.fetchSeekTask.value, this.seekTask.value],
171
- task: async ([files, segments], { signal }) => {
172
- console.log("EFMedia audioBufferTask", this.outerHTML);
171
+ task: async ([files, segments], { signal: _signal }) => {
173
172
  if (!files) {
174
173
  return;
175
174
  }
@@ -207,20 +206,17 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
207
206
  `
208
207
  ];
209
208
  }
210
- // get requiredAssets() {
211
- // return { [this.md5SumLoader.value]: this.requiredAssetsPath.value ?? [] };
212
- // }
213
209
  fragmentIndexPath() {
214
- if (this.getAttribute("src")?.startsWith("http")) {
215
- return this.getAttribute("src") + "/index";
210
+ if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
211
+ return `${this.src}/index`;
216
212
  }
217
213
  return `/@ef-track-fragment-index/${this.getAttribute("src") ?? ""}`;
218
214
  }
219
215
  fragmentTrackPath(trackId) {
220
- if (this.getAttribute("src")?.startsWith("http")) {
221
- return this.getAttribute("src").replace("files", "tracks") + `/${trackId}`;
216
+ if (this.src.startsWith("editframe://") || this.src.startsWith("http")) {
217
+ return `${this.src.replace("files", "tracks")}/${trackId}`;
222
218
  }
223
- return `/@ef-track/${this.getAttribute("src") ?? ""}?trackId=${trackId}`;
219
+ return `/@ef-track/${this.src ?? ""}?trackId=${trackId}`;
224
220
  }
225
221
  get defaultVideoTrackId() {
226
222
  return Object.values(this.trackFragmentIndexLoader.value ?? {}).find(
@@ -290,12 +286,18 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
290
286
  return segmentStartsBeforeEnd && segmentEndsAfterStart;
291
287
  }
292
288
  );
293
- console.log("FRAGMENTS SPANNING TIME", JSON.stringify(fragments));
294
289
  const firstFragment = fragments[0];
290
+ if (!firstFragment) {
291
+ console.warn("No audio fragments found");
292
+ return;
293
+ }
295
294
  const lastFragment = fragments[fragments.length - 1];
295
+ if (!lastFragment) {
296
+ console.warn("No audio fragments found");
297
+ return;
298
+ }
296
299
  const fragmentStart = firstFragment.offset;
297
300
  const fragmentEnd = lastFragment.offset + lastFragment.size - 1;
298
- console.log("FETCHING BYTES", `bytes=${fragmentStart}-${fragmentEnd}`);
299
301
  const audioFragmentRequest = this.fetch(
300
302
  this.fragmentTrackPath(String(audioTrackId)),
301
303
  {
@@ -318,14 +320,14 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
318
320
  }
319
321
  __decorateClass([
320
322
  property({ type: Number })
321
- ], EFMedia.prototype, "currentTimeMs", 2);
323
+ ], EFMedia.prototype, "currentTimeMs");
322
324
  __decorateClass([
323
325
  consume({ context: apiHostContext, subscribe: true }),
324
326
  state()
325
- ], EFMedia.prototype, "efHost", 2);
327
+ ], EFMedia.prototype, "efHost");
326
328
  __decorateClass([
327
329
  state()
328
- ], EFMedia.prototype, "desiredSeekTimeMs", 2);
330
+ ], EFMedia.prototype, "desiredSeekTimeMs");
329
331
  export {
330
332
  EFMedia,
331
333
  deepGetMediaElements
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const context = require("@lit/context");
4
+ const EFWorkbench = require("../gui/EFWorkbench.cjs");
5
+ const state_js = require("lit/decorators/state.js");
6
+ const task = require("@lit/task");
7
+ const property_js = require("lit/decorators/property.js");
8
+ var __defProp = Object.defineProperty;
9
+ var __decorateClass = (decorators, target, key, kind) => {
10
+ var result = void 0;
11
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
12
+ if (decorator = decorators[i])
13
+ result = decorator(target, key, result) || result;
14
+ if (result) __defProp(target, key, result);
15
+ return result;
16
+ };
17
+ function EFSourceMixin(superClass, options) {
18
+ class EFSourceElement extends superClass {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.src = "";
22
+ this.md5SumLoader = new task.Task(this, {
23
+ autoRun: false,
24
+ args: () => [this.src],
25
+ task: async ([src], { signal }) => {
26
+ const md5Path = `/@ef-asset/${src}`;
27
+ const response = await fetch(md5Path, { method: "HEAD", signal });
28
+ return response.headers.get("etag") ?? void 0;
29
+ }
30
+ });
31
+ }
32
+ productionSrc() {
33
+ if (!this.md5SumLoader.value) {
34
+ throw new Error(
35
+ `MD5 sum not available for ${this}. Cannot generate production URL`
36
+ );
37
+ }
38
+ if (!this.efHost) {
39
+ throw new Error(
40
+ `efHost not available for ${this}. Cannot generate production URL`
41
+ );
42
+ }
43
+ return `${this.efHost}/api/video2/${options.assetType}/${this.md5SumLoader.value}`;
44
+ }
45
+ }
46
+ __decorateClass([
47
+ context.consume({ context: EFWorkbench.apiHostContext, subscribe: true }),
48
+ state_js.state()
49
+ ], EFSourceElement.prototype, "efHost");
50
+ __decorateClass([
51
+ property_js.property({ type: String })
52
+ ], EFSourceElement.prototype, "src");
53
+ return EFSourceElement;
54
+ }
55
+ exports.EFSourceMixin = EFSourceMixin;
@@ -0,0 +1,12 @@
1
+ import { LitElement } from 'lit';
2
+
3
+ export declare class EFSourceMixinInterface {
4
+ productionSrc(): string;
5
+ src: string;
6
+ }
7
+ interface EFSourceMixinOptions {
8
+ assetType: string;
9
+ }
10
+ type Constructor<T = {}> = new (...args: any[]) => T;
11
+ export declare function EFSourceMixin<T extends Constructor<LitElement>>(superClass: T, options: EFSourceMixinOptions): Constructor<EFSourceMixinInterface> & T;
12
+ export {};