@editframe/elements 0.5.0-beta.9 → 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 (82) hide show
  1. package/dist/lib/av/EncodedAsset.cjs +561 -0
  2. package/dist/lib/av/{EncodedAsset.mjs → EncodedAsset.js} +18 -13
  3. package/dist/lib/av/MP4File.cjs +182 -0
  4. package/dist/lib/av/{MP4File.mjs → MP4File.js} +14 -9
  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/packages/elements/src/EF_FRAMEGEN.cjs +197 -0
  9. package/dist/packages/elements/src/EF_FRAMEGEN.d.ts +45 -0
  10. package/dist/packages/elements/src/{EF_FRAMEGEN.mjs → EF_FRAMEGEN.js} +21 -7
  11. package/dist/packages/elements/src/EF_INTERACTIVE.cjs +4 -0
  12. package/dist/packages/elements/src/EF_INTERACTIVE.d.ts +1 -0
  13. package/dist/packages/elements/src/elements/CrossUpdateController.cjs +16 -0
  14. package/dist/packages/elements/src/elements/CrossUpdateController.d.ts +9 -0
  15. package/dist/packages/elements/src/elements/EFAudio.cjs +53 -0
  16. package/dist/packages/elements/src/elements/EFAudio.d.ts +10 -0
  17. package/dist/packages/elements/src/elements/{EFAudio.mjs → EFAudio.js} +1 -1
  18. package/dist/packages/elements/src/elements/EFCaptions.cjs +171 -0
  19. package/dist/packages/elements/src/elements/EFCaptions.d.ts +39 -0
  20. package/dist/packages/elements/src/elements/{EFCaptions.mjs → EFCaptions.js} +13 -13
  21. package/dist/packages/elements/src/elements/EFImage.cjs +79 -0
  22. package/dist/packages/elements/src/elements/EFImage.d.ts +14 -0
  23. package/dist/packages/elements/src/elements/{EFImage.mjs → EFImage.js} +6 -4
  24. package/dist/packages/elements/src/elements/EFMedia.cjs +334 -0
  25. package/dist/packages/elements/src/elements/EFMedia.d.ts +61 -0
  26. package/dist/packages/elements/src/elements/{EFMedia.mjs → EFMedia.js} +29 -18
  27. package/dist/packages/elements/src/elements/EFSourceMixin.cjs +55 -0
  28. package/dist/packages/elements/src/elements/EFSourceMixin.d.ts +12 -0
  29. package/dist/packages/elements/src/elements/{EFSourceMixin.mjs → EFSourceMixin.js} +1 -1
  30. package/dist/packages/elements/src/elements/EFTemporal.cjs +198 -0
  31. package/dist/packages/elements/src/elements/EFTemporal.d.ts +36 -0
  32. package/dist/packages/elements/src/elements/{EFTemporal.mjs → EFTemporal.js} +4 -7
  33. package/dist/packages/elements/src/elements/EFTimegroup.browsertest.d.ts +12 -0
  34. package/dist/packages/elements/src/elements/EFTimegroup.cjs +343 -0
  35. package/dist/packages/elements/src/elements/EFTimegroup.d.ts +39 -0
  36. package/dist/packages/elements/src/elements/{EFTimegroup.mjs → EFTimegroup.js} +23 -22
  37. package/dist/packages/elements/src/elements/EFTimeline.cjs +15 -0
  38. package/dist/packages/elements/src/elements/EFTimeline.d.ts +3 -0
  39. package/dist/packages/elements/src/elements/{EFTimeline.mjs → EFTimeline.js} +5 -2
  40. package/dist/packages/elements/src/elements/EFVideo.cjs +110 -0
  41. package/dist/packages/elements/src/elements/EFVideo.d.ts +14 -0
  42. package/dist/packages/elements/src/elements/{EFVideo.mjs → EFVideo.js} +2 -2
  43. package/dist/packages/elements/src/elements/EFWaveform.cjs +235 -0
  44. package/dist/packages/elements/src/elements/EFWaveform.d.ts +28 -0
  45. package/dist/packages/elements/src/elements/{EFWaveform.mjs → EFWaveform.js} +14 -14
  46. package/dist/packages/elements/src/elements/FetchMixin.cjs +28 -0
  47. package/dist/packages/elements/src/elements/FetchMixin.d.ts +8 -0
  48. package/dist/packages/elements/src/elements/{FetchMixin.mjs → FetchMixin.js} +1 -1
  49. package/dist/packages/elements/src/elements/TimegroupController.cjs +20 -0
  50. package/dist/packages/elements/src/elements/TimegroupController.d.ts +14 -0
  51. package/dist/packages/elements/src/elements/durationConverter.cjs +8 -0
  52. package/dist/packages/elements/src/elements/durationConverter.d.ts +4 -0
  53. package/dist/packages/elements/src/elements/{durationConverter.mjs → durationConverter.js} +1 -1
  54. package/dist/packages/elements/src/elements/parseTimeToMs.cjs +12 -0
  55. package/dist/packages/elements/src/elements/parseTimeToMs.d.ts +1 -0
  56. package/dist/packages/elements/src/elements/parseTimeToMs.js +12 -0
  57. package/dist/packages/elements/src/elements/util.cjs +11 -0
  58. package/dist/packages/elements/src/elements/util.d.ts +4 -0
  59. package/dist/packages/elements/src/elements/{util.mjs → util.js} +1 -1
  60. package/dist/packages/elements/src/gui/EFFilmstrip.cjs +675 -0
  61. package/dist/packages/elements/src/gui/EFFilmstrip.d.ts +138 -0
  62. package/dist/packages/elements/src/gui/{EFFilmstrip.mjs → EFFilmstrip.js} +48 -34
  63. package/dist/packages/elements/src/gui/EFWorkbench.cjs +199 -0
  64. package/dist/packages/elements/src/gui/EFWorkbench.d.ts +44 -0
  65. package/dist/packages/elements/src/gui/{EFWorkbench.mjs → EFWorkbench.js} +26 -27
  66. package/dist/packages/elements/src/gui/TWMixin.cjs +28 -0
  67. package/dist/packages/elements/src/gui/TWMixin.css.cjs +3 -0
  68. package/dist/packages/elements/src/gui/TWMixin.d.ts +3 -0
  69. package/dist/packages/elements/src/gui/{TWMixin.mjs → TWMixin.js} +4 -3
  70. package/dist/packages/elements/src/index.cjs +47 -0
  71. package/dist/packages/elements/src/index.d.ts +10 -0
  72. package/dist/packages/elements/src/index.js +23 -0
  73. package/package.json +18 -4
  74. package/dist/packages/elements/src/elements/parseTimeToMs.mjs +0 -13
  75. package/dist/packages/elements/src/elements.mjs +0 -12
  76. /package/dist/lib/av/{msToTimeCode.mjs → msToTimeCode.js} +0 -0
  77. /package/dist/lib/util/{awaitMicrotask.mjs → awaitMicrotask.js} +0 -0
  78. /package/dist/lib/util/{memoize.mjs → memoize.js} +0 -0
  79. /package/dist/packages/elements/src/{EF_INTERACTIVE.mjs → EF_INTERACTIVE.js} +0 -0
  80. /package/dist/packages/elements/src/elements/{CrossUpdateController.mjs → CrossUpdateController.js} +0 -0
  81. /package/dist/packages/elements/src/elements/{TimegroupController.mjs → TimegroupController.js} +0 -0
  82. /package/dist/packages/elements/src/gui/{TWMixin.css.mjs → TWMixin.css.js} +0 -0
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const MP4Box = require("mp4box");
4
+ function _interopNamespaceDefault(e) {
5
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
6
+ if (e) {
7
+ for (const k in e) {
8
+ if (k !== "default") {
9
+ const d = Object.getOwnPropertyDescriptor(e, k);
10
+ Object.defineProperty(n, k, d.get ? d : {
11
+ enumerable: true,
12
+ get: () => e[k]
13
+ });
14
+ }
15
+ }
16
+ }
17
+ n.default = e;
18
+ return Object.freeze(n);
19
+ }
20
+ const MP4Box__namespace = /* @__PURE__ */ _interopNamespaceDefault(MP4Box);
21
+ class MP4File extends MP4Box__namespace.ISOFile {
22
+ constructor() {
23
+ super(...arguments);
24
+ this.readyPromise = new Promise((resolve, reject) => {
25
+ this.onReady = () => resolve();
26
+ this.onError = reject;
27
+ });
28
+ this.waitingForSamples = [];
29
+ this._hasSeenLastSamples = false;
30
+ this._arrayBufferFileStart = 0;
31
+ }
32
+ setSegmentOptions(id, user, options) {
33
+ const trak = this.getTrackById(id);
34
+ if (trak) {
35
+ trak.nextSample = 0;
36
+ this.fragmentedTracks.push({
37
+ id,
38
+ user,
39
+ trak,
40
+ segmentStream: null,
41
+ nb_samples: "nbSamples" in options && options.nbSamples || 1e3,
42
+ rapAlignement: ("rapAlignement" in options && options.rapAlignement) ?? true
43
+ });
44
+ }
45
+ }
46
+ /**
47
+ * Fragments all tracks in a file into separate array buffers.
48
+ */
49
+ async fragmentAllTracks() {
50
+ const trackBuffers = {};
51
+ for await (const segment of this.fragmentIterator()) {
52
+ (trackBuffers[segment.track] ??= []).push(segment.data);
53
+ }
54
+ return trackBuffers;
55
+ }
56
+ async *fragmentIterator() {
57
+ await this.readyPromise;
58
+ const trackInfo = {};
59
+ for (const videoTrack of this.getInfo().videoTracks) {
60
+ trackInfo[videoTrack.id] = { index: 0, complete: false };
61
+ this.setSegmentOptions(videoTrack.id, null, {
62
+ rapAlignement: true
63
+ });
64
+ }
65
+ for (const audioTrack of this.getInfo().audioTracks) {
66
+ trackInfo[audioTrack.id] = { index: 0, complete: false };
67
+ const sampleRate = audioTrack.audio.sample_rate;
68
+ const probablePacketSize = 1024;
69
+ const probableFourSecondsOfSamples = Math.ceil(
70
+ sampleRate / probablePacketSize * 4
71
+ );
72
+ this.setSegmentOptions(audioTrack.id, null, {
73
+ nbSamples: probableFourSecondsOfSamples
74
+ });
75
+ }
76
+ const initSegments = this.initializeSegmentation();
77
+ for (const initSegment of initSegments) {
78
+ yield {
79
+ track: initSegment.id,
80
+ segment: "init",
81
+ data: initSegment.buffer,
82
+ complete: false
83
+ };
84
+ }
85
+ const fragmentStartSamples = {};
86
+ let finishedReading = false;
87
+ const allTracksFinished = () => {
88
+ for (const fragmentedTrack of this.fragmentedTracks) {
89
+ if (!trackInfo[fragmentedTrack.id]?.complete) {
90
+ return false;
91
+ }
92
+ }
93
+ return true;
94
+ };
95
+ while (!(finishedReading && allTracksFinished())) {
96
+ for (const fragTrak of this.fragmentedTracks) {
97
+ const trak = fragTrak.trak;
98
+ if (trak.nextSample === void 0) {
99
+ throw new Error("trak.nextSample is undefined");
100
+ }
101
+ if (trak.samples === void 0) {
102
+ throw new Error("trak.samples is undefined");
103
+ }
104
+ while (trak.nextSample < trak.samples.length) {
105
+ let result = void 0;
106
+ const fragTrakNextSample = trak.samples[trak.nextSample];
107
+ if (fragTrakNextSample) {
108
+ fragmentStartSamples[fragTrak.id] ||= fragTrakNextSample;
109
+ }
110
+ try {
111
+ result = this.createFragment(
112
+ fragTrak.id,
113
+ trak.nextSample,
114
+ fragTrak.segmentStream
115
+ );
116
+ } catch (error) {
117
+ console.log("Failed to createFragment", error);
118
+ }
119
+ if (result) {
120
+ fragTrak.segmentStream = result;
121
+ trak.nextSample++;
122
+ } else {
123
+ finishedReading = await this.waitForMoreSamples();
124
+ break;
125
+ }
126
+ const nextSample = trak.samples[trak.nextSample];
127
+ const emitSegment = (
128
+ // if rapAlignement is true, we emit a fragment when we have a rap sample coming up next
129
+ fragTrak.rapAlignement === true && nextSample?.is_sync || // if rapAlignement is false, we emit a fragment when we have the required number of samples
130
+ !fragTrak.rapAlignement && trak.nextSample % fragTrak.nb_samples === 0 || // // if this is the last sample, we emit the fragment
131
+ // finished ||
132
+ // if we have more samples than the number of samples requested, we emit the fragment
133
+ trak.nextSample >= trak.samples.length
134
+ );
135
+ if (emitSegment) {
136
+ const trackInfoForFrag = trackInfo[fragTrak.id];
137
+ if (!trackInfoForFrag) {
138
+ throw new Error("trackInfoForFrag is undefined");
139
+ }
140
+ if (trak.nextSample >= trak.samples.length) {
141
+ trackInfoForFrag.complete = true;
142
+ }
143
+ const startSample = fragmentStartSamples[fragTrak.id];
144
+ const endSample = trak.samples[trak.nextSample - 1];
145
+ if (!startSample || !endSample) {
146
+ throw new Error("startSample or endSample is undefined");
147
+ }
148
+ yield {
149
+ track: fragTrak.id,
150
+ segment: trackInfoForFrag.index,
151
+ data: fragTrak.segmentStream.buffer,
152
+ complete: trackInfoForFrag.complete,
153
+ cts: startSample.cts,
154
+ dts: startSample.dts,
155
+ duration: endSample.dts - startSample.dts + endSample.duration
156
+ };
157
+ trackInfoForFrag.index += 1;
158
+ fragTrak.segmentStream = null;
159
+ delete fragmentStartSamples[fragTrak.id];
160
+ }
161
+ }
162
+ }
163
+ finishedReading = await this.waitForMoreSamples();
164
+ }
165
+ }
166
+ waitForMoreSamples() {
167
+ if (this._hasSeenLastSamples) {
168
+ return Promise.resolve(true);
169
+ }
170
+ return new Promise((resolve) => {
171
+ this.waitingForSamples.push(resolve);
172
+ });
173
+ }
174
+ processSamples(last) {
175
+ this._hasSeenLastSamples = last;
176
+ for (const observer of this.waitingForSamples) {
177
+ observer(last);
178
+ }
179
+ this.waitingForSamples = [];
180
+ }
181
+ }
182
+ exports.MP4File = MP4File;
@@ -28,7 +28,7 @@ class MP4File extends MP4Box.ISOFile {
28
28
  * Fragments all tracks in a file into separate array buffers.
29
29
  */
30
30
  async fragmentAllTracks() {
31
- let trackBuffers = {};
31
+ const trackBuffers = {};
32
32
  for await (const segment of this.fragmentIterator()) {
33
33
  (trackBuffers[segment.track] ??= []).push(segment.data);
34
34
  }
@@ -82,10 +82,11 @@ class MP4File extends MP4Box.ISOFile {
82
82
  if (trak.samples === void 0) {
83
83
  throw new Error("trak.samples is undefined");
84
84
  }
85
- eachSample: while (trak.nextSample < trak.samples.length) {
85
+ while (trak.nextSample < trak.samples.length) {
86
86
  let result = void 0;
87
- if (trak?.samples[trak.nextSample]) {
88
- fragmentStartSamples[fragTrak.id] ||= trak.samples[trak.nextSample];
87
+ const fragTrakNextSample = trak.samples[trak.nextSample];
88
+ if (fragTrakNextSample) {
89
+ fragmentStartSamples[fragTrak.id] ||= fragTrakNextSample;
89
90
  }
90
91
  try {
91
92
  result = this.createFragment(
@@ -101,7 +102,7 @@ class MP4File extends MP4Box.ISOFile {
101
102
  trak.nextSample++;
102
103
  } else {
103
104
  finishedReading = await this.waitForMoreSamples();
104
- break eachSample;
105
+ break;
105
106
  }
106
107
  const nextSample = trak.samples[trak.nextSample];
107
108
  const emitSegment = (
@@ -113,8 +114,12 @@ class MP4File extends MP4Box.ISOFile {
113
114
  trak.nextSample >= trak.samples.length
114
115
  );
115
116
  if (emitSegment) {
117
+ const trackInfoForFrag = trackInfo[fragTrak.id];
118
+ if (!trackInfoForFrag) {
119
+ throw new Error("trackInfoForFrag is undefined");
120
+ }
116
121
  if (trak.nextSample >= trak.samples.length) {
117
- trackInfo[fragTrak.id].complete = true;
122
+ trackInfoForFrag.complete = true;
118
123
  }
119
124
  const startSample = fragmentStartSamples[fragTrak.id];
120
125
  const endSample = trak.samples[trak.nextSample - 1];
@@ -123,14 +128,14 @@ class MP4File extends MP4Box.ISOFile {
123
128
  }
124
129
  yield {
125
130
  track: fragTrak.id,
126
- segment: trackInfo[fragTrak.id].index,
131
+ segment: trackInfoForFrag.index,
127
132
  data: fragTrak.segmentStream.buffer,
128
- complete: trackInfo[fragTrak.id].complete,
133
+ complete: trackInfoForFrag.complete,
129
134
  cts: startSample.cts,
130
135
  dts: startSample.dts,
131
136
  duration: endSample.dts - startSample.dts + endSample.duration
132
137
  };
133
- trackInfo[fragTrak.id].index += 1;
138
+ trackInfoForFrag.index += 1;
134
139
  fragTrak.segmentStream = null;
135
140
  delete fragmentStartSamples[fragTrak.id];
136
141
  }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const msToTimeCode = (ms, subSecond = false) => {
4
+ const seconds = Math.floor(ms / 1e3);
5
+ const minutes = Math.floor(seconds / 60);
6
+ const hours = Math.floor(minutes / 60);
7
+ const pad = (num) => num.toString().padStart(2, "0");
8
+ let timecode = `${pad(hours)}:${pad(minutes % 60)}:${pad(seconds % 60)}`;
9
+ if (subSecond) {
10
+ const subSeconds = Math.floor(ms % 1e3 / 10);
11
+ timecode += `.${subSeconds.toString().padStart(2, "0")}`;
12
+ }
13
+ return timecode;
14
+ };
15
+ exports.msToTimeCode = msToTimeCode;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const awaitMicrotask = async () => {
4
+ await new Promise((resolve) => {
5
+ queueMicrotask(resolve);
6
+ });
7
+ };
8
+ exports.awaitMicrotask = awaitMicrotask;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const memoize = (_target, _propertyKey, descriptor) => {
4
+ const get = descriptor.get;
5
+ if (!get) return;
6
+ const memoized = /* @__PURE__ */ new WeakMap();
7
+ descriptor.get = function() {
8
+ if (!memoized.has(this)) {
9
+ memoized.set(this, get.call(this));
10
+ }
11
+ return memoized.get(this);
12
+ };
13
+ };
14
+ exports.memoize = memoize;
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const task = require("@lit/task");
4
+ const awaitMicrotask = require("../../../lib/util/awaitMicrotask.cjs");
5
+ const EFTemporal = require("./elements/EFTemporal.cjs");
6
+ const EFTimegroup = require("./elements/EFTimegroup.cjs");
7
+ class TriggerCanvas {
8
+ constructor() {
9
+ this.canvas = document.createElement("canvas");
10
+ this.canvas.width = 1;
11
+ this.canvas.height = 1;
12
+ Object.assign(this.canvas.style, {
13
+ position: "fixed",
14
+ top: "0px",
15
+ left: "0px",
16
+ width: "1px",
17
+ height: "1px",
18
+ zIndex: "100000"
19
+ });
20
+ document.body.prepend(this.canvas);
21
+ const ctx = this.canvas.getContext("2d", { willReadFrequently: true });
22
+ if (!ctx) throw new Error("Canvas 2d context not ready");
23
+ this.ctx = ctx;
24
+ this.ctx.fillStyle = "black";
25
+ }
26
+ trigger() {
27
+ console.log("TRIGGERING CANVAS");
28
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
29
+ }
30
+ }
31
+ class EfFramegen {
32
+ constructor() {
33
+ this.time = 0;
34
+ this.frameDurationMs = 0;
35
+ this.initialBusyTasks = Promise.resolve([]);
36
+ this.frameBox = document.createElement("div");
37
+ this.BRIDGE = window.FRAMEGEN_BRIDGE;
38
+ this.triggerCanvas = new TriggerCanvas();
39
+ if (this.BRIDGE) {
40
+ this.connectToBridge();
41
+ }
42
+ }
43
+ log(...args) {
44
+ console.log("[EF_FRAMEGEN]", ...args);
45
+ }
46
+ trace(...args) {
47
+ console.trace("[EF_FRAMEGEN]", ...args);
48
+ }
49
+ connectToBridge() {
50
+ const BRIDGE = this.BRIDGE;
51
+ if (!BRIDGE) {
52
+ throw new Error("No BRIDGE when attempting to connect to bridge");
53
+ }
54
+ BRIDGE.onInitialize(async (renderId, renderOptions) => {
55
+ this.log("BRIDGE.onInitialize", renderId, renderOptions);
56
+ await this.initialize(renderId, renderOptions);
57
+ BRIDGE.initialized(renderId);
58
+ });
59
+ BRIDGE.onBeginFrame((renderId, frameNumber, isLast) => {
60
+ this.log("BRIDGE.onBeginFrame", renderId, frameNumber, isLast);
61
+ this.beginFrame(renderId, frameNumber, isLast);
62
+ });
63
+ }
64
+ async initialize(renderId, renderOptions) {
65
+ addEventListener("unhandledrejection", (event) => {
66
+ this.trace("Unhandled rejection:", event.reason);
67
+ if (this.BRIDGE) {
68
+ this.BRIDGE.error(renderId, event.reason);
69
+ }
70
+ });
71
+ addEventListener("error", (event) => {
72
+ this.trace("Uncaught error", event.error);
73
+ if (this.BRIDGE) {
74
+ this.BRIDGE.error(renderId, event.error);
75
+ }
76
+ });
77
+ this.renderOptions = renderOptions;
78
+ const workbench = document.querySelector("ef-workbench");
79
+ if (!workbench) {
80
+ throw new Error("No workbench found");
81
+ }
82
+ workbench.rendering = true;
83
+ const timegroups = EFTimegroup.shallowGetTimegroups(workbench);
84
+ const temporals = EFTemporal.deepGetElementsWithFrameTasks(workbench);
85
+ const firstGroup = timegroups[0];
86
+ if (!firstGroup) {
87
+ throw new Error("No temporal elements found");
88
+ }
89
+ firstGroup.currentTimeMs = renderOptions.encoderOptions.fromMs;
90
+ this.frameDurationMs = 1e3 / renderOptions.encoderOptions.video.framerate;
91
+ this.initialBusyTasks = Promise.all(
92
+ temporals.filter((temporal) => temporal.frameTask.status < task.TaskStatus.COMPLETE).map((temporal) => temporal.frameTask).map((task2) => task2.taskComplete)
93
+ );
94
+ this.time = 0;
95
+ if (renderOptions.showFrameBox) {
96
+ Object.assign(this.frameBox.style, {
97
+ width: "200px",
98
+ height: "100px",
99
+ font: "30px Arial",
100
+ backgroundColor: "white",
101
+ position: "absolute",
102
+ top: "0px",
103
+ left: "0px",
104
+ zIndex: "100000"
105
+ });
106
+ document.body.prepend(this.frameBox);
107
+ }
108
+ this.audioBufferPromise = firstGroup.renderAudio(
109
+ renderOptions.encoderOptions.alignedFromUs / 1e3,
110
+ renderOptions.encoderOptions.alignedToUs / 1e3
111
+ // renderOptions.encoderOptions.fromMs,
112
+ // renderOptions.encoderOptions.toMs,
113
+ );
114
+ this.log("Initialized");
115
+ }
116
+ async beginFrame(renderId, frameNumber, isLast) {
117
+ if (this.renderOptions === void 0) {
118
+ throw new Error("No renderOptions");
119
+ }
120
+ if (this.renderOptions.showFrameBox) {
121
+ this.frameBox.innerHTML = `
122
+ <div>Frame #${frameNumber}</div>
123
+ <div>${this.time.toFixed(4)}</div>
124
+ `;
125
+ }
126
+ const workbench = document.querySelector("ef-workbench");
127
+ if (!workbench) {
128
+ throw new Error("No workbench found");
129
+ }
130
+ workbench.rendering = true;
131
+ const timegroups = EFTimegroup.shallowGetTimegroups(workbench);
132
+ const temporals = EFTemporal.deepGetElementsWithFrameTasks(workbench);
133
+ const firstGroup = timegroups[0];
134
+ if (!firstGroup) {
135
+ throw new Error("No temporal elements found");
136
+ }
137
+ this.time = this.renderOptions.encoderOptions.fromMs + frameNumber * this.frameDurationMs;
138
+ firstGroup.currentTimeMs = this.time;
139
+ await this.initialBusyTasks;
140
+ await awaitMicrotask.awaitMicrotask();
141
+ const now = performance.now();
142
+ await Promise.all(
143
+ temporals.filter((temporal) => temporal.frameTask.status < task.TaskStatus.COMPLETE).map((temporal) => {
144
+ return temporal.frameTask;
145
+ }).map((task2) => task2.taskComplete)
146
+ );
147
+ console.log(
148
+ `frame:${frameNumber} All tasks complete ${performance.now() - now}ms`
149
+ );
150
+ if (isLast && this.audioBufferPromise) {
151
+ const renderedAudio = await this.audioBufferPromise;
152
+ const channelCount = renderedAudio.numberOfChannels;
153
+ const interleavedSamples = new Float32Array(
154
+ channelCount * renderedAudio.length
155
+ );
156
+ for (let i = 0; i < renderedAudio.length; i++) {
157
+ for (let j = 0; j < channelCount; j++) {
158
+ interleavedSamples.set(
159
+ renderedAudio.getChannelData(j).slice(i, i + 1),
160
+ i * channelCount + j
161
+ );
162
+ }
163
+ }
164
+ if (this.BRIDGE) {
165
+ this.triggerCanvas.trigger();
166
+ this.BRIDGE.frameReady(
167
+ renderId,
168
+ frameNumber,
169
+ interleavedSamples.buffer
170
+ );
171
+ } else {
172
+ const fileReader = new FileReader();
173
+ fileReader.readAsDataURL(new Blob([interleavedSamples.buffer]));
174
+ await new Promise((resolve, reject) => {
175
+ fileReader.onload = resolve;
176
+ fileReader.onerror = reject;
177
+ });
178
+ return fileReader.result;
179
+ }
180
+ } else {
181
+ if (this.BRIDGE) {
182
+ this.triggerCanvas.trigger();
183
+ this.BRIDGE.frameReady(renderId, frameNumber, new ArrayBuffer(0));
184
+ } else {
185
+ const fileReader = new FileReader();
186
+ fileReader.readAsDataURL(new Blob([]));
187
+ await new Promise((resolve, reject) => {
188
+ fileReader.onload = resolve;
189
+ fileReader.onerror = reject;
190
+ });
191
+ return fileReader.result;
192
+ }
193
+ }
194
+ }
195
+ }
196
+ window.EF_FRAMEGEN = new EfFramegen();
197
+ exports.EfFramegen = EfFramegen;
@@ -0,0 +1,45 @@
1
+ import { VideoRenderOptions } from '../../assets';
2
+
3
+ declare global {
4
+ interface Window {
5
+ EF_FRAMEGEN?: EfFramegen;
6
+ FRAMEGEN_BRIDGE?: {
7
+ onInitialize: (callback: (renderId: string, renderOptions: VideoRenderOptions) => void) => void;
8
+ initialized(renderId: string): void;
9
+ onBeginFrame(callback: (renderId: string, frameNumber: number, isLast: boolean) => void): void;
10
+ onTriggerCanvas(callback: () => void): void;
11
+ frameReady(renderId: string, frameNumber: number, audioSamples: ArrayBuffer): void;
12
+ error(renderId: string, error: Error): void;
13
+ };
14
+ }
15
+ }
16
+ declare class TriggerCanvas {
17
+ private canvas;
18
+ private ctx;
19
+ constructor();
20
+ trigger(): void;
21
+ }
22
+ export declare class EfFramegen {
23
+ time: number;
24
+ frameDurationMs: number;
25
+ initialBusyTasks: Promise<unknown[]>;
26
+ audioBufferPromise?: Promise<AudioBuffer>;
27
+ renderOptions?: VideoRenderOptions;
28
+ frameBox: HTMLDivElement;
29
+ BRIDGE: {
30
+ onInitialize: (callback: (renderId: string, renderOptions: VideoRenderOptions) => void) => void;
31
+ initialized(renderId: string): void;
32
+ onBeginFrame(callback: (renderId: string, frameNumber: number, isLast: boolean) => void): void;
33
+ onTriggerCanvas(callback: () => void): void;
34
+ frameReady(renderId: string, frameNumber: number, audioSamples: ArrayBuffer): void;
35
+ error(renderId: string, error: Error): void;
36
+ } | undefined;
37
+ triggerCanvas: TriggerCanvas;
38
+ log(...args: any[]): void;
39
+ trace(...args: any[]): void;
40
+ constructor();
41
+ connectToBridge(): void;
42
+ initialize(renderId: string, renderOptions: VideoRenderOptions): Promise<void>;
43
+ beginFrame(renderId: string, frameNumber: number, isLast: boolean): Promise<string | ArrayBuffer | null | undefined>;
44
+ }
45
+ export {};
@@ -1,7 +1,7 @@
1
- import { deepGetElementsWithFrameTasks } from "./elements/EFTemporal.mjs";
2
- import { awaitMicrotask } from "../../../lib/util/awaitMicrotask.mjs";
3
1
  import { TaskStatus } from "@lit/task";
4
- import { shallowGetTimegroups } from "./elements/EFTimegroup.mjs";
2
+ import { awaitMicrotask } from "../../../lib/util/awaitMicrotask.js";
3
+ import { deepGetElementsWithFrameTasks } from "./elements/EFTemporal.js";
4
+ import { shallowGetTimegroups } from "./elements/EFTimegroup.js";
5
5
  class TriggerCanvas {
6
6
  constructor() {
7
7
  this.canvas = document.createElement("canvas");
@@ -11,12 +11,14 @@ class TriggerCanvas {
11
11
  position: "fixed",
12
12
  top: "0px",
13
13
  left: "0px",
14
- width: `1px`,
15
- height: `1px`,
14
+ width: "1px",
15
+ height: "1px",
16
16
  zIndex: "100000"
17
17
  });
18
18
  document.body.prepend(this.canvas);
19
- this.ctx = this.canvas.getContext("2d", { willReadFrequently: true });
19
+ const ctx = this.canvas.getContext("2d", { willReadFrequently: true });
20
+ if (!ctx) throw new Error("Canvas 2d context not ready");
21
+ this.ctx = ctx;
20
22
  this.ctx.fillStyle = "black";
21
23
  }
22
24
  trigger() {
@@ -72,6 +74,9 @@ class EfFramegen {
72
74
  });
73
75
  this.renderOptions = renderOptions;
74
76
  const workbench = document.querySelector("ef-workbench");
77
+ if (!workbench) {
78
+ throw new Error("No workbench found");
79
+ }
75
80
  workbench.rendering = true;
76
81
  const timegroups = shallowGetTimegroups(workbench);
77
82
  const temporals = deepGetElementsWithFrameTasks(workbench);
@@ -107,17 +112,26 @@ class EfFramegen {
107
112
  this.log("Initialized");
108
113
  }
109
114
  async beginFrame(renderId, frameNumber, isLast) {
110
- if (this.renderOptions?.showFrameBox) {
115
+ if (this.renderOptions === void 0) {
116
+ throw new Error("No renderOptions");
117
+ }
118
+ if (this.renderOptions.showFrameBox) {
111
119
  this.frameBox.innerHTML = `
112
120
  <div>Frame #${frameNumber}</div>
113
121
  <div>${this.time.toFixed(4)}</div>
114
122
  `;
115
123
  }
116
124
  const workbench = document.querySelector("ef-workbench");
125
+ if (!workbench) {
126
+ throw new Error("No workbench found");
127
+ }
117
128
  workbench.rendering = true;
118
129
  const timegroups = shallowGetTimegroups(workbench);
119
130
  const temporals = deepGetElementsWithFrameTasks(workbench);
120
131
  const firstGroup = timegroups[0];
132
+ if (!firstGroup) {
133
+ throw new Error("No temporal elements found");
134
+ }
121
135
  this.time = this.renderOptions.encoderOptions.fromMs + frameNumber * this.frameDurationMs;
122
136
  firstGroup.currentTimeMs = this.time;
123
137
  await this.initialBusyTasks;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const EF_INTERACTIVE = !window.location.search.includes("EF_NONINTERACTIVE");
4
+ exports.EF_INTERACTIVE = EF_INTERACTIVE;
@@ -0,0 +1 @@
1
+ export declare const EF_INTERACTIVE: boolean;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ class CrossUpdateController {
4
+ constructor(host, target) {
5
+ this.host = host;
6
+ this.target = target;
7
+ this.host.addController(this);
8
+ }
9
+ hostUpdate() {
10
+ this.target.requestUpdate();
11
+ }
12
+ remove() {
13
+ this.host.removeController(this);
14
+ }
15
+ }
16
+ exports.CrossUpdateController = CrossUpdateController;
@@ -0,0 +1,9 @@
1
+ import { LitElement, ReactiveController, ReactiveControllerHost } from 'lit';
2
+
3
+ export declare class CrossUpdateController implements ReactiveController {
4
+ private host;
5
+ private target;
6
+ constructor(host: ReactiveControllerHost, target: LitElement);
7
+ hostUpdate(): void;
8
+ remove(): void;
9
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const lit = require("lit");
4
+ const ref_js = require("lit/directives/ref.js");
5
+ const decorators_js = require("lit/decorators.js");
6
+ const EFMedia = require("./EFMedia.cjs");
7
+ const task = require("@lit/task");
8
+ var __defProp = Object.defineProperty;
9
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
+ var __decorateClass = (decorators, target, key, kind) => {
11
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
12
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
13
+ if (decorator = decorators[i])
14
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
15
+ if (kind && result) __defProp(target, key, result);
16
+ return result;
17
+ };
18
+ exports.EFAudio = class EFAudio extends EFMedia.EFMedia {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.audioElementRef = ref_js.createRef();
22
+ this.src = "";
23
+ this.frameTask = new task.Task(this, {
24
+ args: () => [
25
+ this.trackFragmentIndexLoader.status,
26
+ this.initSegmentsLoader.status,
27
+ this.seekTask.status,
28
+ this.fetchSeekTask.status,
29
+ this.videoAssetTask.status
30
+ ],
31
+ task: async () => {
32
+ await this.trackFragmentIndexLoader.taskComplete;
33
+ await this.initSegmentsLoader.taskComplete;
34
+ await this.seekTask.taskComplete;
35
+ await this.fetchSeekTask.taskComplete;
36
+ await this.videoAssetTask.taskComplete;
37
+ this.rootTimegroup?.requestUpdate();
38
+ }
39
+ });
40
+ }
41
+ render() {
42
+ return lit.html`<audio ${ref_js.ref(this.audioElementRef)}></audio>`;
43
+ }
44
+ get audioElement() {
45
+ return this.audioElementRef.value;
46
+ }
47
+ };
48
+ __decorateClass([
49
+ decorators_js.property({ type: String })
50
+ ], exports.EFAudio.prototype, "src", 2);
51
+ exports.EFAudio = __decorateClass([
52
+ decorators_js.customElement("ef-audio")
53
+ ], exports.EFAudio);