@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.
- package/dist/lib/av/EncodedAsset.cjs +561 -0
- package/dist/lib/av/{EncodedAsset.mjs → EncodedAsset.js} +18 -13
- package/dist/lib/av/MP4File.cjs +182 -0
- package/dist/lib/av/{MP4File.mjs → MP4File.js} +14 -9
- package/dist/lib/av/msToTimeCode.cjs +15 -0
- package/dist/lib/util/awaitMicrotask.cjs +8 -0
- package/dist/lib/util/memoize.cjs +14 -0
- package/dist/packages/elements/src/EF_FRAMEGEN.cjs +197 -0
- package/dist/packages/elements/src/EF_FRAMEGEN.d.ts +45 -0
- package/dist/packages/elements/src/{EF_FRAMEGEN.mjs → EF_FRAMEGEN.js} +21 -7
- package/dist/packages/elements/src/EF_INTERACTIVE.cjs +4 -0
- package/dist/packages/elements/src/EF_INTERACTIVE.d.ts +1 -0
- package/dist/packages/elements/src/elements/CrossUpdateController.cjs +16 -0
- package/dist/packages/elements/src/elements/CrossUpdateController.d.ts +9 -0
- package/dist/packages/elements/src/elements/EFAudio.cjs +53 -0
- package/dist/packages/elements/src/elements/EFAudio.d.ts +10 -0
- package/dist/packages/elements/src/elements/{EFAudio.mjs → EFAudio.js} +1 -1
- package/dist/packages/elements/src/elements/EFCaptions.cjs +171 -0
- package/dist/packages/elements/src/elements/EFCaptions.d.ts +39 -0
- package/dist/packages/elements/src/elements/{EFCaptions.mjs → EFCaptions.js} +13 -13
- package/dist/packages/elements/src/elements/EFImage.cjs +79 -0
- package/dist/packages/elements/src/elements/EFImage.d.ts +14 -0
- package/dist/packages/elements/src/elements/{EFImage.mjs → EFImage.js} +6 -4
- package/dist/packages/elements/src/elements/EFMedia.cjs +334 -0
- package/dist/packages/elements/src/elements/EFMedia.d.ts +61 -0
- package/dist/packages/elements/src/elements/{EFMedia.mjs → EFMedia.js} +29 -18
- package/dist/packages/elements/src/elements/EFSourceMixin.cjs +55 -0
- package/dist/packages/elements/src/elements/EFSourceMixin.d.ts +12 -0
- package/dist/packages/elements/src/elements/{EFSourceMixin.mjs → EFSourceMixin.js} +1 -1
- package/dist/packages/elements/src/elements/EFTemporal.cjs +198 -0
- package/dist/packages/elements/src/elements/EFTemporal.d.ts +36 -0
- package/dist/packages/elements/src/elements/{EFTemporal.mjs → EFTemporal.js} +4 -7
- package/dist/packages/elements/src/elements/EFTimegroup.browsertest.d.ts +12 -0
- package/dist/packages/elements/src/elements/EFTimegroup.cjs +343 -0
- package/dist/packages/elements/src/elements/EFTimegroup.d.ts +39 -0
- package/dist/packages/elements/src/elements/{EFTimegroup.mjs → EFTimegroup.js} +23 -22
- package/dist/packages/elements/src/elements/EFTimeline.cjs +15 -0
- package/dist/packages/elements/src/elements/EFTimeline.d.ts +3 -0
- package/dist/packages/elements/src/elements/{EFTimeline.mjs → EFTimeline.js} +5 -2
- package/dist/packages/elements/src/elements/EFVideo.cjs +110 -0
- package/dist/packages/elements/src/elements/EFVideo.d.ts +14 -0
- package/dist/packages/elements/src/elements/{EFVideo.mjs → EFVideo.js} +2 -2
- package/dist/packages/elements/src/elements/EFWaveform.cjs +235 -0
- package/dist/packages/elements/src/elements/EFWaveform.d.ts +28 -0
- package/dist/packages/elements/src/elements/{EFWaveform.mjs → EFWaveform.js} +14 -14
- package/dist/packages/elements/src/elements/FetchMixin.cjs +28 -0
- package/dist/packages/elements/src/elements/FetchMixin.d.ts +8 -0
- package/dist/packages/elements/src/elements/{FetchMixin.mjs → FetchMixin.js} +1 -1
- package/dist/packages/elements/src/elements/TimegroupController.cjs +20 -0
- package/dist/packages/elements/src/elements/TimegroupController.d.ts +14 -0
- package/dist/packages/elements/src/elements/durationConverter.cjs +8 -0
- package/dist/packages/elements/src/elements/durationConverter.d.ts +4 -0
- package/dist/packages/elements/src/elements/{durationConverter.mjs → durationConverter.js} +1 -1
- package/dist/packages/elements/src/elements/parseTimeToMs.cjs +12 -0
- package/dist/packages/elements/src/elements/parseTimeToMs.d.ts +1 -0
- package/dist/packages/elements/src/elements/parseTimeToMs.js +12 -0
- package/dist/packages/elements/src/elements/util.cjs +11 -0
- package/dist/packages/elements/src/elements/util.d.ts +4 -0
- package/dist/packages/elements/src/elements/{util.mjs → util.js} +1 -1
- package/dist/packages/elements/src/gui/EFFilmstrip.cjs +675 -0
- package/dist/packages/elements/src/gui/EFFilmstrip.d.ts +138 -0
- package/dist/packages/elements/src/gui/{EFFilmstrip.mjs → EFFilmstrip.js} +48 -34
- package/dist/packages/elements/src/gui/EFWorkbench.cjs +199 -0
- package/dist/packages/elements/src/gui/EFWorkbench.d.ts +44 -0
- package/dist/packages/elements/src/gui/{EFWorkbench.mjs → EFWorkbench.js} +26 -27
- package/dist/packages/elements/src/gui/TWMixin.cjs +28 -0
- package/dist/packages/elements/src/gui/TWMixin.css.cjs +3 -0
- package/dist/packages/elements/src/gui/TWMixin.d.ts +3 -0
- package/dist/packages/elements/src/gui/{TWMixin.mjs → TWMixin.js} +4 -3
- package/dist/packages/elements/src/index.cjs +47 -0
- package/dist/packages/elements/src/index.d.ts +10 -0
- package/dist/packages/elements/src/index.js +23 -0
- package/package.json +18 -4
- package/dist/packages/elements/src/elements/parseTimeToMs.mjs +0 -13
- package/dist/packages/elements/src/elements.mjs +0 -12
- /package/dist/lib/av/{msToTimeCode.mjs → msToTimeCode.js} +0 -0
- /package/dist/lib/util/{awaitMicrotask.mjs → awaitMicrotask.js} +0 -0
- /package/dist/lib/util/{memoize.mjs → memoize.js} +0 -0
- /package/dist/packages/elements/src/{EF_INTERACTIVE.mjs → EF_INTERACTIVE.js} +0 -0
- /package/dist/packages/elements/src/elements/{CrossUpdateController.mjs → CrossUpdateController.js} +0 -0
- /package/dist/packages/elements/src/elements/{TimegroupController.mjs → TimegroupController.js} +0 -0
- /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
|
-
|
|
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
|
-
|
|
85
|
+
while (trak.nextSample < trak.samples.length) {
|
|
86
86
|
let result = void 0;
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
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
|
-
|
|
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:
|
|
131
|
+
segment: trackInfoForFrag.index,
|
|
127
132
|
data: fragTrak.segmentStream.buffer,
|
|
128
|
-
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
|
-
|
|
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,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 {
|
|
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:
|
|
15
|
-
height:
|
|
14
|
+
width: "1px",
|
|
15
|
+
height: "1px",
|
|
16
16
|
zIndex: "100000"
|
|
17
17
|
});
|
|
18
18
|
document.body.prepend(this.canvas);
|
|
19
|
-
|
|
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
|
|
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 @@
|
|
|
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);
|