@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,561 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const MP4Box = require("mp4box");
4
+ const memoize = require("../util/memoize.cjs");
5
+ const MP4File = require("./MP4File.cjs");
6
+ function _interopNamespaceDefault(e) {
7
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
8
+ if (e) {
9
+ for (const k in e) {
10
+ if (k !== "default") {
11
+ const d = Object.getOwnPropertyDescriptor(e, k);
12
+ Object.defineProperty(n, k, d.get ? d : {
13
+ enumerable: true,
14
+ get: () => e[k]
15
+ });
16
+ }
17
+ }
18
+ }
19
+ n.default = e;
20
+ return Object.freeze(n);
21
+ }
22
+ const MP4Box__namespace = /* @__PURE__ */ _interopNamespaceDefault(MP4Box);
23
+ var __defProp = Object.defineProperty;
24
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
25
+ var __decorateClass = (decorators, target, key, kind) => {
26
+ var result = __getOwnPropDesc(target, key);
27
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
28
+ if (decorator = decorators[i])
29
+ result = decorator(target, key, result) || result;
30
+ if (result) __defProp(target, key, result);
31
+ return result;
32
+ };
33
+ const BUFFER_SIZE = 10;
34
+ class AssetNotAvailableLocally extends Error {
35
+ }
36
+ class FileAsset {
37
+ constructor(localName, file) {
38
+ this.localName = localName;
39
+ this.file = file;
40
+ }
41
+ async arrayBuffer() {
42
+ return this.file.arrayBuffer();
43
+ }
44
+ get byteSize() {
45
+ return this.file.size;
46
+ }
47
+ get fileExtension() {
48
+ return this.file.name.split(".").pop();
49
+ }
50
+ slice(start, end) {
51
+ return this.file.slice(start, end);
52
+ }
53
+ }
54
+ class ISOFileAsset extends FileAsset {
55
+ constructor(localName, file, mp4boxFile) {
56
+ super(localName, file);
57
+ this.localName = localName;
58
+ this.file = file;
59
+ this.mp4boxFile = mp4boxFile;
60
+ }
61
+ get fileInfo() {
62
+ return this.mp4boxFile.getInfo();
63
+ }
64
+ get containerFormat() {
65
+ return "mp4";
66
+ }
67
+ }
68
+ __decorateClass([
69
+ memoize.memoize
70
+ ], ISOFileAsset.prototype, "fileInfo");
71
+ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
72
+ constructor(localName, mp4boxFile, file) {
73
+ super(localName, file, mp4boxFile);
74
+ this.decodedFrames = [];
75
+ this.requestedSampleNumber = 0;
76
+ this.outCursor = 0;
77
+ this.sampleCursor = 0;
78
+ this.eventListeners = {};
79
+ this.latestSeekCts = 0;
80
+ this.videoDecoder = new VideoDecoder({
81
+ error: (e) => {
82
+ console.error(e);
83
+ },
84
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
85
+ output: async (decodedFrame) => {
86
+ const clone = decodedFrame.clone();
87
+ this.decodedFrames.push(clone);
88
+ this.pruneBuffer();
89
+ decodedFrame.close();
90
+ this.outCursor = this.samples.findIndex(
91
+ (sample) => sample.cts === decodedFrame.timestamp
92
+ );
93
+ this.emit("frame", clone);
94
+ }
95
+ });
96
+ this.configureDecoder();
97
+ }
98
+ static async createFromReadableStream(id, stream, file) {
99
+ let fileStart = 0;
100
+ const inputFile = new MP4File.MP4File();
101
+ const reader = stream.getReader();
102
+ const processChunk = ({
103
+ done,
104
+ value
105
+ }) => {
106
+ if (done) {
107
+ return;
108
+ }
109
+ if (!value) {
110
+ return;
111
+ }
112
+ const mp4buffer = value.buffer;
113
+ mp4buffer.fileStart = fileStart;
114
+ const isLast = file.size === fileStart + value.byteLength;
115
+ inputFile.appendBuffer(mp4buffer, isLast);
116
+ fileStart += value.byteLength;
117
+ return reader.read().then(processChunk);
118
+ };
119
+ await reader.read().then(processChunk);
120
+ return new _VideoAsset2(id, inputFile, file);
121
+ }
122
+ /**
123
+ * **Only use this function in tests to reset a VideoAsset to its initial state.**
124
+ *
125
+ * @deprecated
126
+ */
127
+ async TEST_ONLY_RESET() {
128
+ await this.videoDecoder.flush();
129
+ this.configureDecoder();
130
+ this.requestedSampleNumber = 0;
131
+ this.outCursor = 0;
132
+ this.sampleCursor = 0;
133
+ for (const frame of this.decodedFrames) {
134
+ frame.close();
135
+ }
136
+ this.decodedFrames = [];
137
+ this.lastDecodedSample = void 0;
138
+ this.lastSoughtFrame?.close();
139
+ this.lastSoughtFrame = void 0;
140
+ }
141
+ addEventListener(type, callback) {
142
+ this.eventListeners[type] ||= /* @__PURE__ */ new Set();
143
+ this.eventListeners[type]?.add(callback);
144
+ }
145
+ removeEventListener(type, callback) {
146
+ this.eventListeners[type]?.delete(callback);
147
+ }
148
+ emit(type, ...args) {
149
+ for (const listener of this.eventListeners[type] ?? []) {
150
+ listener(...args);
151
+ }
152
+ }
153
+ get videoCodec() {
154
+ if (!this.defaultVideoTrack) {
155
+ throw new Error("No default video track found");
156
+ }
157
+ return this.defaultVideoTrack?.codec;
158
+ }
159
+ get fragmentInfo() {
160
+ const fragments = [];
161
+ const [first, ...samples] = this.samples;
162
+ if (!first) {
163
+ return fragments;
164
+ }
165
+ let currentFragment = {
166
+ offset: first.offset,
167
+ size: first.size,
168
+ start_ms: first.cts,
169
+ duration_ms: 0
170
+ };
171
+ for (const sample of samples) {
172
+ if (sample.is_sync) {
173
+ if (currentFragment) {
174
+ currentFragment.duration_ms = sample.cts - currentFragment.start_ms;
175
+ fragments.push(currentFragment);
176
+ }
177
+ currentFragment = {
178
+ offset: sample.offset,
179
+ size: sample.size,
180
+ start_ms: sample.cts,
181
+ duration_ms: 0
182
+ };
183
+ } else {
184
+ currentFragment.size += sample.size;
185
+ }
186
+ }
187
+ return fragments;
188
+ }
189
+ pruneBuffer() {
190
+ if (this.decodedFrames.length > BUFFER_SIZE) {
191
+ this.decodedFrames.shift()?.close();
192
+ }
193
+ }
194
+ prettyPrint() {
195
+ const samplesInEncoder = this.sampleCursor - this.outCursor;
196
+ const cachedSamples = this.decodedFrames.length;
197
+ console.log(
198
+ Array.from({
199
+ length: this.sampleCursor - samplesInEncoder - cachedSamples
200
+ }).fill("⬜️").join(" "),
201
+ Array.from({ length: cachedSamples }).fill("🟩").join(" "),
202
+ Array.from({
203
+ length: samplesInEncoder
204
+ }).fill("🟨").join(" ")
205
+ );
206
+ }
207
+ get editsOffset() {
208
+ if (!this.defaultVideoTrack?.edits) {
209
+ return 0;
210
+ }
211
+ return this.defaultVideoTrack.edits.reduce((acc, edit) => {
212
+ return acc + edit.media_time;
213
+ }, 0);
214
+ }
215
+ async waitUntilVideoQueueDrained() {
216
+ if (this.videoDecoder.decodeQueueSize === 0) {
217
+ return;
218
+ }
219
+ await new Promise((resolve) => {
220
+ this.videoDecoder.addEventListener(
221
+ "dequeue",
222
+ () => {
223
+ resolve();
224
+ },
225
+ { once: true }
226
+ );
227
+ });
228
+ await this.waitUntilVideoQueueDrained();
229
+ }
230
+ get canDecodeNextSample() {
231
+ return this.sampleCursor < this.samples.length;
232
+ }
233
+ async decodeNextSample() {
234
+ if (!this.canDecodeNextSample) {
235
+ throw new Error("No more samples to decode");
236
+ }
237
+ await this.decodeSlice(this.sampleCursor, this.sampleCursor);
238
+ this.sampleCursor++;
239
+ }
240
+ async decodeSlice(start, end) {
241
+ const samples = this.samples.slice(start, end + 1);
242
+ const firstSample = samples[0];
243
+ const lastSample = samples[samples.length - 1];
244
+ if (!firstSample || !lastSample) {
245
+ throw new Error("Samples not found");
246
+ }
247
+ const sliceStart = firstSample.offset;
248
+ const sliceEnd = lastSample.offset + lastSample.size;
249
+ const buffer = await this.file.slice(sliceStart, sliceEnd).arrayBuffer();
250
+ const firstSampleOffset = firstSample.offset;
251
+ for (let i = start; i <= end; i++) {
252
+ await this.waitUntilVideoQueueDrained();
253
+ const sample = this.getSample(i);
254
+ const sampleStart = sample.offset - firstSampleOffset;
255
+ const sampleEnd = sample.offset + sample.size - firstSampleOffset;
256
+ const chunk = new EncodedVideoChunk({
257
+ data: buffer.slice(sampleStart, sampleEnd),
258
+ timestamp: sample.cts,
259
+ duration: sample.duration,
260
+ type: sample.is_sync ? "key" : "delta"
261
+ });
262
+ this.videoDecoder.decode(chunk);
263
+ const nextSample = this.defaultVideoTrak?.samples?.[i + 1];
264
+ if (nextSample === void 0) {
265
+ await this.videoDecoder.flush();
266
+ }
267
+ }
268
+ }
269
+ get decoderConfiguration() {
270
+ if (!this.defaultVideoTrack) {
271
+ throw new Error("No default video track found");
272
+ }
273
+ let description = new Uint8Array();
274
+ const trak = this.mp4boxFile.getTrackById(this.defaultVideoTrack.id);
275
+ for (const entry of trak.mdia.minf.stbl.stsd.entries) {
276
+ if (entry.avcC ?? entry.hvcC) {
277
+ const stream = new MP4Box__namespace.DataStream(
278
+ void 0,
279
+ 0,
280
+ MP4Box__namespace.DataStream.BIG_ENDIAN
281
+ );
282
+ if (entry.avcC) {
283
+ entry.avcC.write(stream);
284
+ } else {
285
+ entry.hvcC.write(stream);
286
+ }
287
+ description = new Uint8Array(stream.buffer, 8);
288
+ break;
289
+ }
290
+ }
291
+ return {
292
+ codec: this.defaultVideoTrack.codec,
293
+ codedWidth: this.defaultVideoTrack.track_width,
294
+ codedHeight: this.defaultVideoTrack.track_height,
295
+ optimizeForLatency: true,
296
+ description
297
+ };
298
+ }
299
+ /**
300
+ * Configures the video decoder with the appropriate codec, dimensions, and hardware acceleration settings.
301
+ * If the decoder is already configured, it will be reset before being reconfigured.
302
+ */
303
+ configureDecoder() {
304
+ if (this.videoDecoder.state === "configured") {
305
+ this.videoDecoder.reset();
306
+ }
307
+ this.videoDecoder.configure(this.decoderConfiguration);
308
+ }
309
+ // Default to -1 to throw error if called without an index
310
+ getSample(index = -1) {
311
+ const sample = this.samples?.[index];
312
+ if (!sample) {
313
+ throw new Error(`Sample not found at index ${index}`);
314
+ }
315
+ return sample;
316
+ }
317
+ get timescale() {
318
+ if (!this.defaultVideoTrack) {
319
+ throw new Error("No default video track found");
320
+ }
321
+ return this.defaultVideoTrack.timescale;
322
+ }
323
+ get samples() {
324
+ if (!this.defaultVideoTrak.samples) {
325
+ throw new Error("No video samples found");
326
+ }
327
+ return this.defaultVideoTrak.samples;
328
+ }
329
+ get displayOrderedSamples() {
330
+ return Array.from(this.samples).sort((a, b) => {
331
+ return a.cts - b.cts;
332
+ });
333
+ }
334
+ getSampleClosetToTime(seconds) {
335
+ const targetTime = Math.round(seconds * this.timescale + this.editsOffset);
336
+ const sampleIndex = this.displayOrderedSamples.findIndex(
337
+ (sample) => sample.cts >= targetTime
338
+ );
339
+ if (sampleIndex === -1) {
340
+ return this.displayOrderedSamples[this.displayOrderedSamples.length - 1];
341
+ }
342
+ return this.displayOrderedSamples[sampleIndex];
343
+ }
344
+ seekingWillEmitNewFrame(seconds) {
345
+ if (!this.lastSoughtFrame) {
346
+ return true;
347
+ }
348
+ if (this.seekingWillGoBackwards(seconds)) {
349
+ return true;
350
+ }
351
+ const nextCts = this.getSampleClosetToTime(seconds).cts;
352
+ return nextCts > this.lastSoughtFrame.timestamp;
353
+ }
354
+ seekingWillSkipPictureGroup(seconds) {
355
+ let start = this.sampleCursor;
356
+ const end = this.getSampleClosetToTime(seconds).number;
357
+ let syncFrameCrossings = 0;
358
+ while (start <= end) {
359
+ const sample = this.getSample(start);
360
+ if (sample.is_sync) {
361
+ if (syncFrameCrossings > 1) {
362
+ return true;
363
+ }
364
+ syncFrameCrossings++;
365
+ }
366
+ start++;
367
+ }
368
+ return false;
369
+ }
370
+ seekingWillGoBackwards(seconds) {
371
+ const targetSample = this.getSampleClosetToTime(seconds);
372
+ const targetIndex = this.displayOrderedSamples.indexOf(targetSample);
373
+ const targetInCache = this.decodedFrames.find(
374
+ (frame) => frame.timestamp === targetSample.cts
375
+ );
376
+ const atEnd = this.sampleCursor === this.samples.length - 1;
377
+ if (atEnd) {
378
+ return false;
379
+ }
380
+ if (targetInCache) {
381
+ return false;
382
+ }
383
+ return this.outCursor > targetIndex;
384
+ }
385
+ async seekToTime(seconds) {
386
+ const sample = this.getSampleClosetToTime(seconds);
387
+ const cts = sample.cts;
388
+ this.latestSeekCts = cts;
389
+ const alreadyDecodedFrame = this.decodedFrames.find(
390
+ (f) => f.timestamp === cts
391
+ );
392
+ if (alreadyDecodedFrame) {
393
+ return alreadyDecodedFrame;
394
+ }
395
+ if (this.seekingWillSkipPictureGroup(seconds)) {
396
+ await this.videoDecoder.flush();
397
+ let syncSampleNumber = sample.number;
398
+ while (!this.getSample(syncSampleNumber).is_sync) {
399
+ syncSampleNumber--;
400
+ }
401
+ this.sampleCursor = syncSampleNumber;
402
+ }
403
+ if (this.seekingWillGoBackwards(seconds)) {
404
+ console.log("BACKWARDS FLUSH");
405
+ await this.videoDecoder.flush();
406
+ for (const frame2 of this.decodedFrames) {
407
+ frame2.close();
408
+ }
409
+ this.decodedFrames = [];
410
+ let syncSampleNumber = sample.number;
411
+ while (!this.getSample(syncSampleNumber).is_sync) {
412
+ syncSampleNumber--;
413
+ }
414
+ this.sampleCursor = syncSampleNumber;
415
+ }
416
+ let frame;
417
+ const maybeFrame = (_frame) => {
418
+ if (frame) {
419
+ return;
420
+ }
421
+ if (_frame.timestamp === cts) {
422
+ this.removeEventListener("frame", maybeFrame);
423
+ frame = _frame;
424
+ }
425
+ };
426
+ this.addEventListener("frame", maybeFrame);
427
+ while (frame === void 0 && this.canDecodeNextSample) {
428
+ await this.decodeNextSample();
429
+ }
430
+ this.removeEventListener("frame", maybeFrame);
431
+ if (frame) {
432
+ if (this.lastSoughtFrame && !this.decodedFrames.includes(this.lastSoughtFrame)) {
433
+ this.lastSoughtFrame.close();
434
+ }
435
+ this.lastSoughtFrame = frame;
436
+ }
437
+ return frame;
438
+ }
439
+ get defaultVideoTrack() {
440
+ return this.fileInfo.videoTracks[0];
441
+ }
442
+ get defaultVideoTrak() {
443
+ return this.mp4boxFile.getTrackById(this.defaultVideoTrack?.id ?? -1);
444
+ }
445
+ get duration() {
446
+ return this.fileInfo.duration / this.fileInfo.timescale;
447
+ }
448
+ };
449
+ __decorateClass([
450
+ memoize.memoize
451
+ ], _VideoAsset.prototype, "editsOffset");
452
+ __decorateClass([
453
+ memoize.memoize
454
+ ], _VideoAsset.prototype, "timescale");
455
+ __decorateClass([
456
+ memoize.memoize
457
+ ], _VideoAsset.prototype, "samples");
458
+ __decorateClass([
459
+ memoize.memoize
460
+ ], _VideoAsset.prototype, "displayOrderedSamples");
461
+ __decorateClass([
462
+ memoize.memoize
463
+ ], _VideoAsset.prototype, "defaultVideoTrack");
464
+ __decorateClass([
465
+ memoize.memoize
466
+ ], _VideoAsset.prototype, "defaultVideoTrak");
467
+ __decorateClass([
468
+ memoize.memoize
469
+ ], _VideoAsset.prototype, "duration");
470
+ let VideoAsset = _VideoAsset;
471
+ const _AudioAsset = class _AudioAsset2 extends ISOFileAsset {
472
+ static async createFromReadableStream(id, stream, file) {
473
+ let fileStart = 0;
474
+ const inputFile = new MP4File.MP4File();
475
+ const reader = stream.getReader();
476
+ const processChunk = ({
477
+ done,
478
+ value
479
+ }) => {
480
+ if (done) {
481
+ return;
482
+ }
483
+ if (!value) {
484
+ return;
485
+ }
486
+ const mp4buffer = value.buffer;
487
+ mp4buffer.fileStart = fileStart;
488
+ fileStart += value.byteLength;
489
+ inputFile.appendBuffer(mp4buffer);
490
+ return reader.read().then(processChunk);
491
+ };
492
+ await reader.read().then(processChunk);
493
+ return new _AudioAsset2(id, file, inputFile);
494
+ }
495
+ get defaultAudioTrack() {
496
+ return this.fileInfo.audioTracks[0];
497
+ }
498
+ get defaultAudioTrak() {
499
+ return this.mp4boxFile.getTrackById(this.defaultAudioTrack?.id ?? -1);
500
+ }
501
+ get audioCodec() {
502
+ if (!this.defaultAudioTrack) {
503
+ throw new Error("No default audio track found");
504
+ }
505
+ return this.defaultAudioTrack.codec;
506
+ }
507
+ get samplerate() {
508
+ if (!this.defaultAudioTrack) {
509
+ throw new Error("No default audio track found");
510
+ }
511
+ return this.defaultAudioTrack.audio.sample_rate;
512
+ }
513
+ get channelCount() {
514
+ if (!this.defaultAudioTrack) {
515
+ throw new Error("No default audio track found");
516
+ }
517
+ return this.defaultAudioTrack.audio.channel_count;
518
+ }
519
+ };
520
+ __decorateClass([
521
+ memoize.memoize
522
+ ], _AudioAsset.prototype, "defaultAudioTrack");
523
+ __decorateClass([
524
+ memoize.memoize
525
+ ], _AudioAsset.prototype, "defaultAudioTrak");
526
+ __decorateClass([
527
+ memoize.memoize
528
+ ], _AudioAsset.prototype, "audioCodec");
529
+ __decorateClass([
530
+ memoize.memoize
531
+ ], _AudioAsset.prototype, "samplerate");
532
+ __decorateClass([
533
+ memoize.memoize
534
+ ], _AudioAsset.prototype, "channelCount");
535
+ const _ImageAsset = class _ImageAsset2 extends FileAsset {
536
+ static async createFromReadableStream(id, file) {
537
+ if (file.size === 0) {
538
+ throw new AssetNotAvailableLocally();
539
+ }
540
+ return new _ImageAsset2(id, file);
541
+ }
542
+ get objectUrl() {
543
+ return URL.createObjectURL(this.file);
544
+ }
545
+ get format() {
546
+ return this.fileExtension;
547
+ }
548
+ get type() {
549
+ return `image/${this.format}`;
550
+ }
551
+ };
552
+ __decorateClass([
553
+ memoize.memoize
554
+ ], _ImageAsset.prototype, "objectUrl");
555
+ __decorateClass([
556
+ memoize.memoize
557
+ ], _ImageAsset.prototype, "format");
558
+ exports.AssetNotAvailableLocally = AssetNotAvailableLocally;
559
+ exports.FileAsset = FileAsset;
560
+ exports.ISOFileAsset = ISOFileAsset;
561
+ exports.VideoAsset = VideoAsset;
@@ -1,6 +1,6 @@
1
1
  import * as MP4Box from "mp4box";
2
- import { memoize } from "../util/memoize.mjs";
3
- import { MP4File } from "./MP4File.mjs";
2
+ import { memoize } from "../util/memoize.js";
3
+ import { MP4File } from "./MP4File.js";
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __decorateClass = (decorators, target, key, kind) => {
@@ -111,9 +111,9 @@ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
111
111
  this.requestedSampleNumber = 0;
112
112
  this.outCursor = 0;
113
113
  this.sampleCursor = 0;
114
- this.decodedFrames.forEach((frame) => {
114
+ for (const frame of this.decodedFrames) {
115
115
  frame.close();
116
- });
116
+ }
117
117
  this.decodedFrames = [];
118
118
  this.lastDecodedSample = void 0;
119
119
  this.lastSoughtFrame?.close();
@@ -127,9 +127,9 @@ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
127
127
  this.eventListeners[type]?.delete(callback);
128
128
  }
129
129
  emit(type, ...args) {
130
- this.eventListeners[type]?.forEach((listener) => {
130
+ for (const listener of this.eventListeners[type] ?? []) {
131
131
  listener(...args);
132
- });
132
+ }
133
133
  }
134
134
  get videoCodec() {
135
135
  if (!this.defaultVideoTrack) {
@@ -220,10 +220,15 @@ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
220
220
  }
221
221
  async decodeSlice(start, end) {
222
222
  const samples = this.samples.slice(start, end + 1);
223
- const sliceStart = samples[0].offset;
224
- const sliceEnd = samples[samples.length - 1].offset + samples[samples.length - 1].size;
223
+ const firstSample = samples[0];
224
+ const lastSample = samples[samples.length - 1];
225
+ if (!firstSample || !lastSample) {
226
+ throw new Error("Samples not found");
227
+ }
228
+ const sliceStart = firstSample.offset;
229
+ const sliceEnd = lastSample.offset + lastSample.size;
225
230
  const buffer = await this.file.slice(sliceStart, sliceEnd).arrayBuffer();
226
- const firstSampleOffset = samples[0].offset;
231
+ const firstSampleOffset = firstSample.offset;
227
232
  for (let i = start; i <= end; i++) {
228
233
  await this.waitUntilVideoQueueDrained();
229
234
  const sample = this.getSample(i);
@@ -246,7 +251,7 @@ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
246
251
  if (!this.defaultVideoTrack) {
247
252
  throw new Error("No default video track found");
248
253
  }
249
- let description;
254
+ let description = new Uint8Array();
250
255
  const trak = this.mp4boxFile.getTrackById(this.defaultVideoTrack.id);
251
256
  for (const entry of trak.mdia.minf.stbl.stsd.entries) {
252
257
  if (entry.avcC ?? entry.hvcC) {
@@ -286,7 +291,7 @@ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
286
291
  getSample(index = -1) {
287
292
  const sample = this.samples?.[index];
288
293
  if (!sample) {
289
- throw new Error("Sample not found at index " + index);
294
+ throw new Error(`Sample not found at index ${index}`);
290
295
  }
291
296
  return sample;
292
297
  }
@@ -379,9 +384,9 @@ const _VideoAsset = class _VideoAsset2 extends ISOFileAsset {
379
384
  if (this.seekingWillGoBackwards(seconds)) {
380
385
  console.log("BACKWARDS FLUSH");
381
386
  await this.videoDecoder.flush();
382
- this.decodedFrames.forEach((frame2) => {
387
+ for (const frame2 of this.decodedFrames) {
383
388
  frame2.close();
384
- });
389
+ }
385
390
  this.decodedFrames = [];
386
391
  let syncSampleNumber = sample.number;
387
392
  while (!this.getSample(syncSampleNumber).is_sync) {