@remotion/webcodecs 4.0.244 → 4.0.246
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/LICENSE.md +1 -1
- package/dist/audio-decoder.d.ts +2 -1
- package/dist/audio-encoder.d.ts +2 -1
- package/dist/auto-select-writer.d.ts +1 -1
- package/dist/auto-select-writer.js +4 -4
- package/dist/convert-encoded-chunk.d.ts +0 -1
- package/dist/convert-encoded-chunk.js +1 -21
- package/dist/convert-media.d.ts +3 -2
- package/dist/convert-media.js +5 -3
- package/dist/create/event-emitter.d.ts +31 -0
- package/dist/create/event-emitter.js +25 -0
- package/dist/create/iso-base-media/codec-specific/avc1.d.ts +2 -0
- package/dist/create/iso-base-media/codec-specific/avc1.js +48 -0
- package/dist/create/iso-base-media/codec-specific/create-codec-specific-data.d.ts +22 -0
- package/dist/create/iso-base-media/codec-specific/create-codec-specific-data.js +36 -0
- package/dist/create/iso-base-media/codec-specific/mp4a.d.ts +2 -0
- package/dist/create/iso-base-media/codec-specific/mp4a.js +74 -0
- package/dist/create/iso-base-media/create-colr.d.ts +6 -0
- package/dist/create/iso-base-media/create-colr.js +26 -0
- package/dist/create/iso-base-media/create-ftyp.d.ts +10 -0
- package/dist/create/iso-base-media/create-ftyp.js +22 -0
- package/dist/create/iso-base-media/create-ilst.d.ts +1 -0
- package/dist/create/iso-base-media/create-ilst.js +14 -0
- package/dist/create/iso-base-media/create-iso-base-media.d.ts +2 -0
- package/dist/create/iso-base-media/create-iso-base-media.js +184 -0
- package/dist/create/iso-base-media/create-mdia.d.ts +5 -0
- package/dist/create/iso-base-media/create-mdia.js +18 -0
- package/dist/create/iso-base-media/create-moov.d.ts +5 -0
- package/dist/create/iso-base-media/create-moov.js +18 -0
- package/dist/create/iso-base-media/create-mvhd.d.ts +10 -0
- package/dist/create/iso-base-media/create-mvhd.js +48 -0
- package/dist/create/iso-base-media/create-trak.d.ts +4 -0
- package/dist/create/iso-base-media/create-trak.js +17 -0
- package/dist/create/iso-base-media/create-udta.d.ts +1 -0
- package/dist/create/iso-base-media/create-udta.js +14 -0
- package/dist/create/iso-base-media/create-url.d.ts +1 -0
- package/dist/create/iso-base-media/create-url.js +16 -0
- package/dist/create/iso-base-media/example-stts.d.ts +3 -0
- package/dist/create/iso-base-media/example-stts.js +2797 -0
- package/dist/create/iso-base-media/ilst/create-cmt.d.ts +1 -0
- package/dist/create/iso-base-media/ilst/create-cmt.js +26 -0
- package/dist/create/iso-base-media/ilst/create-too.d.ts +1 -0
- package/dist/create/iso-base-media/ilst/create-too.js +27 -0
- package/dist/create/iso-base-media/mdia/create-mdhd.d.ts +6 -0
- package/dist/create/iso-base-media/mdia/create-mdhd.js +33 -0
- package/dist/create/iso-base-media/mp4-header.d.ts +6 -0
- package/dist/create/iso-base-media/mp4-header.js +48 -0
- package/dist/create/iso-base-media/primitives.d.ts +26 -0
- package/dist/create/iso-base-media/primitives.js +133 -0
- package/dist/create/iso-base-media/serialize-track.d.ts +9 -0
- package/dist/create/iso-base-media/serialize-track.js +63 -0
- package/dist/create/iso-base-media/trak/create-tkhd.d.ts +27 -0
- package/dist/create/iso-base-media/trak/create-tkhd.js +97 -0
- package/dist/create/iso-base-media/trak/mdia/create-minf.d.ts +4 -0
- package/dist/create/iso-base-media/trak/mdia/create-minf.js +19 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-dinf.d.ts +1 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-dinf.js +22 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-smhd.d.ts +1 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-smhd.js +20 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-stbl.d.ts +6 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-stbl.js +41 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-vmhd.d.ts +1 -0
- package/dist/create/iso-base-media/trak/mdia/minf/create-vmhd.js +20 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-ctts.d.ts +2 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-ctts.js +45 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stco.d.ts +2 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stco.js +28 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stsc.d.ts +2 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stsc.js +56 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stss.d.ts +2 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stss.js +23 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stsz.d.ts +2 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stsz.js +25 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stts.d.ts +2 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stts.js +51 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avc1.d.ts +1 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avc1.js +20 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avcc.d.ts +1 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avcc.js +16 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-pasp.d.ts +1 -0
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-pasp.js +13 -0
- package/dist/create/iso-base-media/udta/create-meta.d.ts +4 -0
- package/dist/create/iso-base-media/udta/create-meta.js +20 -0
- package/dist/create/iso-base-media/udta/meta/create-hdlr.d.ts +1 -0
- package/dist/create/iso-base-media/udta/meta/create-hdlr.js +32 -0
- package/dist/create/make-track-info.d.ts +20 -0
- package/dist/create/matroska/cluster-segment.d.ts +10 -0
- package/dist/create/matroska/cluster-segment.js +38 -0
- package/dist/create/matroska/cluster.d.ts +25 -0
- package/dist/create/matroska/cluster.js +76 -0
- package/dist/create/matroska/color.d.ts +2 -0
- package/dist/create/matroska/color.js +85 -0
- package/dist/create/matroska/create-matroska-media.d.ts +2 -0
- package/dist/create/matroska/create-matroska-media.js +189 -0
- package/dist/create/matroska/make-duration-with-padding.d.ts +1 -0
- package/dist/create/matroska/make-duration-with-padding.js +15 -0
- package/dist/create/matroska/matroska-cues.d.ts +6 -0
- package/dist/create/matroska/matroska-cues.js +49 -0
- package/dist/create/matroska/matroska-header.d.ts +1 -0
- package/dist/create/matroska/matroska-header.js +66 -0
- package/dist/create/matroska/matroska-info.d.ts +3 -0
- package/dist/create/matroska/matroska-info.js +33 -0
- package/dist/create/matroska/matroska-seek.d.ts +6 -0
- package/dist/create/matroska/matroska-seek.js +32 -0
- package/dist/create/matroska/matroska-segment.d.ts +3 -0
- package/dist/create/matroska/matroska-segment.js +13 -0
- package/dist/create/matroska/matroska-trackentry.d.ts +10 -0
- package/dist/create/matroska/matroska-trackentry.js +249 -0
- package/dist/create/matroska/matroska-utils.d.ts +30 -0
- package/dist/create/matroska/matroska-utils.js +292 -0
- package/dist/create/media-fn.d.ts +32 -0
- package/dist/create/progress-tracker.d.ts +9 -0
- package/dist/create/progress-tracker.js +67 -0
- package/dist/create/timescale.d.ts +1 -0
- package/dist/create/timescale.js +4 -0
- package/dist/create/wav/create-wav.d.ts +2 -0
- package/dist/create/wav/create-wav.js +110 -0
- package/dist/create/with-resolvers.d.ts +10 -0
- package/dist/create/with-resolvers.js +28 -0
- package/dist/esm/buffer.mjs +74 -0
- package/dist/esm/index.mjs +2518 -40
- package/dist/esm/web-fs.mjs +92 -0
- package/dist/from-unix-timestamp.d.ts +1 -0
- package/dist/from-unix-timestamp.js +11 -0
- package/dist/index.d.ts +1 -0
- package/dist/io-manager/io-synchronizer.d.ts +1 -1
- package/dist/io-manager/io-synchronizer.js +5 -4
- package/dist/io-manager/make-timeout-promise.js +2 -2
- package/dist/on-audio-track.d.ts +3 -1
- package/dist/on-video-track.d.ts +3 -1
- package/dist/select-container-creator.d.ts +1 -1
- package/dist/select-container-creator.js +6 -4
- package/dist/test/avc1.test.d.ts +1 -0
- package/dist/test/avc1.test.js +39 -0
- package/dist/test/avcc.test.d.ts +1 -0
- package/dist/test/avcc.test.js +15 -0
- package/dist/test/cmt.test.d.ts +1 -0
- package/dist/test/cmt.test.js +13 -0
- package/dist/test/colr.test.d.ts +1 -0
- package/dist/test/colr.test.js +16 -0
- package/dist/test/create-ftyp.test.d.ts +1 -0
- package/dist/test/create-ftyp.test.js +47 -0
- package/dist/test/create-matroska.test.d.ts +1 -0
- package/dist/test/create-matroska.test.js +101 -0
- package/dist/test/create-mvhd.test.d.ts +1 -0
- package/dist/test/create-mvhd.test.js +108 -0
- package/dist/test/ctts.test.d.ts +1 -0
- package/dist/test/ctts.test.js +49 -0
- package/dist/test/dinf.test.d.ts +1 -0
- package/dist/test/dinf.test.js +12 -0
- package/dist/test/ilst.test.d.ts +1 -0
- package/dist/test/ilst.test.js +22 -0
- package/dist/test/mdhd.test.d.ts +1 -0
- package/dist/test/mdhd.test.js +17 -0
- package/dist/test/meta.test.d.ts +1 -0
- package/dist/test/meta.test.js +26 -0
- package/dist/test/mp4a.test.d.ts +1 -0
- package/dist/test/mp4a.test.js +24 -0
- package/dist/test/pasp.test.d.ts +1 -0
- package/dist/test/pasp.test.js +12 -0
- package/dist/test/stbl.test.js +166 -0
- package/dist/test/stco.test.d.ts +1 -0
- package/dist/test/stco.test.js +34 -0
- package/dist/test/stsc.test.d.ts +1 -0
- package/dist/test/stsc.test.js +63 -0
- package/dist/test/stsd.test.d.ts +1 -0
- package/dist/test/stsd.test.js +264 -0
- package/dist/test/stss.test.d.ts +1 -0
- package/dist/test/stss.test.js +14 -0
- package/dist/test/stsz.test.d.ts +1 -0
- package/dist/test/stsz.test.js +43 -0
- package/dist/test/stts.test.d.ts +1 -0
- package/dist/test/stts.test.js +12 -0
- package/dist/test/tkhd.test.d.ts +1 -0
- package/dist/test/tkhd.test.js +175 -0
- package/dist/test/too.test.d.ts +1 -0
- package/dist/test/too.test.js +12 -0
- package/dist/test/url.test.d.ts +1 -0
- package/dist/test/url.test.js +11 -0
- package/dist/truthy.d.ts +3 -0
- package/dist/truthy.js +6 -0
- package/dist/video-decoder.d.ts +2 -1
- package/dist/video-encoder.d.ts +2 -1
- package/dist/writers/buffer-implementation/writer.d.ts +2 -0
- package/dist/writers/buffer-implementation/writer.js +54 -0
- package/dist/writers/buffer.d.ts +2 -0
- package/dist/writers/buffer.js +7 -0
- package/dist/writers/web-fs.d.ts +3 -0
- package/dist/writers/web-fs.js +75 -0
- package/dist/writers/writer.d.ts +15 -0
- package/package.json +36 -5
- package/dist/get-operation-id.js +0 -1
- package/dist/resizing/resizing.d.ts +0 -13
- package/dist/resizing.d.ts +0 -13
- package/dist/rotate-video-frame.d.ts +0 -9
- package/dist/rotate-video-frame.js +0 -53
- package/dist/scaling.d.ts +0 -13
- /package/dist/{resizing.js → create/make-track-info.js} +0 -0
- /package/dist/{resizing/resizing.js → create/media-fn.js} +0 -0
- /package/dist/{get-operation-id.d.ts → test/stbl.test.d.ts} +0 -0
- /package/dist/{scaling.js → writers/writer.js} +0 -0
package/dist/esm/index.mjs
CHANGED
|
@@ -92,6 +92,131 @@ var require_dist = __commonJS((exports) => {
|
|
|
92
92
|
} });
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
+
// src/writers/web-fs.ts
|
|
96
|
+
var createContent = async ({ filename }) => {
|
|
97
|
+
const directoryHandle = await navigator.storage.getDirectory();
|
|
98
|
+
const actualFilename = `__remotion_mediaparser:${filename}`;
|
|
99
|
+
const remove = async () => {
|
|
100
|
+
await directoryHandle.removeEntry(actualFilename, {
|
|
101
|
+
recursive: true
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
await remove();
|
|
105
|
+
const fileHandle = await directoryHandle.getFileHandle(actualFilename, {
|
|
106
|
+
create: true
|
|
107
|
+
});
|
|
108
|
+
const writable = await fileHandle.createWritable();
|
|
109
|
+
let written = 0;
|
|
110
|
+
let writPromise = Promise.resolve();
|
|
111
|
+
const write = async (arr) => {
|
|
112
|
+
await writable.write(arr);
|
|
113
|
+
written += arr.byteLength;
|
|
114
|
+
};
|
|
115
|
+
const updateDataAt = async (position, data) => {
|
|
116
|
+
await writable.seek(position);
|
|
117
|
+
await writable.write(data);
|
|
118
|
+
await writable.seek(written);
|
|
119
|
+
};
|
|
120
|
+
const writer = {
|
|
121
|
+
write: (arr) => {
|
|
122
|
+
writPromise = writPromise.then(() => write(arr));
|
|
123
|
+
return writPromise;
|
|
124
|
+
},
|
|
125
|
+
save: async () => {
|
|
126
|
+
try {
|
|
127
|
+
await writable.close();
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
const newHandle = await directoryHandle.getFileHandle(actualFilename, {
|
|
131
|
+
create: true
|
|
132
|
+
});
|
|
133
|
+
const newFile = await newHandle.getFile();
|
|
134
|
+
return newFile;
|
|
135
|
+
},
|
|
136
|
+
getWrittenByteCount: () => written,
|
|
137
|
+
updateDataAt: (position, data) => {
|
|
138
|
+
writPromise = writPromise.then(() => updateDataAt(position, data));
|
|
139
|
+
return writPromise;
|
|
140
|
+
},
|
|
141
|
+
waitForFinish: async () => {
|
|
142
|
+
await writPromise;
|
|
143
|
+
},
|
|
144
|
+
remove
|
|
145
|
+
};
|
|
146
|
+
return writer;
|
|
147
|
+
};
|
|
148
|
+
var webFsWriter = {
|
|
149
|
+
createContent
|
|
150
|
+
};
|
|
151
|
+
var canUseWebFsWriter = async () => {
|
|
152
|
+
if (!("storage" in navigator)) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
if (!("getDirectory" in navigator.storage)) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const directoryHandle = await navigator.storage.getDirectory();
|
|
159
|
+
const fileHandle = await directoryHandle.getFileHandle("remotion-probe-web-fs-support", {
|
|
160
|
+
create: true
|
|
161
|
+
});
|
|
162
|
+
const canUse = fileHandle.createWritable !== undefined;
|
|
163
|
+
return canUse;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// src/writers/buffer-implementation/writer.ts
|
|
167
|
+
var createContent2 = ({ filename, mimeType }) => {
|
|
168
|
+
const buf = new ArrayBuffer(0, {
|
|
169
|
+
maxByteLength: 2000000000
|
|
170
|
+
});
|
|
171
|
+
if (!buf.resize) {
|
|
172
|
+
throw new Error("Could not create buffer writer");
|
|
173
|
+
}
|
|
174
|
+
const write = (newData) => {
|
|
175
|
+
const oldLength = buf.byteLength;
|
|
176
|
+
const newLength = oldLength + newData.byteLength;
|
|
177
|
+
buf.resize(newLength);
|
|
178
|
+
const newArray = new Uint8Array(buf);
|
|
179
|
+
newArray.set(newData, oldLength);
|
|
180
|
+
};
|
|
181
|
+
const updateDataAt = (position, newData) => {
|
|
182
|
+
const newArray = new Uint8Array(buf);
|
|
183
|
+
newArray.set(newData, position);
|
|
184
|
+
};
|
|
185
|
+
let writPromise = Promise.resolve();
|
|
186
|
+
let removed = false;
|
|
187
|
+
const writer = {
|
|
188
|
+
write: (arr) => {
|
|
189
|
+
writPromise = writPromise.then(() => write(arr));
|
|
190
|
+
return writPromise;
|
|
191
|
+
},
|
|
192
|
+
save: () => {
|
|
193
|
+
if (removed) {
|
|
194
|
+
return Promise.reject(new Error("Already called .remove() on the result"));
|
|
195
|
+
}
|
|
196
|
+
const arr = new Uint8Array(buf);
|
|
197
|
+
return Promise.resolve(new File([arr.slice()], filename, { type: mimeType }));
|
|
198
|
+
},
|
|
199
|
+
remove() {
|
|
200
|
+
removed = true;
|
|
201
|
+
return Promise.resolve();
|
|
202
|
+
},
|
|
203
|
+
getWrittenByteCount: () => buf.byteLength,
|
|
204
|
+
updateDataAt: (position, newData) => {
|
|
205
|
+
writPromise = writPromise.then(() => updateDataAt(position, newData));
|
|
206
|
+
return writPromise;
|
|
207
|
+
},
|
|
208
|
+
waitForFinish: async () => {
|
|
209
|
+
await writPromise;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
return Promise.resolve(writer);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/writers/buffer.ts
|
|
216
|
+
var bufferWriter = {
|
|
217
|
+
createContent: createContent2
|
|
218
|
+
};
|
|
219
|
+
|
|
95
220
|
// src/resizing/calculate-new-size.ts
|
|
96
221
|
var ensureMultipleOfTwo = ({
|
|
97
222
|
dimensions,
|
|
@@ -325,17 +450,59 @@ var getWaveAudioDecoder = ({
|
|
|
325
450
|
};
|
|
326
451
|
};
|
|
327
452
|
|
|
328
|
-
// src/
|
|
329
|
-
|
|
453
|
+
// src/create/event-emitter.ts
|
|
454
|
+
class IoEventEmitter {
|
|
455
|
+
listeners = {
|
|
456
|
+
input: [],
|
|
457
|
+
output: [],
|
|
458
|
+
processed: [],
|
|
459
|
+
progress: []
|
|
460
|
+
};
|
|
461
|
+
addEventListener(name, callback) {
|
|
462
|
+
this.listeners[name].push(callback);
|
|
463
|
+
}
|
|
464
|
+
removeEventListener(name, callback) {
|
|
465
|
+
this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
|
|
466
|
+
}
|
|
467
|
+
dispatchEvent(dispatchName, context) {
|
|
468
|
+
this.listeners[dispatchName].forEach((callback) => {
|
|
469
|
+
callback({ detail: context });
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/create/with-resolvers.ts
|
|
475
|
+
var withResolvers = function() {
|
|
476
|
+
let resolve;
|
|
477
|
+
let reject;
|
|
478
|
+
const promise = new Promise((res, rej) => {
|
|
479
|
+
resolve = res;
|
|
480
|
+
reject = rej;
|
|
481
|
+
});
|
|
482
|
+
return { promise, resolve, reject };
|
|
483
|
+
};
|
|
484
|
+
var withResolversAndWaitForReturn = () => {
|
|
485
|
+
const { promise, reject, resolve } = withResolvers();
|
|
486
|
+
const { promise: returnPromise, resolve: resolveReturn } = withResolvers();
|
|
487
|
+
return {
|
|
488
|
+
getPromiseToImmediatelyReturn: () => {
|
|
489
|
+
resolveReturn(undefined);
|
|
490
|
+
return promise;
|
|
491
|
+
},
|
|
492
|
+
reject: (reason) => {
|
|
493
|
+
returnPromise.then(() => reject(reason));
|
|
494
|
+
},
|
|
495
|
+
resolve
|
|
496
|
+
};
|
|
497
|
+
};
|
|
330
498
|
|
|
331
499
|
// src/log.ts
|
|
332
500
|
import { MediaParserInternals } from "@remotion/media-parser";
|
|
333
501
|
var { Log } = MediaParserInternals;
|
|
334
502
|
|
|
335
503
|
// src/io-manager/make-timeout-promise.ts
|
|
336
|
-
import { MediaParserInternals as MediaParserInternals2 } from "@remotion/media-parser";
|
|
337
504
|
var makeTimeoutPromise = (label, ms) => {
|
|
338
|
-
const { promise, reject, resolve } =
|
|
505
|
+
const { promise, reject, resolve } = withResolvers();
|
|
339
506
|
const timeout = setTimeout(() => {
|
|
340
507
|
reject(new Error(`${label()} (timed out after ${ms}ms)`));
|
|
341
508
|
}, ms);
|
|
@@ -354,7 +521,7 @@ var makeIoSynchronizer = ({
|
|
|
354
521
|
label,
|
|
355
522
|
progress
|
|
356
523
|
}) => {
|
|
357
|
-
const eventEmitter = new
|
|
524
|
+
const eventEmitter = new IoEventEmitter;
|
|
358
525
|
let lastInput = 0;
|
|
359
526
|
let lastInputKeyframe = 0;
|
|
360
527
|
let lastOutput = 0;
|
|
@@ -398,7 +565,7 @@ var makeIoSynchronizer = ({
|
|
|
398
565
|
printState("Got output");
|
|
399
566
|
};
|
|
400
567
|
const waitForOutput = () => {
|
|
401
|
-
const { promise, resolve } =
|
|
568
|
+
const { promise, resolve } = withResolvers();
|
|
402
569
|
const on = () => {
|
|
403
570
|
eventEmitter.removeEventListener("output", on);
|
|
404
571
|
resolve();
|
|
@@ -407,7 +574,7 @@ var makeIoSynchronizer = ({
|
|
|
407
574
|
return promise;
|
|
408
575
|
};
|
|
409
576
|
const waitForProcessed = () => {
|
|
410
|
-
const { promise, resolve } =
|
|
577
|
+
const { promise, resolve } = withResolvers();
|
|
411
578
|
const on = () => {
|
|
412
579
|
eventEmitter.removeEventListener("processed", on);
|
|
413
580
|
resolve();
|
|
@@ -927,17 +1094,9 @@ var canReencodeVideoTrack = async ({
|
|
|
927
1094
|
return Boolean(videoDecoderConfig && videoEncoderConfig);
|
|
928
1095
|
};
|
|
929
1096
|
// src/convert-media.ts
|
|
930
|
-
import {
|
|
931
|
-
MediaParserInternals as MediaParserInternals9,
|
|
932
|
-
parseMedia
|
|
933
|
-
} from "@remotion/media-parser";
|
|
1097
|
+
import { parseMedia } from "@remotion/media-parser";
|
|
934
1098
|
|
|
935
1099
|
// src/auto-select-writer.ts
|
|
936
|
-
import { canUseWebFsWriter, webFsWriter } from "@remotion/media-parser/web-fs";
|
|
937
|
-
import {
|
|
938
|
-
MediaParserInternals as MediaParserInternals4
|
|
939
|
-
} from "@remotion/media-parser";
|
|
940
|
-
import { bufferWriter } from "@remotion/media-parser/buffer";
|
|
941
1100
|
var autoSelectWriter = async (writer, logLevel) => {
|
|
942
1101
|
if (writer) {
|
|
943
1102
|
Log.verbose(logLevel, "Using writer provided by user");
|
|
@@ -950,11 +1109,7 @@ var autoSelectWriter = async (writer, logLevel) => {
|
|
|
950
1109
|
return bufferWriter;
|
|
951
1110
|
}
|
|
952
1111
|
try {
|
|
953
|
-
const {
|
|
954
|
-
promise: timeout,
|
|
955
|
-
reject,
|
|
956
|
-
resolve
|
|
957
|
-
} = MediaParserInternals4.withResolvers();
|
|
1112
|
+
const { promise: timeout, reject, resolve } = withResolvers();
|
|
958
1113
|
const time = setTimeout(() => reject(new Error("WebFS check timeout")), 2000);
|
|
959
1114
|
const webFsSupported = await Promise.race([canUseWebFsWriter(), timeout]);
|
|
960
1115
|
resolve();
|
|
@@ -981,6 +1136,64 @@ var calculateProgress = ({
|
|
|
981
1136
|
return millisecondsWritten / expectedOutputDurationInMs;
|
|
982
1137
|
};
|
|
983
1138
|
|
|
1139
|
+
// src/create/progress-tracker.ts
|
|
1140
|
+
var makeProgressTracker = () => {
|
|
1141
|
+
const trackNumberProgresses = {};
|
|
1142
|
+
const eventEmitter = new IoEventEmitter;
|
|
1143
|
+
let startingTimestamp = null;
|
|
1144
|
+
const setPossibleLowestTimestamp = (timestamp) => {
|
|
1145
|
+
if (startingTimestamp === null) {
|
|
1146
|
+
startingTimestamp = timestamp;
|
|
1147
|
+
} else {
|
|
1148
|
+
startingTimestamp = Math.min(startingTimestamp, timestamp);
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
const getStartingTimestamp = () => {
|
|
1152
|
+
if (startingTimestamp === null) {
|
|
1153
|
+
throw new Error("No starting timestamp");
|
|
1154
|
+
}
|
|
1155
|
+
return startingTimestamp;
|
|
1156
|
+
};
|
|
1157
|
+
const calculateSmallestProgress = () => {
|
|
1158
|
+
const progressValues = Object.values(trackNumberProgresses).map((p) => {
|
|
1159
|
+
if (p !== null) {
|
|
1160
|
+
return p;
|
|
1161
|
+
}
|
|
1162
|
+
if (startingTimestamp === null) {
|
|
1163
|
+
throw new Error("No progress values to calculate smallest progress from");
|
|
1164
|
+
}
|
|
1165
|
+
return startingTimestamp;
|
|
1166
|
+
});
|
|
1167
|
+
return Math.min(...progressValues);
|
|
1168
|
+
};
|
|
1169
|
+
return {
|
|
1170
|
+
registerTrack: (trackNumber) => {
|
|
1171
|
+
trackNumberProgresses[trackNumber] = null;
|
|
1172
|
+
},
|
|
1173
|
+
getSmallestProgress: calculateSmallestProgress,
|
|
1174
|
+
updateTrackProgress: (trackNumber, progress) => {
|
|
1175
|
+
if (trackNumberProgresses[trackNumber] === undefined) {
|
|
1176
|
+
throw new Error(`Tried to update progress for a track that was not registered: ${trackNumber}`);
|
|
1177
|
+
}
|
|
1178
|
+
trackNumberProgresses[trackNumber] = progress;
|
|
1179
|
+
eventEmitter.dispatchEvent("progress", {
|
|
1180
|
+
smallestProgress: calculateSmallestProgress()
|
|
1181
|
+
});
|
|
1182
|
+
},
|
|
1183
|
+
waitForProgress: () => {
|
|
1184
|
+
const { promise, resolve } = withResolvers();
|
|
1185
|
+
const on = () => {
|
|
1186
|
+
eventEmitter.removeEventListener("progress", on);
|
|
1187
|
+
resolve();
|
|
1188
|
+
};
|
|
1189
|
+
eventEmitter.addEventListener("progress", on);
|
|
1190
|
+
return promise;
|
|
1191
|
+
},
|
|
1192
|
+
getStartingTimestamp,
|
|
1193
|
+
setPossibleLowestTimestamp
|
|
1194
|
+
};
|
|
1195
|
+
};
|
|
1196
|
+
|
|
984
1197
|
// src/error-cause.ts
|
|
985
1198
|
var error_cause_default = Error;
|
|
986
1199
|
|
|
@@ -994,7 +1207,7 @@ var generateOutputFilename = (source, container) => {
|
|
|
994
1207
|
|
|
995
1208
|
// src/on-audio-track.ts
|
|
996
1209
|
import {
|
|
997
|
-
MediaParserInternals as
|
|
1210
|
+
MediaParserInternals as MediaParserInternals3
|
|
998
1211
|
} from "@remotion/media-parser";
|
|
999
1212
|
|
|
1000
1213
|
// src/convert-encoded-chunk.ts
|
|
@@ -1015,7 +1228,7 @@ var convertEncodedChunk = (chunk, trackId) => {
|
|
|
1015
1228
|
};
|
|
1016
1229
|
|
|
1017
1230
|
// src/default-on-audio-track-handler.ts
|
|
1018
|
-
import { MediaParserInternals as
|
|
1231
|
+
import { MediaParserInternals as MediaParserInternals2 } from "@remotion/media-parser";
|
|
1019
1232
|
var DEFAULT_BITRATE = 128000;
|
|
1020
1233
|
var defaultOnAudioTrackHandler = async ({
|
|
1021
1234
|
track,
|
|
@@ -1025,11 +1238,11 @@ var defaultOnAudioTrackHandler = async ({
|
|
|
1025
1238
|
}) => {
|
|
1026
1239
|
const bitrate = DEFAULT_BITRATE;
|
|
1027
1240
|
if (canCopyTrack) {
|
|
1028
|
-
|
|
1241
|
+
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can copy track, therefore copying`);
|
|
1029
1242
|
return Promise.resolve({ type: "copy" });
|
|
1030
1243
|
}
|
|
1031
1244
|
if (defaultAudioCodec === null) {
|
|
1032
|
-
|
|
1245
|
+
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Container does not support audio, dropping audio`);
|
|
1033
1246
|
return Promise.resolve({ type: "drop" });
|
|
1034
1247
|
}
|
|
1035
1248
|
const canReencode = await canReencodeAudioTrack({
|
|
@@ -1038,14 +1251,14 @@ var defaultOnAudioTrackHandler = async ({
|
|
|
1038
1251
|
bitrate
|
|
1039
1252
|
});
|
|
1040
1253
|
if (canReencode) {
|
|
1041
|
-
|
|
1254
|
+
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
|
|
1042
1255
|
return Promise.resolve({
|
|
1043
1256
|
type: "reencode",
|
|
1044
1257
|
bitrate,
|
|
1045
1258
|
audioCodec: defaultAudioCodec
|
|
1046
1259
|
});
|
|
1047
1260
|
}
|
|
1048
|
-
|
|
1261
|
+
MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
|
|
1049
1262
|
return Promise.resolve({ type: "fail" });
|
|
1050
1263
|
};
|
|
1051
1264
|
|
|
@@ -1141,7 +1354,7 @@ var makeAudioTrackHandler = ({
|
|
|
1141
1354
|
abortConversion(new error_cause_default(`Could not configure audio decoder of track ${track.trackId}`));
|
|
1142
1355
|
return null;
|
|
1143
1356
|
}
|
|
1144
|
-
const codecPrivate = audioOperation.audioCodec === "aac" ?
|
|
1357
|
+
const codecPrivate = audioOperation.audioCodec === "aac" ? MediaParserInternals3.createAacCodecPrivate({
|
|
1145
1358
|
audioObjectType: 2,
|
|
1146
1359
|
sampleRate: track.sampleRate,
|
|
1147
1360
|
channelConfiguration: track.numberOfChannels
|
|
@@ -1222,7 +1435,7 @@ var arrayBufferToUint8Array = (buffer) => {
|
|
|
1222
1435
|
};
|
|
1223
1436
|
|
|
1224
1437
|
// src/default-on-video-track-handler.ts
|
|
1225
|
-
import { MediaParserInternals as
|
|
1438
|
+
import { MediaParserInternals as MediaParserInternals4 } from "@remotion/media-parser";
|
|
1226
1439
|
var defaultOnVideoTrackHandler = async ({
|
|
1227
1440
|
track,
|
|
1228
1441
|
defaultVideoCodec,
|
|
@@ -1232,11 +1445,11 @@ var defaultOnVideoTrackHandler = async ({
|
|
|
1232
1445
|
resizeOperation
|
|
1233
1446
|
}) => {
|
|
1234
1447
|
if (canCopyTrack) {
|
|
1235
|
-
|
|
1448
|
+
MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
|
|
1236
1449
|
return Promise.resolve({ type: "copy" });
|
|
1237
1450
|
}
|
|
1238
1451
|
if (defaultVideoCodec === null) {
|
|
1239
|
-
|
|
1452
|
+
MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (video): Is audio container, therefore dropping video`);
|
|
1240
1453
|
return Promise.resolve({ type: "drop" });
|
|
1241
1454
|
}
|
|
1242
1455
|
const canReencode = await canReencodeVideoTrack({
|
|
@@ -1244,7 +1457,7 @@ var defaultOnVideoTrackHandler = async ({
|
|
|
1244
1457
|
track
|
|
1245
1458
|
});
|
|
1246
1459
|
if (canReencode) {
|
|
1247
|
-
|
|
1460
|
+
MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
|
|
1248
1461
|
return Promise.resolve({
|
|
1249
1462
|
type: "reencode",
|
|
1250
1463
|
videoCodec: defaultVideoCodec,
|
|
@@ -1252,7 +1465,7 @@ var defaultOnVideoTrackHandler = async ({
|
|
|
1252
1465
|
resize: resizeOperation
|
|
1253
1466
|
});
|
|
1254
1467
|
}
|
|
1255
|
-
|
|
1468
|
+
MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
|
|
1256
1469
|
return Promise.resolve({ type: "fail" });
|
|
1257
1470
|
};
|
|
1258
1471
|
|
|
@@ -1706,17 +1919,2282 @@ var makeVideoTrackHandler = ({
|
|
|
1706
1919
|
};
|
|
1707
1920
|
};
|
|
1708
1921
|
|
|
1709
|
-
// src/
|
|
1710
|
-
import {
|
|
1922
|
+
// src/create/iso-base-media/create-iso-base-media.ts
|
|
1923
|
+
import {
|
|
1924
|
+
MediaParserInternals as MediaParserInternals6
|
|
1925
|
+
} from "@remotion/media-parser";
|
|
1926
|
+
|
|
1927
|
+
// src/create/matroska/matroska-utils.ts
|
|
1928
|
+
import { MediaParserInternals as MediaParserInternals5 } from "@remotion/media-parser";
|
|
1929
|
+
var getIdForName = (name) => {
|
|
1930
|
+
const value = Object.entries(MediaParserInternals5.matroskaElements).find(([key]) => key === name)?.[1];
|
|
1931
|
+
if (!value) {
|
|
1932
|
+
throw new Error(`Could not find id for name ${name}`);
|
|
1933
|
+
}
|
|
1934
|
+
return value;
|
|
1935
|
+
};
|
|
1936
|
+
function putUintDynamic(number, minimumLength) {
|
|
1937
|
+
if (number < 0) {
|
|
1938
|
+
throw new Error("This function is designed for non-negative integers only.");
|
|
1939
|
+
}
|
|
1940
|
+
const length = Math.max(minimumLength ?? 0, Math.ceil(Math.log2(number + 1) / 8));
|
|
1941
|
+
const bytes = new Uint8Array(length);
|
|
1942
|
+
for (let i = 0;i < length; i++) {
|
|
1943
|
+
bytes[length - 1 - i] = number >> 8 * i & 255;
|
|
1944
|
+
}
|
|
1945
|
+
return bytes;
|
|
1946
|
+
}
|
|
1947
|
+
var makeFromStructure = (fields) => {
|
|
1948
|
+
if ("bytes" in fields) {
|
|
1949
|
+
return fields;
|
|
1950
|
+
}
|
|
1951
|
+
const arrays = [];
|
|
1952
|
+
const struct = MediaParserInternals5.ebmlMap[getIdForName(fields.type)];
|
|
1953
|
+
if (struct.type === "uint8array") {
|
|
1954
|
+
return {
|
|
1955
|
+
bytes: fields.value,
|
|
1956
|
+
offsets: { offset: 0, children: [], field: fields.type }
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
if (struct.type === "children") {
|
|
1960
|
+
const children = [];
|
|
1961
|
+
let bytesWritten = 0;
|
|
1962
|
+
for (const item of fields.value) {
|
|
1963
|
+
const { bytes, offsets } = makeMatroskaBytes(item);
|
|
1964
|
+
arrays.push(bytes);
|
|
1965
|
+
children.push(incrementOffsetAndChildren(offsets, bytesWritten));
|
|
1966
|
+
bytesWritten += bytes.byteLength;
|
|
1967
|
+
}
|
|
1968
|
+
return {
|
|
1969
|
+
bytes: combineUint8Arrays(arrays),
|
|
1970
|
+
offsets: { offset: 0, children, field: fields.type }
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
if (struct.type === "string") {
|
|
1974
|
+
return {
|
|
1975
|
+
bytes: new TextEncoder().encode(fields.value),
|
|
1976
|
+
offsets: {
|
|
1977
|
+
children: [],
|
|
1978
|
+
offset: 0,
|
|
1979
|
+
field: fields.type
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
if (struct.type === "uint") {
|
|
1984
|
+
return {
|
|
1985
|
+
bytes: putUintDynamic(fields.value.value, fields.value.byteLength),
|
|
1986
|
+
offsets: {
|
|
1987
|
+
children: [],
|
|
1988
|
+
offset: 0,
|
|
1989
|
+
field: fields.type
|
|
1990
|
+
}
|
|
1991
|
+
};
|
|
1992
|
+
}
|
|
1993
|
+
if (struct.type === "hex-string") {
|
|
1994
|
+
const hex = fields.value.substring(2);
|
|
1995
|
+
const arr = new Uint8Array(hex.length / 2);
|
|
1996
|
+
for (let i = 0;i < hex.length; i += 2) {
|
|
1997
|
+
const byte = parseInt(hex.substring(i, i + 2), 16);
|
|
1998
|
+
arr[i / 2] = byte;
|
|
1999
|
+
}
|
|
2000
|
+
return {
|
|
2001
|
+
bytes: arr,
|
|
2002
|
+
offsets: {
|
|
2003
|
+
children: [],
|
|
2004
|
+
offset: 0,
|
|
2005
|
+
field: fields.type
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
}
|
|
2009
|
+
if (struct.type === "float") {
|
|
2010
|
+
const value = fields.value;
|
|
2011
|
+
if (value.size === "32") {
|
|
2012
|
+
const dataView = new DataView(new ArrayBuffer(4));
|
|
2013
|
+
dataView.setFloat32(0, value.value);
|
|
2014
|
+
return {
|
|
2015
|
+
bytes: new Uint8Array(dataView.buffer),
|
|
2016
|
+
offsets: {
|
|
2017
|
+
children: [],
|
|
2018
|
+
offset: 0,
|
|
2019
|
+
field: fields.type
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
const dataView2 = new DataView(new ArrayBuffer(8));
|
|
2024
|
+
dataView2.setFloat64(0, value.value);
|
|
2025
|
+
return {
|
|
2026
|
+
bytes: new Uint8Array(dataView2.buffer),
|
|
2027
|
+
offsets: {
|
|
2028
|
+
children: [],
|
|
2029
|
+
offset: 0,
|
|
2030
|
+
field: fields.type
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
throw new Error("Unexpected type");
|
|
2035
|
+
};
|
|
2036
|
+
var combineUint8Arrays = (arrays) => {
|
|
2037
|
+
if (arrays.length === 0) {
|
|
2038
|
+
return new Uint8Array([]);
|
|
2039
|
+
}
|
|
2040
|
+
if (arrays.length === 1) {
|
|
2041
|
+
return arrays[0];
|
|
2042
|
+
}
|
|
2043
|
+
let totalLength = 0;
|
|
2044
|
+
for (const array of arrays) {
|
|
2045
|
+
totalLength += array.length;
|
|
2046
|
+
}
|
|
2047
|
+
const result = new Uint8Array(totalLength);
|
|
2048
|
+
let offset = 0;
|
|
2049
|
+
for (const array of arrays) {
|
|
2050
|
+
result.set(array, offset);
|
|
2051
|
+
offset += array.length;
|
|
2052
|
+
}
|
|
2053
|
+
return result;
|
|
2054
|
+
};
|
|
2055
|
+
var incrementOffsetAndChildren = (offset, increment) => {
|
|
2056
|
+
return {
|
|
2057
|
+
offset: offset.offset + increment,
|
|
2058
|
+
children: offset.children.map((c) => incrementOffsetAndChildren(c, increment)),
|
|
2059
|
+
field: offset.field
|
|
2060
|
+
};
|
|
2061
|
+
};
|
|
2062
|
+
var matroskaToHex = (matrId) => {
|
|
2063
|
+
const numbers = new Uint8Array((matrId.length - 2) / 2);
|
|
2064
|
+
for (let i = 2;i < matrId.length; i += 2) {
|
|
2065
|
+
const hex = matrId.substring(i, i + 2);
|
|
2066
|
+
numbers[(i - 2) / 2] = parseInt(hex, 16);
|
|
2067
|
+
}
|
|
2068
|
+
return numbers;
|
|
2069
|
+
};
|
|
2070
|
+
var measureEBMLVarInt = (value) => {
|
|
2071
|
+
if (value < (1 << 7) - 1) {
|
|
2072
|
+
return 1;
|
|
2073
|
+
}
|
|
2074
|
+
if (value < (1 << 14) - 1) {
|
|
2075
|
+
return 2;
|
|
2076
|
+
}
|
|
2077
|
+
if (value < (1 << 21) - 1) {
|
|
2078
|
+
return 3;
|
|
2079
|
+
}
|
|
2080
|
+
if (value < (1 << 28) - 1) {
|
|
2081
|
+
return 4;
|
|
2082
|
+
}
|
|
2083
|
+
if (value < 2 ** 35 - 1) {
|
|
2084
|
+
return 5;
|
|
2085
|
+
}
|
|
2086
|
+
if (value < 2 ** 42 - 1) {
|
|
2087
|
+
return 6;
|
|
2088
|
+
}
|
|
2089
|
+
throw new Error("EBML VINT size not supported " + value);
|
|
2090
|
+
};
|
|
2091
|
+
var getVariableInt = (value, minWidth) => {
|
|
2092
|
+
const width = Math.max(measureEBMLVarInt(value), minWidth ?? 0);
|
|
2093
|
+
switch (width) {
|
|
2094
|
+
case 1:
|
|
2095
|
+
return new Uint8Array([1 << 7 | value]);
|
|
2096
|
+
case 2:
|
|
2097
|
+
return new Uint8Array([1 << 6 | value >> 8, value]);
|
|
2098
|
+
case 3:
|
|
2099
|
+
return new Uint8Array([1 << 5 | value >> 16, value >> 8, value]);
|
|
2100
|
+
case 4:
|
|
2101
|
+
return new Uint8Array([
|
|
2102
|
+
1 << 4 | value >> 24,
|
|
2103
|
+
value >> 16,
|
|
2104
|
+
value >> 8,
|
|
2105
|
+
value
|
|
2106
|
+
]);
|
|
2107
|
+
case 5:
|
|
2108
|
+
return new Uint8Array([
|
|
2109
|
+
1 << 3 | value / 2 ** 32 & 7,
|
|
2110
|
+
value >> 24,
|
|
2111
|
+
value >> 16,
|
|
2112
|
+
value >> 8,
|
|
2113
|
+
value
|
|
2114
|
+
]);
|
|
2115
|
+
case 6:
|
|
2116
|
+
return new Uint8Array([
|
|
2117
|
+
1 << 2 | value / 2 ** 40 & 3,
|
|
2118
|
+
value / 2 ** 32 | 0,
|
|
2119
|
+
value >> 24,
|
|
2120
|
+
value >> 16,
|
|
2121
|
+
value >> 8,
|
|
2122
|
+
value
|
|
2123
|
+
]);
|
|
2124
|
+
case 7:
|
|
2125
|
+
return new Uint8Array([
|
|
2126
|
+
1 << 1 | value / 2 ** 48 & 1,
|
|
2127
|
+
value / 2 ** 40 | 0,
|
|
2128
|
+
value / 2 ** 32 | 0,
|
|
2129
|
+
value >> 24,
|
|
2130
|
+
value >> 16,
|
|
2131
|
+
value >> 8,
|
|
2132
|
+
value
|
|
2133
|
+
]);
|
|
2134
|
+
case 8:
|
|
2135
|
+
return new Uint8Array([
|
|
2136
|
+
1 << 0 | value / 2 ** 56 & 1,
|
|
2137
|
+
value / 2 ** 48 | 0,
|
|
2138
|
+
value / 2 ** 40 | 0,
|
|
2139
|
+
value / 2 ** 32 | 0,
|
|
2140
|
+
value >> 24,
|
|
2141
|
+
value >> 16,
|
|
2142
|
+
value >> 8,
|
|
2143
|
+
value
|
|
2144
|
+
]);
|
|
2145
|
+
default:
|
|
2146
|
+
throw new Error("Bad EBML VINT size " + width);
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
var makeMatroskaBytes = (fields) => {
|
|
2150
|
+
if ("bytes" in fields) {
|
|
2151
|
+
return fields;
|
|
2152
|
+
}
|
|
2153
|
+
const value = makeFromStructure(fields);
|
|
2154
|
+
const header = matroskaToHex(getIdForName(fields.type));
|
|
2155
|
+
const size = getVariableInt(value.bytes.length, fields.minVintWidth);
|
|
2156
|
+
const bytes = combineUint8Arrays([header, size, value.bytes]);
|
|
2157
|
+
return {
|
|
2158
|
+
bytes,
|
|
2159
|
+
offsets: {
|
|
2160
|
+
offset: value.offsets.offset,
|
|
2161
|
+
field: value.offsets.field,
|
|
2162
|
+
children: value.offsets.children.map((c) => {
|
|
2163
|
+
return incrementOffsetAndChildren(c, header.byteLength + size.byteLength);
|
|
2164
|
+
})
|
|
2165
|
+
}
|
|
2166
|
+
};
|
|
2167
|
+
};
|
|
2168
|
+
var padMatroskaBytes = (fields, totalLength) => {
|
|
2169
|
+
const regular = makeMatroskaBytes(fields);
|
|
2170
|
+
const paddingLength = totalLength - regular.bytes.byteLength - matroskaToHex(MediaParserInternals5.matroskaElements.Void).byteLength;
|
|
2171
|
+
if (paddingLength < 0) {
|
|
2172
|
+
throw new Error("ooops");
|
|
2173
|
+
}
|
|
2174
|
+
const padding = makeMatroskaBytes({
|
|
2175
|
+
type: "Void",
|
|
2176
|
+
value: new Uint8Array(paddingLength).fill(0),
|
|
2177
|
+
minVintWidth: null
|
|
2178
|
+
});
|
|
2179
|
+
return [
|
|
2180
|
+
regular,
|
|
2181
|
+
{
|
|
2182
|
+
bytes: padding.bytes,
|
|
2183
|
+
offsets: incrementOffsetAndChildren(padding.offsets, regular.bytes.length)
|
|
2184
|
+
}
|
|
2185
|
+
];
|
|
2186
|
+
};
|
|
2187
|
+
function serializeUint16(value) {
|
|
2188
|
+
const buffer = new ArrayBuffer(2);
|
|
2189
|
+
const view = new DataView(buffer);
|
|
2190
|
+
view.setUint16(0, value);
|
|
2191
|
+
return new Uint8Array(buffer);
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
// src/create/iso-base-media/primitives.ts
|
|
2195
|
+
var stringsToUint8Array = (str) => {
|
|
2196
|
+
return new TextEncoder().encode(str);
|
|
2197
|
+
};
|
|
2198
|
+
var numberTo32BitUIntOrInt = (num) => {
|
|
2199
|
+
return new Uint8Array([
|
|
2200
|
+
num >> 24 & 255,
|
|
2201
|
+
num >> 16 & 255,
|
|
2202
|
+
num >> 8 & 255,
|
|
2203
|
+
num & 255
|
|
2204
|
+
]);
|
|
2205
|
+
};
|
|
2206
|
+
var numberTo32BitUIntOrIntLeading128 = (num) => {
|
|
2207
|
+
const arr = [
|
|
2208
|
+
num >> 24 & 255,
|
|
2209
|
+
num >> 16 & 255,
|
|
2210
|
+
num >> 8 & 255,
|
|
2211
|
+
num & 255
|
|
2212
|
+
];
|
|
2213
|
+
for (const i in arr) {
|
|
2214
|
+
if (arr[i] === 0) {
|
|
2215
|
+
arr[i] = 128;
|
|
2216
|
+
} else {
|
|
2217
|
+
break;
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
return new Uint8Array(arr);
|
|
2221
|
+
};
|
|
2222
|
+
var numberTo16BitUIntOrInt = (num) => {
|
|
2223
|
+
return new Uint8Array([num >> 8 & 255, num & 255]);
|
|
2224
|
+
};
|
|
2225
|
+
var setFixedPointSignedOrUnsigned1616Number = (num) => {
|
|
2226
|
+
const val = Math.round(num * 2 ** 16);
|
|
2227
|
+
return numberTo32BitUIntOrInt(val);
|
|
2228
|
+
};
|
|
2229
|
+
var setFixedPointSigned230Number = (num) => {
|
|
2230
|
+
const val = Math.round(num * 2 ** 30);
|
|
2231
|
+
return numberTo32BitUIntOrInt(val);
|
|
2232
|
+
};
|
|
2233
|
+
var addSize = (arr) => {
|
|
2234
|
+
return combineUint8Arrays([numberTo32BitUIntOrInt(arr.length + 4), arr]);
|
|
2235
|
+
};
|
|
2236
|
+
var addLeading128Size = (arr) => {
|
|
2237
|
+
return combineUint8Arrays([
|
|
2238
|
+
numberTo32BitUIntOrIntLeading128(arr.length),
|
|
2239
|
+
arr
|
|
2240
|
+
]);
|
|
2241
|
+
};
|
|
2242
|
+
var floatTo16Point1632Bit = (number) => {
|
|
2243
|
+
const fixedNumber = Number(number.toFixed(2));
|
|
2244
|
+
const result = new Uint8Array(4);
|
|
2245
|
+
const tens = Math.floor(fixedNumber / 10);
|
|
2246
|
+
const ones = Math.floor(fixedNumber % 10);
|
|
2247
|
+
const tenths = Math.floor(fixedNumber * 10 % 10);
|
|
2248
|
+
const hundredths = Math.floor(fixedNumber * 100 % 10);
|
|
2249
|
+
result[0] = tens;
|
|
2250
|
+
result[1] = ones;
|
|
2251
|
+
result[2] = tenths;
|
|
2252
|
+
result[3] = hundredths;
|
|
2253
|
+
return result;
|
|
2254
|
+
};
|
|
2255
|
+
var floatTo16Point16_16Bit = (number) => {
|
|
2256
|
+
const fixedNumber = Number(number.toFixed(2));
|
|
2257
|
+
const result = new Uint8Array(2);
|
|
2258
|
+
const ones = Math.floor(fixedNumber % 10);
|
|
2259
|
+
const tenths = Math.floor(fixedNumber * 10 % 10);
|
|
2260
|
+
result[0] = ones;
|
|
2261
|
+
result[1] = tenths;
|
|
2262
|
+
return result;
|
|
2263
|
+
};
|
|
2264
|
+
var serializeMatrix = (matrix) => {
|
|
2265
|
+
return combineUint8Arrays([
|
|
2266
|
+
setFixedPointSignedOrUnsigned1616Number(matrix[0]),
|
|
2267
|
+
setFixedPointSignedOrUnsigned1616Number(matrix[1]),
|
|
2268
|
+
setFixedPointSigned230Number(matrix[2]),
|
|
2269
|
+
setFixedPointSignedOrUnsigned1616Number(matrix[3]),
|
|
2270
|
+
setFixedPointSignedOrUnsigned1616Number(matrix[4]),
|
|
2271
|
+
setFixedPointSigned230Number(matrix[5]),
|
|
2272
|
+
setFixedPointSignedOrUnsigned1616Number(matrix[6]),
|
|
2273
|
+
setFixedPointSignedOrUnsigned1616Number(matrix[7]),
|
|
2274
|
+
setFixedPointSigned230Number(matrix[8])
|
|
2275
|
+
]);
|
|
2276
|
+
};
|
|
2277
|
+
var stringToPascalString = (str) => {
|
|
2278
|
+
const buffer = new Uint8Array(32);
|
|
2279
|
+
for (let i = 0;i < Math.min(str.length, 32); i++) {
|
|
2280
|
+
buffer[i] = str.charCodeAt(i);
|
|
2281
|
+
}
|
|
2282
|
+
return buffer;
|
|
2283
|
+
};
|
|
2284
|
+
var padIsoBaseMediaBytes = (data, totalLength) => {
|
|
2285
|
+
if (data.length - 8 > totalLength) {
|
|
2286
|
+
throw new Error(`Data is longer than the total length: ${data.length - 8} > ${totalLength}`);
|
|
2287
|
+
}
|
|
2288
|
+
if (data.length - 8 === totalLength) {
|
|
2289
|
+
return data;
|
|
2290
|
+
}
|
|
2291
|
+
return combineUint8Arrays([
|
|
2292
|
+
data,
|
|
2293
|
+
addSize(combineUint8Arrays([
|
|
2294
|
+
stringsToUint8Array("free"),
|
|
2295
|
+
new Uint8Array(totalLength - (data.length - 8))
|
|
2296
|
+
]))
|
|
2297
|
+
]);
|
|
2298
|
+
};
|
|
2299
|
+
var IDENTITY_MATRIX = [1, 0, 0, 0, 1, 0, 0, 0, 1];
|
|
2300
|
+
|
|
2301
|
+
// src/create/iso-base-media/create-ftyp.ts
|
|
2302
|
+
var createFtyp = ({
|
|
2303
|
+
majorBrand,
|
|
2304
|
+
minorBrand,
|
|
2305
|
+
compatibleBrands
|
|
2306
|
+
}) => {
|
|
2307
|
+
const type = stringsToUint8Array("ftyp");
|
|
2308
|
+
const majorBrandArr = stringsToUint8Array(majorBrand);
|
|
2309
|
+
const minorBrandArr = numberTo32BitUIntOrInt(minorBrand);
|
|
2310
|
+
const compatibleBrandsArr = combineUint8Arrays(compatibleBrands.map((b) => stringsToUint8Array(b)));
|
|
2311
|
+
return addSize(combineUint8Arrays([
|
|
2312
|
+
type,
|
|
2313
|
+
majorBrandArr,
|
|
2314
|
+
minorBrandArr,
|
|
2315
|
+
compatibleBrandsArr
|
|
2316
|
+
]));
|
|
2317
|
+
};
|
|
2318
|
+
var createIsoBaseMediaFtyp = ({
|
|
2319
|
+
majorBrand,
|
|
2320
|
+
minorBrand,
|
|
2321
|
+
compatibleBrands
|
|
2322
|
+
}) => {
|
|
2323
|
+
return createFtyp({ compatibleBrands, majorBrand, minorBrand });
|
|
2324
|
+
};
|
|
2325
|
+
|
|
2326
|
+
// src/create/iso-base-media/mp4-header.ts
|
|
2327
|
+
import { VERSION as VERSION2 } from "@remotion/media-parser";
|
|
2328
|
+
|
|
2329
|
+
// src/create/iso-base-media/create-ilst.ts
|
|
2330
|
+
var createIlst = (items) => {
|
|
2331
|
+
return addSize(combineUint8Arrays([
|
|
2332
|
+
stringsToUint8Array("ilst"),
|
|
2333
|
+
...items
|
|
2334
|
+
]));
|
|
2335
|
+
};
|
|
2336
|
+
|
|
2337
|
+
// src/create/iso-base-media/create-moov.ts
|
|
2338
|
+
var createMoov = ({
|
|
2339
|
+
mvhd,
|
|
2340
|
+
traks,
|
|
2341
|
+
udta
|
|
2342
|
+
}) => {
|
|
2343
|
+
return addSize(combineUint8Arrays([
|
|
2344
|
+
stringsToUint8Array("moov"),
|
|
2345
|
+
mvhd,
|
|
2346
|
+
...traks,
|
|
2347
|
+
udta
|
|
2348
|
+
]));
|
|
2349
|
+
};
|
|
2350
|
+
|
|
2351
|
+
// src/from-unix-timestamp.ts
|
|
2352
|
+
var fromUnixTimestamp = (value) => {
|
|
2353
|
+
if (value === null) {
|
|
2354
|
+
return 0;
|
|
2355
|
+
}
|
|
2356
|
+
const baseDate = new Date("1904-01-01T00:00:00Z");
|
|
2357
|
+
return Math.floor(value / 1000 - baseDate.getTime() / 1000);
|
|
2358
|
+
};
|
|
2359
|
+
|
|
2360
|
+
// src/create/iso-base-media/create-mvhd.ts
|
|
2361
|
+
var createMvhd = ({
|
|
2362
|
+
timescale,
|
|
2363
|
+
durationInUnits,
|
|
2364
|
+
rate,
|
|
2365
|
+
volume,
|
|
2366
|
+
nextTrackId,
|
|
2367
|
+
matrix,
|
|
2368
|
+
creationTime,
|
|
2369
|
+
modificationTime
|
|
2370
|
+
}) => {
|
|
2371
|
+
if (matrix.length !== 9) {
|
|
2372
|
+
throw new Error("Matrix must be 9 elements long");
|
|
2373
|
+
}
|
|
2374
|
+
const content = combineUint8Arrays([
|
|
2375
|
+
stringsToUint8Array("mvhd"),
|
|
2376
|
+
new Uint8Array([0]),
|
|
2377
|
+
new Uint8Array([0, 0, 0]),
|
|
2378
|
+
creationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(creationTime)),
|
|
2379
|
+
modificationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(modificationTime)),
|
|
2380
|
+
numberTo32BitUIntOrInt(timescale),
|
|
2381
|
+
numberTo32BitUIntOrInt(durationInUnits),
|
|
2382
|
+
floatTo16Point1632Bit(rate),
|
|
2383
|
+
floatTo16Point16_16Bit(volume),
|
|
2384
|
+
new Uint8Array([0, 0]),
|
|
2385
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2386
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2387
|
+
serializeMatrix(matrix),
|
|
2388
|
+
combineUint8Arrays(new Array(6).fill(new Uint8Array([0, 0, 0, 0]))),
|
|
2389
|
+
numberTo32BitUIntOrInt(nextTrackId)
|
|
2390
|
+
]);
|
|
2391
|
+
return addSize(content);
|
|
2392
|
+
};
|
|
2393
|
+
|
|
2394
|
+
// src/create/iso-base-media/create-udta.ts
|
|
2395
|
+
var createUdta = (children) => {
|
|
2396
|
+
return addSize(combineUint8Arrays([
|
|
2397
|
+
stringsToUint8Array("udta"),
|
|
2398
|
+
children
|
|
2399
|
+
]));
|
|
2400
|
+
};
|
|
2401
|
+
|
|
2402
|
+
// src/create/iso-base-media/ilst/create-cmt.ts
|
|
2403
|
+
var createCmt = (comment) => {
|
|
2404
|
+
return addSize(combineUint8Arrays([
|
|
2405
|
+
new Uint8Array([169, 99, 109, 116]),
|
|
2406
|
+
addSize(combineUint8Arrays([
|
|
2407
|
+
stringsToUint8Array("data"),
|
|
2408
|
+
new Uint8Array([0, 0]),
|
|
2409
|
+
new Uint8Array([0, 1]),
|
|
2410
|
+
new Uint8Array([0, 0]),
|
|
2411
|
+
new Uint8Array([0, 0]),
|
|
2412
|
+
stringsToUint8Array(comment)
|
|
2413
|
+
]))
|
|
2414
|
+
]));
|
|
2415
|
+
};
|
|
2416
|
+
|
|
2417
|
+
// src/create/iso-base-media/ilst/create-too.ts
|
|
2418
|
+
var createToo = (value) => {
|
|
2419
|
+
return addSize(combineUint8Arrays([
|
|
2420
|
+
new Uint8Array([169, 116, 111, 111]),
|
|
2421
|
+
addSize(combineUint8Arrays([
|
|
2422
|
+
new Uint8Array([100, 97, 116, 97]),
|
|
2423
|
+
new Uint8Array([0, 0]),
|
|
2424
|
+
new Uint8Array([0, 1]),
|
|
2425
|
+
new Uint8Array([0, 0]),
|
|
2426
|
+
new Uint8Array([0, 0]),
|
|
2427
|
+
stringsToUint8Array(value)
|
|
2428
|
+
]))
|
|
2429
|
+
]));
|
|
2430
|
+
};
|
|
2431
|
+
|
|
2432
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avcc.ts
|
|
2433
|
+
var createAvccBox = (privateData) => {
|
|
2434
|
+
if (!privateData) {
|
|
2435
|
+
throw new Error("privateData is required");
|
|
2436
|
+
}
|
|
2437
|
+
return addSize(combineUint8Arrays([
|
|
2438
|
+
stringsToUint8Array("avcC"),
|
|
2439
|
+
privateData
|
|
2440
|
+
]));
|
|
2441
|
+
};
|
|
2442
|
+
|
|
2443
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-pasp.ts
|
|
2444
|
+
var createPasp = (x, y) => {
|
|
2445
|
+
return addSize(combineUint8Arrays([
|
|
2446
|
+
stringsToUint8Array("pasp"),
|
|
2447
|
+
numberTo32BitUIntOrInt(x),
|
|
2448
|
+
numberTo32BitUIntOrInt(y)
|
|
2449
|
+
]));
|
|
2450
|
+
};
|
|
2451
|
+
|
|
2452
|
+
// src/create/iso-base-media/codec-specific/avc1.ts
|
|
2453
|
+
var createAvc1Data = ({
|
|
2454
|
+
avccBox,
|
|
2455
|
+
pasp,
|
|
2456
|
+
width,
|
|
2457
|
+
height,
|
|
2458
|
+
horizontalResolution,
|
|
2459
|
+
verticalResolution,
|
|
2460
|
+
compressorName,
|
|
2461
|
+
depth
|
|
2462
|
+
}) => {
|
|
2463
|
+
return addSize(combineUint8Arrays([
|
|
2464
|
+
stringsToUint8Array("avc1"),
|
|
2465
|
+
new Uint8Array([0, 0, 0, 0, 0, 0]),
|
|
2466
|
+
new Uint8Array([0, 1]),
|
|
2467
|
+
new Uint8Array([0, 0]),
|
|
2468
|
+
new Uint8Array([0, 0]),
|
|
2469
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2470
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2471
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2472
|
+
numberTo16BitUIntOrInt(width),
|
|
2473
|
+
numberTo16BitUIntOrInt(height),
|
|
2474
|
+
setFixedPointSignedOrUnsigned1616Number(horizontalResolution),
|
|
2475
|
+
setFixedPointSignedOrUnsigned1616Number(verticalResolution),
|
|
2476
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2477
|
+
numberTo16BitUIntOrInt(1),
|
|
2478
|
+
stringToPascalString(compressorName),
|
|
2479
|
+
numberTo16BitUIntOrInt(depth),
|
|
2480
|
+
numberTo16BitUIntOrInt(-1),
|
|
2481
|
+
avccBox,
|
|
2482
|
+
pasp
|
|
2483
|
+
]));
|
|
2484
|
+
};
|
|
2485
|
+
|
|
2486
|
+
// src/create/iso-base-media/codec-specific/mp4a.ts
|
|
2487
|
+
var createMp4a = ({
|
|
2488
|
+
sampleRate,
|
|
2489
|
+
channelCount,
|
|
2490
|
+
avgBitrate,
|
|
2491
|
+
maxBitrate,
|
|
2492
|
+
codecPrivate
|
|
2493
|
+
}) => {
|
|
2494
|
+
if (!codecPrivate) {
|
|
2495
|
+
throw new Error("Need codecPrivate for mp4a");
|
|
2496
|
+
}
|
|
2497
|
+
const esdsAtom = addSize(combineUint8Arrays([
|
|
2498
|
+
stringsToUint8Array("esds"),
|
|
2499
|
+
new Uint8Array([0]),
|
|
2500
|
+
new Uint8Array([0, 0, 0]),
|
|
2501
|
+
new Uint8Array([3]),
|
|
2502
|
+
addLeading128Size(combineUint8Arrays([
|
|
2503
|
+
numberTo16BitUIntOrInt(2),
|
|
2504
|
+
new Uint8Array([0]),
|
|
2505
|
+
new Uint8Array([4]),
|
|
2506
|
+
addLeading128Size(combineUint8Arrays([
|
|
2507
|
+
new Uint8Array([64]),
|
|
2508
|
+
new Uint8Array([21]),
|
|
2509
|
+
new Uint8Array([0, 0, 0]),
|
|
2510
|
+
numberTo32BitUIntOrInt(maxBitrate),
|
|
2511
|
+
numberTo32BitUIntOrInt(avgBitrate),
|
|
2512
|
+
new Uint8Array([5]),
|
|
2513
|
+
addLeading128Size(codecPrivate)
|
|
2514
|
+
])),
|
|
2515
|
+
new Uint8Array([6]),
|
|
2516
|
+
addLeading128Size(new Uint8Array([2]))
|
|
2517
|
+
]))
|
|
2518
|
+
]));
|
|
2519
|
+
return addSize(combineUint8Arrays([
|
|
2520
|
+
stringsToUint8Array("mp4a"),
|
|
2521
|
+
new Uint8Array([0, 0, 0, 0, 0, 0]),
|
|
2522
|
+
numberTo16BitUIntOrInt(1),
|
|
2523
|
+
numberTo16BitUIntOrInt(0),
|
|
2524
|
+
numberTo16BitUIntOrInt(0),
|
|
2525
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2526
|
+
numberTo16BitUIntOrInt(channelCount),
|
|
2527
|
+
numberTo16BitUIntOrInt(16),
|
|
2528
|
+
numberTo16BitUIntOrInt(0),
|
|
2529
|
+
numberTo16BitUIntOrInt(0),
|
|
2530
|
+
setFixedPointSignedOrUnsigned1616Number(sampleRate),
|
|
2531
|
+
esdsAtom
|
|
2532
|
+
]));
|
|
2533
|
+
};
|
|
2534
|
+
|
|
2535
|
+
// src/create/iso-base-media/codec-specific/create-codec-specific-data.ts
|
|
2536
|
+
var createCodecSpecificData = (track) => {
|
|
2537
|
+
if (track.type === "video") {
|
|
2538
|
+
return createAvc1Data({
|
|
2539
|
+
avccBox: createAvccBox(track.codecPrivate),
|
|
2540
|
+
compressorName: "WebCodecs",
|
|
2541
|
+
depth: 24,
|
|
2542
|
+
horizontalResolution: 72,
|
|
2543
|
+
verticalResolution: 72,
|
|
2544
|
+
height: track.height,
|
|
2545
|
+
width: track.width,
|
|
2546
|
+
pasp: createPasp(1, 1),
|
|
2547
|
+
type: "avc1-data"
|
|
2548
|
+
});
|
|
2549
|
+
}
|
|
2550
|
+
if (track.type === "audio") {
|
|
2551
|
+
return createMp4a({
|
|
2552
|
+
type: "mp4a-data",
|
|
2553
|
+
avgBitrate: 128 * 1024,
|
|
2554
|
+
maxBitrate: 128 * 1024,
|
|
2555
|
+
channelCount: track.numberOfChannels,
|
|
2556
|
+
sampleRate: track.sampleRate,
|
|
2557
|
+
codecPrivate: track.codecPrivate
|
|
2558
|
+
});
|
|
2559
|
+
}
|
|
2560
|
+
throw new Error("Unsupported codec specific data " + track);
|
|
2561
|
+
};
|
|
2562
|
+
|
|
2563
|
+
// src/create/iso-base-media/create-mdia.ts
|
|
2564
|
+
var createMdia = ({
|
|
2565
|
+
mdhd,
|
|
2566
|
+
hdlr,
|
|
2567
|
+
minf
|
|
2568
|
+
}) => {
|
|
2569
|
+
return addSize(combineUint8Arrays([
|
|
2570
|
+
stringsToUint8Array("mdia"),
|
|
2571
|
+
mdhd,
|
|
2572
|
+
hdlr,
|
|
2573
|
+
minf
|
|
2574
|
+
]));
|
|
2575
|
+
};
|
|
2576
|
+
|
|
2577
|
+
// src/truthy.ts
|
|
2578
|
+
function truthy(value) {
|
|
2579
|
+
return Boolean(value);
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
// src/create/iso-base-media/create-trak.ts
|
|
2583
|
+
var createTrak = ({
|
|
2584
|
+
tkhd,
|
|
2585
|
+
mdia
|
|
2586
|
+
}) => {
|
|
2587
|
+
return addSize(combineUint8Arrays([
|
|
2588
|
+
stringsToUint8Array("trak"),
|
|
2589
|
+
tkhd,
|
|
2590
|
+
mdia
|
|
2591
|
+
].filter(truthy)));
|
|
2592
|
+
};
|
|
2593
|
+
|
|
2594
|
+
// src/create/iso-base-media/mdia/create-mdhd.ts
|
|
2595
|
+
var createMdhd = ({
|
|
2596
|
+
creationTime,
|
|
2597
|
+
modificationTime,
|
|
2598
|
+
timescale,
|
|
2599
|
+
duration
|
|
2600
|
+
}) => {
|
|
2601
|
+
return addSize(combineUint8Arrays([
|
|
2602
|
+
stringsToUint8Array("mdhd"),
|
|
2603
|
+
new Uint8Array([0]),
|
|
2604
|
+
new Uint8Array([0, 0, 0]),
|
|
2605
|
+
creationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(creationTime)),
|
|
2606
|
+
modificationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(modificationTime)),
|
|
2607
|
+
numberTo32BitUIntOrInt(timescale),
|
|
2608
|
+
numberTo32BitUIntOrInt(Math.round(duration / 1000 * timescale)),
|
|
2609
|
+
new Uint8Array([85, 196]),
|
|
2610
|
+
new Uint8Array([0, 0])
|
|
2611
|
+
]));
|
|
2612
|
+
};
|
|
2613
|
+
|
|
2614
|
+
// src/create/iso-base-media/trak/create-tkhd.ts
|
|
2615
|
+
var TKHD_FLAGS = {
|
|
2616
|
+
TRACK_ENABLED: 1,
|
|
2617
|
+
TRACK_IN_MOVIE: 2,
|
|
2618
|
+
TRACK_IN_PREVIEW: 4,
|
|
2619
|
+
TRACK_IN_POSTER: 8
|
|
2620
|
+
};
|
|
2621
|
+
var createTkhdForAudio = ({
|
|
2622
|
+
creationTime,
|
|
2623
|
+
modificationTime,
|
|
2624
|
+
flags,
|
|
2625
|
+
trackId,
|
|
2626
|
+
duration,
|
|
2627
|
+
volume,
|
|
2628
|
+
timescale
|
|
2629
|
+
}) => {
|
|
2630
|
+
return addSize(combineUint8Arrays([
|
|
2631
|
+
stringsToUint8Array("tkhd"),
|
|
2632
|
+
new Uint8Array([0]),
|
|
2633
|
+
new Uint8Array([0, 0, flags]),
|
|
2634
|
+
creationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(creationTime)),
|
|
2635
|
+
modificationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(modificationTime)),
|
|
2636
|
+
numberTo32BitUIntOrInt(trackId),
|
|
2637
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2638
|
+
numberTo32BitUIntOrInt(Math.round(duration / 1000 * timescale)),
|
|
2639
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2640
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2641
|
+
new Uint8Array([0, 0]),
|
|
2642
|
+
new Uint8Array([0, 1]),
|
|
2643
|
+
floatTo16Point16_16Bit(volume),
|
|
2644
|
+
new Uint8Array([0, 0]),
|
|
2645
|
+
serializeMatrix(IDENTITY_MATRIX),
|
|
2646
|
+
setFixedPointSignedOrUnsigned1616Number(0),
|
|
2647
|
+
setFixedPointSignedOrUnsigned1616Number(0)
|
|
2648
|
+
]));
|
|
2649
|
+
};
|
|
2650
|
+
var createTkhdForVideo = ({
|
|
2651
|
+
creationTime,
|
|
2652
|
+
modificationTime,
|
|
2653
|
+
duration,
|
|
2654
|
+
trackId,
|
|
2655
|
+
volume,
|
|
2656
|
+
matrix,
|
|
2657
|
+
width,
|
|
2658
|
+
height,
|
|
2659
|
+
flags,
|
|
2660
|
+
timescale
|
|
2661
|
+
}) => {
|
|
2662
|
+
const content = combineUint8Arrays([
|
|
2663
|
+
stringsToUint8Array("tkhd"),
|
|
2664
|
+
new Uint8Array([0]),
|
|
2665
|
+
new Uint8Array([0, 0, flags]),
|
|
2666
|
+
creationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(creationTime)),
|
|
2667
|
+
modificationTime === null ? numberTo32BitUIntOrInt(0) : numberTo32BitUIntOrInt(fromUnixTimestamp(modificationTime)),
|
|
2668
|
+
numberTo32BitUIntOrInt(trackId),
|
|
2669
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2670
|
+
numberTo32BitUIntOrInt(duration / 1000 * timescale),
|
|
2671
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2672
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2673
|
+
new Uint8Array([0, 0]),
|
|
2674
|
+
new Uint8Array([0, 0]),
|
|
2675
|
+
floatTo16Point16_16Bit(volume),
|
|
2676
|
+
new Uint8Array([0, 0]),
|
|
2677
|
+
serializeMatrix(matrix),
|
|
2678
|
+
setFixedPointSignedOrUnsigned1616Number(width),
|
|
2679
|
+
setFixedPointSignedOrUnsigned1616Number(height)
|
|
2680
|
+
]);
|
|
2681
|
+
return addSize(content);
|
|
2682
|
+
};
|
|
2683
|
+
|
|
2684
|
+
// src/create/iso-base-media/trak/mdia/minf/create-dinf.ts
|
|
2685
|
+
var createDinf = () => {
|
|
2686
|
+
return addSize(combineUint8Arrays([
|
|
2687
|
+
stringsToUint8Array("dinf"),
|
|
2688
|
+
addSize(combineUint8Arrays([
|
|
2689
|
+
stringsToUint8Array("dref"),
|
|
2690
|
+
new Uint8Array([0]),
|
|
2691
|
+
new Uint8Array([0, 0, 0]),
|
|
2692
|
+
new Uint8Array([0, 0, 0, 1]),
|
|
2693
|
+
addSize(combineUint8Arrays([
|
|
2694
|
+
stringsToUint8Array("url "),
|
|
2695
|
+
new Uint8Array([0]),
|
|
2696
|
+
new Uint8Array([0, 0, 1])
|
|
2697
|
+
]))
|
|
2698
|
+
]))
|
|
2699
|
+
]));
|
|
2700
|
+
};
|
|
2701
|
+
|
|
2702
|
+
// src/create/iso-base-media/trak/mdia/create-minf.ts
|
|
2703
|
+
var createMinf = ({
|
|
2704
|
+
vmhdAtom,
|
|
2705
|
+
stblAtom
|
|
2706
|
+
}) => {
|
|
2707
|
+
return addSize(combineUint8Arrays([
|
|
2708
|
+
stringsToUint8Array("minf"),
|
|
2709
|
+
vmhdAtom,
|
|
2710
|
+
createDinf(),
|
|
2711
|
+
stblAtom
|
|
2712
|
+
]));
|
|
2713
|
+
};
|
|
2714
|
+
|
|
2715
|
+
// src/create/iso-base-media/trak/mdia/minf/create-smhd.ts
|
|
2716
|
+
var createSmhd = () => {
|
|
2717
|
+
return addSize(combineUint8Arrays([
|
|
2718
|
+
stringsToUint8Array("smhd"),
|
|
2719
|
+
new Uint8Array([0]),
|
|
2720
|
+
new Uint8Array([0, 0, 0]),
|
|
2721
|
+
new Uint8Array([0, 0]),
|
|
2722
|
+
new Uint8Array([0, 0])
|
|
2723
|
+
]));
|
|
2724
|
+
};
|
|
2725
|
+
|
|
2726
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/create-ctts.ts
|
|
2727
|
+
var makeEntry = (entry) => {
|
|
2728
|
+
return combineUint8Arrays([
|
|
2729
|
+
numberTo32BitUIntOrInt(entry.sampleCount),
|
|
2730
|
+
numberTo32BitUIntOrInt(entry.sampleOffset)
|
|
2731
|
+
]);
|
|
2732
|
+
};
|
|
2733
|
+
var createCttsBox = (samplePositions) => {
|
|
2734
|
+
const offsets = samplePositions.map((s) => s.cts - s.dts);
|
|
2735
|
+
const entries = [];
|
|
2736
|
+
let lastOffset = null;
|
|
2737
|
+
for (const offset of offsets) {
|
|
2738
|
+
if (lastOffset === offset) {
|
|
2739
|
+
entries[entries.length - 1].sampleCount++;
|
|
2740
|
+
} else {
|
|
2741
|
+
entries.push({
|
|
2742
|
+
sampleCount: 1,
|
|
2743
|
+
sampleOffset: offset
|
|
2744
|
+
});
|
|
2745
|
+
}
|
|
2746
|
+
lastOffset = offset;
|
|
2747
|
+
}
|
|
2748
|
+
const needsCtts = entries.length > 0 && entries.some((e) => e.sampleOffset !== 0);
|
|
2749
|
+
if (!needsCtts) {
|
|
2750
|
+
return null;
|
|
2751
|
+
}
|
|
2752
|
+
return addSize(combineUint8Arrays([
|
|
2753
|
+
stringsToUint8Array("ctts"),
|
|
2754
|
+
new Uint8Array([0]),
|
|
2755
|
+
new Uint8Array([0, 0, 0]),
|
|
2756
|
+
numberTo32BitUIntOrInt(entries.length),
|
|
2757
|
+
...entries.map((e) => makeEntry(e))
|
|
2758
|
+
]));
|
|
2759
|
+
};
|
|
2760
|
+
|
|
2761
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/create-stco.ts
|
|
2762
|
+
var createStcoAtom = (samplePositions) => {
|
|
2763
|
+
const chunkOffsets = [];
|
|
2764
|
+
let lastChunk;
|
|
2765
|
+
for (const sample of samplePositions) {
|
|
2766
|
+
if (lastChunk !== sample.chunk) {
|
|
2767
|
+
chunkOffsets.push(sample.offset);
|
|
2768
|
+
}
|
|
2769
|
+
lastChunk = sample.chunk;
|
|
2770
|
+
}
|
|
2771
|
+
return addSize(combineUint8Arrays([
|
|
2772
|
+
stringsToUint8Array("stco"),
|
|
2773
|
+
new Uint8Array([0]),
|
|
2774
|
+
new Uint8Array([0, 0, 0]),
|
|
2775
|
+
numberTo32BitUIntOrInt(chunkOffsets.length),
|
|
2776
|
+
...chunkOffsets.map((offset) => numberTo32BitUIntOrInt(offset))
|
|
2777
|
+
]));
|
|
2778
|
+
};
|
|
2779
|
+
|
|
2780
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/create-stsc.ts
|
|
2781
|
+
var createEntry = (entry) => {
|
|
2782
|
+
return combineUint8Arrays([
|
|
2783
|
+
numberTo32BitUIntOrInt(entry.firstChunk),
|
|
2784
|
+
numberTo32BitUIntOrInt(entry.samplesPerChunk),
|
|
2785
|
+
numberTo32BitUIntOrInt(entry.sampleDescriptionIndex)
|
|
2786
|
+
]);
|
|
2787
|
+
};
|
|
2788
|
+
var createStsc = (samplePositions) => {
|
|
2789
|
+
const entries = [];
|
|
2790
|
+
const deduplicateLastEntry = () => {
|
|
2791
|
+
const lastEntry = entries[entries.length - 1];
|
|
2792
|
+
const secondToLastEntry = entries[entries.length - 2];
|
|
2793
|
+
if (lastEntry && secondToLastEntry && lastEntry.samplesPerChunk === secondToLastEntry.samplesPerChunk && lastEntry.sampleDescriptionIndex === secondToLastEntry.sampleDescriptionIndex) {
|
|
2794
|
+
const lastIndex = entries.length - 1;
|
|
2795
|
+
entries.length = lastIndex;
|
|
2796
|
+
}
|
|
2797
|
+
};
|
|
2798
|
+
let lastChunk;
|
|
2799
|
+
for (const samplePosition of samplePositions) {
|
|
2800
|
+
if (samplePosition.chunk === lastChunk) {
|
|
2801
|
+
entries[entries.length - 1].samplesPerChunk++;
|
|
2802
|
+
} else {
|
|
2803
|
+
deduplicateLastEntry();
|
|
2804
|
+
entries.push({
|
|
2805
|
+
firstChunk: samplePosition.chunk,
|
|
2806
|
+
samplesPerChunk: 1,
|
|
2807
|
+
sampleDescriptionIndex: 1
|
|
2808
|
+
});
|
|
2809
|
+
lastChunk = samplePosition.chunk;
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
deduplicateLastEntry();
|
|
2813
|
+
return addSize(combineUint8Arrays([
|
|
2814
|
+
stringsToUint8Array("stsc"),
|
|
2815
|
+
new Uint8Array([0]),
|
|
2816
|
+
new Uint8Array([0, 0, 0]),
|
|
2817
|
+
numberTo32BitUIntOrInt(entries.length),
|
|
2818
|
+
...entries.map((e) => createEntry(e))
|
|
2819
|
+
]));
|
|
2820
|
+
};
|
|
2821
|
+
|
|
2822
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/create-stss.ts
|
|
2823
|
+
var createStss = (samplePositions) => {
|
|
2824
|
+
const samples = samplePositions.map((sample, i) => [sample.isKeyframe, i]).filter((s) => s[0]).map((s) => s[1] + 1);
|
|
2825
|
+
return addSize(combineUint8Arrays([
|
|
2826
|
+
stringsToUint8Array("stss"),
|
|
2827
|
+
new Uint8Array([0]),
|
|
2828
|
+
new Uint8Array([0, 0, 0]),
|
|
2829
|
+
numberTo32BitUIntOrInt(samples.length),
|
|
2830
|
+
...samples.map((sample) => numberTo32BitUIntOrInt(sample))
|
|
2831
|
+
]));
|
|
2832
|
+
};
|
|
2833
|
+
|
|
2834
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/create-stsz.ts
|
|
2835
|
+
var createStsz = (samplePositions) => {
|
|
2836
|
+
const sampleSizes = samplePositions.map((samplePosition) => samplePosition.size);
|
|
2837
|
+
return addSize(combineUint8Arrays([
|
|
2838
|
+
stringsToUint8Array("stsz"),
|
|
2839
|
+
new Uint8Array([0]),
|
|
2840
|
+
new Uint8Array([0, 0, 0]),
|
|
2841
|
+
numberTo32BitUIntOrInt(0),
|
|
2842
|
+
numberTo32BitUIntOrInt(sampleSizes.length),
|
|
2843
|
+
...sampleSizes.map((size) => numberTo32BitUIntOrInt(size))
|
|
2844
|
+
]));
|
|
2845
|
+
};
|
|
2846
|
+
|
|
2847
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/create-stts.ts
|
|
2848
|
+
var makeEntry2 = (entry) => {
|
|
2849
|
+
if (entry.sampleOffset < 0) {
|
|
2850
|
+
throw new Error("negative sample offset in stts " + entry.sampleOffset);
|
|
2851
|
+
}
|
|
2852
|
+
return combineUint8Arrays([
|
|
2853
|
+
numberTo32BitUIntOrInt(entry.sampleCount),
|
|
2854
|
+
numberTo32BitUIntOrInt(entry.sampleOffset)
|
|
2855
|
+
]);
|
|
2856
|
+
};
|
|
2857
|
+
var createSttsAtom = (samplePositions) => {
|
|
2858
|
+
let lastDuration = null;
|
|
2859
|
+
const durations = samplePositions.map((_, i, a) => {
|
|
2860
|
+
if (a[i].duration === undefined || a[i].duration === 0) {
|
|
2861
|
+
return (a[i + 1]?.dts ?? a[i].dts) - a[i].dts;
|
|
2862
|
+
}
|
|
2863
|
+
return a[i].duration;
|
|
2864
|
+
});
|
|
2865
|
+
const entries = [];
|
|
2866
|
+
for (const duration of durations) {
|
|
2867
|
+
if (duration === lastDuration) {
|
|
2868
|
+
entries[entries.length - 1].sampleCount++;
|
|
2869
|
+
} else {
|
|
2870
|
+
entries.push({
|
|
2871
|
+
sampleCount: 1,
|
|
2872
|
+
sampleOffset: duration
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
lastDuration = duration;
|
|
2876
|
+
}
|
|
2877
|
+
return addSize(combineUint8Arrays([
|
|
2878
|
+
stringsToUint8Array("stts"),
|
|
2879
|
+
new Uint8Array([0]),
|
|
2880
|
+
new Uint8Array([0, 0, 0]),
|
|
2881
|
+
numberTo32BitUIntOrInt(entries.length),
|
|
2882
|
+
...entries.map((e) => makeEntry2(e))
|
|
2883
|
+
]));
|
|
2884
|
+
};
|
|
2885
|
+
|
|
2886
|
+
// src/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avc1.ts
|
|
2887
|
+
var createStsdData = (codecSpecificData) => {
|
|
2888
|
+
return addSize(combineUint8Arrays([
|
|
2889
|
+
stringsToUint8Array("stsd"),
|
|
2890
|
+
new Uint8Array([0]),
|
|
2891
|
+
new Uint8Array([0, 0, 0]),
|
|
2892
|
+
new Uint8Array([0, 0, 0, 1]),
|
|
2893
|
+
codecSpecificData
|
|
2894
|
+
]));
|
|
2895
|
+
};
|
|
2896
|
+
|
|
2897
|
+
// src/create/iso-base-media/trak/mdia/minf/create-stbl.ts
|
|
2898
|
+
var createStbl = ({
|
|
2899
|
+
samplePositions,
|
|
2900
|
+
codecSpecificData,
|
|
2901
|
+
isVideo
|
|
2902
|
+
}) => {
|
|
2903
|
+
const sorted = samplePositions.slice().sort((a, b) => a.dts - b.dts);
|
|
2904
|
+
return addSize(combineUint8Arrays([
|
|
2905
|
+
stringsToUint8Array("stbl"),
|
|
2906
|
+
createStsdData(codecSpecificData),
|
|
2907
|
+
createSttsAtom(sorted),
|
|
2908
|
+
isVideo ? createStss(samplePositions) : null,
|
|
2909
|
+
createCttsBox(samplePositions),
|
|
2910
|
+
createStsc(samplePositions),
|
|
2911
|
+
createStsz(samplePositions),
|
|
2912
|
+
createStcoAtom(samplePositions),
|
|
2913
|
+
isVideo ? null : new Uint8Array([
|
|
2914
|
+
0,
|
|
2915
|
+
0,
|
|
2916
|
+
0,
|
|
2917
|
+
26,
|
|
2918
|
+
115,
|
|
2919
|
+
103,
|
|
2920
|
+
112,
|
|
2921
|
+
100,
|
|
2922
|
+
1,
|
|
2923
|
+
0,
|
|
2924
|
+
0,
|
|
2925
|
+
0,
|
|
2926
|
+
114,
|
|
2927
|
+
111,
|
|
2928
|
+
108,
|
|
2929
|
+
108,
|
|
2930
|
+
0,
|
|
2931
|
+
0,
|
|
2932
|
+
0,
|
|
2933
|
+
2,
|
|
2934
|
+
0,
|
|
2935
|
+
0,
|
|
2936
|
+
0,
|
|
2937
|
+
1,
|
|
2938
|
+
255,
|
|
2939
|
+
255,
|
|
2940
|
+
0,
|
|
2941
|
+
0,
|
|
2942
|
+
0,
|
|
2943
|
+
28,
|
|
2944
|
+
115,
|
|
2945
|
+
98,
|
|
2946
|
+
103,
|
|
2947
|
+
112,
|
|
2948
|
+
0,
|
|
2949
|
+
0,
|
|
2950
|
+
0,
|
|
2951
|
+
0,
|
|
2952
|
+
114,
|
|
2953
|
+
111,
|
|
2954
|
+
108,
|
|
2955
|
+
108,
|
|
2956
|
+
0,
|
|
2957
|
+
0,
|
|
2958
|
+
0,
|
|
2959
|
+
1,
|
|
2960
|
+
0,
|
|
2961
|
+
0,
|
|
2962
|
+
10,
|
|
2963
|
+
25,
|
|
2964
|
+
0,
|
|
2965
|
+
0,
|
|
2966
|
+
0,
|
|
2967
|
+
1
|
|
2968
|
+
])
|
|
2969
|
+
].filter(truthy)));
|
|
2970
|
+
};
|
|
2971
|
+
|
|
2972
|
+
// src/create/iso-base-media/trak/mdia/minf/create-vmhd.ts
|
|
2973
|
+
var createVmhd = () => {
|
|
2974
|
+
return addSize(combineUint8Arrays([
|
|
2975
|
+
stringsToUint8Array("vmhd"),
|
|
2976
|
+
new Uint8Array([0]),
|
|
2977
|
+
new Uint8Array([0, 0, 1]),
|
|
2978
|
+
new Uint8Array([0, 0]),
|
|
2979
|
+
new Uint8Array([0, 0, 0, 0, 0, 0])
|
|
2980
|
+
]));
|
|
2981
|
+
};
|
|
2982
|
+
|
|
2983
|
+
// src/create/iso-base-media/udta/meta/create-hdlr.ts
|
|
2984
|
+
var createHdlr = (type) => {
|
|
2985
|
+
return addSize(combineUint8Arrays([
|
|
2986
|
+
stringsToUint8Array("hdlr"),
|
|
2987
|
+
new Uint8Array([0]),
|
|
2988
|
+
new Uint8Array([0, 0, 0]),
|
|
2989
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2990
|
+
stringsToUint8Array(type === "mdir" ? "mdir" : type === "video" ? "vide" : "soun"),
|
|
2991
|
+
type === "mdir" ? numberTo32BitUIntOrInt(1634758764) : new Uint8Array([0, 0, 0, 0]),
|
|
2992
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2993
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
2994
|
+
stringsToUint8Array(type === "mdir" ? "\x00" : type === "video" ? "VideoHandler\x00" : "SoundHandler\x00")
|
|
2995
|
+
]));
|
|
2996
|
+
};
|
|
2997
|
+
|
|
2998
|
+
// src/create/iso-base-media/serialize-track.ts
|
|
2999
|
+
var serializeTrack = ({
|
|
3000
|
+
track,
|
|
3001
|
+
durationInUnits,
|
|
3002
|
+
samplePositions,
|
|
3003
|
+
timescale
|
|
3004
|
+
}) => {
|
|
3005
|
+
if (track.codec !== "h264" && track.codec !== "aac") {
|
|
3006
|
+
throw new Error("Currently only H.264 and AAC is supported");
|
|
3007
|
+
}
|
|
3008
|
+
return createTrak({
|
|
3009
|
+
tkhd: track.codec === "aac" ? createTkhdForAudio({
|
|
3010
|
+
creationTime: Date.now(),
|
|
3011
|
+
flags: TKHD_FLAGS.TRACK_ENABLED | TKHD_FLAGS.TRACK_IN_MOVIE,
|
|
3012
|
+
modificationTime: Date.now(),
|
|
3013
|
+
duration: durationInUnits,
|
|
3014
|
+
trackId: track.trackNumber,
|
|
3015
|
+
volume: 1,
|
|
3016
|
+
timescale
|
|
3017
|
+
}) : track.type === "video" ? createTkhdForVideo({
|
|
3018
|
+
creationTime: Date.now(),
|
|
3019
|
+
modificationTime: Date.now(),
|
|
3020
|
+
duration: durationInUnits,
|
|
3021
|
+
flags: TKHD_FLAGS.TRACK_ENABLED | TKHD_FLAGS.TRACK_IN_MOVIE,
|
|
3022
|
+
height: track.height,
|
|
3023
|
+
width: track.width,
|
|
3024
|
+
matrix: IDENTITY_MATRIX,
|
|
3025
|
+
trackId: track.trackNumber,
|
|
3026
|
+
volume: 0,
|
|
3027
|
+
timescale
|
|
3028
|
+
}) : new Uint8Array(stringsToUint8Array("wrong")),
|
|
3029
|
+
mdia: createMdia({
|
|
3030
|
+
mdhd: createMdhd({
|
|
3031
|
+
creationTime: null,
|
|
3032
|
+
modificationTime: null,
|
|
3033
|
+
duration: durationInUnits,
|
|
3034
|
+
timescale: track.timescale
|
|
3035
|
+
}),
|
|
3036
|
+
hdlr: track.type === "video" ? createHdlr("video") : createHdlr("audio"),
|
|
3037
|
+
minf: createMinf({
|
|
3038
|
+
stblAtom: createStbl({
|
|
3039
|
+
samplePositions,
|
|
3040
|
+
isVideo: track.type === "video",
|
|
3041
|
+
codecSpecificData: createCodecSpecificData(track)
|
|
3042
|
+
}),
|
|
3043
|
+
vmhdAtom: track.type === "audio" ? createSmhd() : createVmhd()
|
|
3044
|
+
})
|
|
3045
|
+
})
|
|
3046
|
+
});
|
|
3047
|
+
};
|
|
3048
|
+
|
|
3049
|
+
// src/create/iso-base-media/udta/create-meta.ts
|
|
3050
|
+
var createMeta = ({
|
|
3051
|
+
hdlr,
|
|
3052
|
+
ilst
|
|
3053
|
+
}) => {
|
|
3054
|
+
return addSize(combineUint8Arrays([
|
|
3055
|
+
stringsToUint8Array("meta"),
|
|
3056
|
+
new Uint8Array([0]),
|
|
3057
|
+
new Uint8Array([0, 0, 0]),
|
|
3058
|
+
hdlr,
|
|
3059
|
+
ilst
|
|
3060
|
+
]));
|
|
3061
|
+
};
|
|
3062
|
+
|
|
3063
|
+
// src/create/iso-base-media/mp4-header.ts
|
|
3064
|
+
var HEADER_LENGTH = 1024000;
|
|
3065
|
+
var createPaddedMoovAtom = ({
|
|
3066
|
+
durationInUnits,
|
|
3067
|
+
trackInfo,
|
|
3068
|
+
timescale
|
|
3069
|
+
}) => {
|
|
3070
|
+
return padIsoBaseMediaBytes(createMoov({
|
|
3071
|
+
mvhd: createMvhd({
|
|
3072
|
+
timescale,
|
|
3073
|
+
durationInUnits,
|
|
3074
|
+
matrix: IDENTITY_MATRIX,
|
|
3075
|
+
nextTrackId: trackInfo.map((t) => t.track.trackNumber).reduce((a, b) => Math.max(a, b), 0) + 1,
|
|
3076
|
+
rate: 1,
|
|
3077
|
+
volume: 1,
|
|
3078
|
+
creationTime: Date.now(),
|
|
3079
|
+
modificationTime: Date.now()
|
|
3080
|
+
}),
|
|
3081
|
+
traks: trackInfo.map((track) => {
|
|
3082
|
+
return serializeTrack({
|
|
3083
|
+
timescale,
|
|
3084
|
+
track: track.track,
|
|
3085
|
+
durationInUnits,
|
|
3086
|
+
samplePositions: track.samplePositions
|
|
3087
|
+
});
|
|
3088
|
+
}),
|
|
3089
|
+
udta: createUdta(createMeta({
|
|
3090
|
+
hdlr: createHdlr("mdir"),
|
|
3091
|
+
ilst: createIlst([
|
|
3092
|
+
createToo("WebCodecs"),
|
|
3093
|
+
createCmt(`Made with @remotion/webcodecs ${VERSION2}`)
|
|
3094
|
+
])
|
|
3095
|
+
}))
|
|
3096
|
+
}), HEADER_LENGTH);
|
|
3097
|
+
};
|
|
3098
|
+
|
|
3099
|
+
// src/create/iso-base-media/create-iso-base-media.ts
|
|
3100
|
+
var CONTAINER_TIMESCALE = 1000;
|
|
3101
|
+
var createIsoBaseMedia = async ({
|
|
3102
|
+
writer,
|
|
3103
|
+
onBytesProgress,
|
|
3104
|
+
onMillisecondsProgress,
|
|
3105
|
+
logLevel,
|
|
3106
|
+
filename,
|
|
3107
|
+
progressTracker
|
|
3108
|
+
}) => {
|
|
3109
|
+
const header = createIsoBaseMediaFtyp({
|
|
3110
|
+
compatibleBrands: ["isom", "iso2", "avc1", "mp42"],
|
|
3111
|
+
majorBrand: "isom",
|
|
3112
|
+
minorBrand: 512
|
|
3113
|
+
});
|
|
3114
|
+
const w = await writer.createContent({ filename, mimeType: "video/mp4" });
|
|
3115
|
+
await w.write(header);
|
|
3116
|
+
let globalDurationInUnits = 0;
|
|
3117
|
+
const lowestTrackTimestamps = {};
|
|
3118
|
+
const trackDurations = {};
|
|
3119
|
+
const currentTracks = [];
|
|
3120
|
+
const samplePositions = [];
|
|
3121
|
+
const sampleChunkIndices = [];
|
|
3122
|
+
const moovOffset = w.getWrittenByteCount();
|
|
3123
|
+
const getPaddedMoovAtom = () => {
|
|
3124
|
+
return createPaddedMoovAtom({
|
|
3125
|
+
durationInUnits: globalDurationInUnits,
|
|
3126
|
+
trackInfo: currentTracks.map((track) => {
|
|
3127
|
+
return {
|
|
3128
|
+
track,
|
|
3129
|
+
durationInUnits: trackDurations[track.trackNumber] ?? 0,
|
|
3130
|
+
samplePositions: samplePositions[track.trackNumber] ?? [],
|
|
3131
|
+
timescale: track.timescale
|
|
3132
|
+
};
|
|
3133
|
+
}),
|
|
3134
|
+
timescale: CONTAINER_TIMESCALE
|
|
3135
|
+
});
|
|
3136
|
+
};
|
|
3137
|
+
await w.write(getPaddedMoovAtom());
|
|
3138
|
+
let mdatSize = 8;
|
|
3139
|
+
const mdatSizeOffset = w.getWrittenByteCount();
|
|
3140
|
+
await w.write(combineUint8Arrays([
|
|
3141
|
+
numberTo32BitUIntOrInt(mdatSize),
|
|
3142
|
+
stringsToUint8Array("mdat")
|
|
3143
|
+
]));
|
|
3144
|
+
const updateMdatSize = async () => {
|
|
3145
|
+
await w.updateDataAt(mdatSizeOffset, numberTo32BitUIntOrInt(mdatSize));
|
|
3146
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3147
|
+
};
|
|
3148
|
+
const operationProm = { current: Promise.resolve() };
|
|
3149
|
+
const updateMoov = async () => {
|
|
3150
|
+
await w.updateDataAt(moovOffset, getPaddedMoovAtom());
|
|
3151
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3152
|
+
};
|
|
3153
|
+
const addCodecPrivateToTrack = ({
|
|
3154
|
+
trackNumber,
|
|
3155
|
+
codecPrivate
|
|
3156
|
+
}) => {
|
|
3157
|
+
currentTracks.forEach((track) => {
|
|
3158
|
+
if (track.trackNumber === trackNumber) {
|
|
3159
|
+
track.codecPrivate = codecPrivate;
|
|
3160
|
+
}
|
|
3161
|
+
});
|
|
3162
|
+
};
|
|
3163
|
+
let lastChunkWasVideo = false;
|
|
3164
|
+
const addSample = async ({
|
|
3165
|
+
chunk,
|
|
3166
|
+
trackNumber,
|
|
3167
|
+
isVideo,
|
|
3168
|
+
codecPrivate
|
|
3169
|
+
}) => {
|
|
3170
|
+
const position = w.getWrittenByteCount();
|
|
3171
|
+
await w.write(chunk.data);
|
|
3172
|
+
mdatSize += chunk.data.length;
|
|
3173
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3174
|
+
progressTracker.setPossibleLowestTimestamp(Math.min(chunk.timestamp, chunk.cts ?? Infinity, chunk.dts ?? Infinity));
|
|
3175
|
+
progressTracker.updateTrackProgress(trackNumber, chunk.timestamp);
|
|
3176
|
+
if (codecPrivate) {
|
|
3177
|
+
addCodecPrivateToTrack({ trackNumber, codecPrivate });
|
|
3178
|
+
}
|
|
3179
|
+
const currentTrack = currentTracks.find((t) => t.trackNumber === trackNumber);
|
|
3180
|
+
if (!currentTrack) {
|
|
3181
|
+
throw new Error(`Tried to add sample to track ${trackNumber}, but it doesn't exist`);
|
|
3182
|
+
}
|
|
3183
|
+
if (!lowestTrackTimestamps[trackNumber] || chunk.timestamp < lowestTrackTimestamps[trackNumber]) {
|
|
3184
|
+
lowestTrackTimestamps[trackNumber] = chunk.timestamp;
|
|
3185
|
+
}
|
|
3186
|
+
if (typeof lowestTrackTimestamps[trackNumber] !== "number") {
|
|
3187
|
+
throw new Error(`Tried to add sample to track ${trackNumber}, but it has no timestamp`);
|
|
3188
|
+
}
|
|
3189
|
+
const newDurationInMicroSeconds = chunk.timestamp + (chunk.duration ?? 0) - lowestTrackTimestamps[trackNumber];
|
|
3190
|
+
const newDurationInTrackTimeUnits = Math.round(newDurationInMicroSeconds / (1e6 / currentTrack.timescale));
|
|
3191
|
+
trackDurations[trackNumber] = newDurationInTrackTimeUnits;
|
|
3192
|
+
const newDurationInMilliseconds = Math.round(newDurationInMicroSeconds / 1e6 * CONTAINER_TIMESCALE);
|
|
3193
|
+
if (newDurationInMilliseconds > globalDurationInUnits) {
|
|
3194
|
+
globalDurationInUnits = newDurationInMilliseconds;
|
|
3195
|
+
onMillisecondsProgress(newDurationInMilliseconds);
|
|
3196
|
+
}
|
|
3197
|
+
if (!samplePositions[trackNumber]) {
|
|
3198
|
+
samplePositions[trackNumber] = [];
|
|
3199
|
+
}
|
|
3200
|
+
if (typeof sampleChunkIndices[trackNumber] === "undefined") {
|
|
3201
|
+
sampleChunkIndices[trackNumber] = 0;
|
|
3202
|
+
}
|
|
3203
|
+
if (isVideo && chunk.type === "key") {
|
|
3204
|
+
sampleChunkIndices[trackNumber]++;
|
|
3205
|
+
} else if (!isVideo && samplePositions[trackNumber].length % 22 === 0) {
|
|
3206
|
+
sampleChunkIndices[trackNumber]++;
|
|
3207
|
+
} else if (lastChunkWasVideo !== isVideo) {
|
|
3208
|
+
sampleChunkIndices[trackNumber]++;
|
|
3209
|
+
}
|
|
3210
|
+
const samplePositionToAdd = {
|
|
3211
|
+
isKeyframe: chunk.type === "key",
|
|
3212
|
+
offset: position,
|
|
3213
|
+
chunk: sampleChunkIndices[trackNumber],
|
|
3214
|
+
cts: Math.round(chunk.cts / 1e6 * currentTrack.timescale),
|
|
3215
|
+
dts: Math.round(chunk.dts / 1e6 * currentTrack.timescale),
|
|
3216
|
+
duration: Math.round((chunk.duration ?? 0) / 1e6 * currentTrack.timescale),
|
|
3217
|
+
size: chunk.data.length
|
|
3218
|
+
};
|
|
3219
|
+
lastChunkWasVideo = isVideo;
|
|
3220
|
+
samplePositions[trackNumber].push(samplePositionToAdd);
|
|
3221
|
+
};
|
|
3222
|
+
const addTrack = (track) => {
|
|
3223
|
+
const trackNumber = currentTracks.length + 1;
|
|
3224
|
+
currentTracks.push({ ...track, trackNumber });
|
|
3225
|
+
progressTracker.registerTrack(trackNumber);
|
|
3226
|
+
return Promise.resolve({ trackNumber });
|
|
3227
|
+
};
|
|
3228
|
+
const waitForFinishPromises = [];
|
|
3229
|
+
return {
|
|
3230
|
+
save: () => {
|
|
3231
|
+
return w.save();
|
|
3232
|
+
},
|
|
3233
|
+
remove: async () => {
|
|
3234
|
+
await w.remove();
|
|
3235
|
+
},
|
|
3236
|
+
addSample: ({ chunk, trackNumber, isVideo, codecPrivate }) => {
|
|
3237
|
+
operationProm.current = operationProm.current.then(() => {
|
|
3238
|
+
return addSample({
|
|
3239
|
+
chunk,
|
|
3240
|
+
trackNumber,
|
|
3241
|
+
isVideo,
|
|
3242
|
+
codecPrivate
|
|
3243
|
+
});
|
|
3244
|
+
});
|
|
3245
|
+
return operationProm.current;
|
|
3246
|
+
},
|
|
3247
|
+
addTrack: (track) => {
|
|
3248
|
+
operationProm.current = operationProm.current.then(() => addTrack(track));
|
|
3249
|
+
return operationProm.current;
|
|
3250
|
+
},
|
|
3251
|
+
updateTrackSampleRate: ({ sampleRate, trackNumber }) => {
|
|
3252
|
+
currentTracks.forEach((track) => {
|
|
3253
|
+
if (track.trackNumber === trackNumber) {
|
|
3254
|
+
if (track.type !== "audio") {
|
|
3255
|
+
throw new Error(`Tried to update sample rate of track ${trackNumber}, but it's not an audio track`);
|
|
3256
|
+
}
|
|
3257
|
+
track.sampleRate = sampleRate;
|
|
3258
|
+
}
|
|
3259
|
+
});
|
|
3260
|
+
},
|
|
3261
|
+
addWaitForFinishPromise: (promise) => {
|
|
3262
|
+
waitForFinishPromises.push(promise);
|
|
3263
|
+
},
|
|
3264
|
+
async waitForFinish() {
|
|
3265
|
+
MediaParserInternals6.Log.verbose(logLevel, "All write operations queued. Waiting for finish...");
|
|
3266
|
+
await Promise.all(waitForFinishPromises.map((p) => p()));
|
|
3267
|
+
MediaParserInternals6.Log.verbose(logLevel, "Cleanup tasks executed");
|
|
3268
|
+
await operationProm.current;
|
|
3269
|
+
await updateMoov();
|
|
3270
|
+
await updateMdatSize();
|
|
3271
|
+
MediaParserInternals6.Log.verbose(logLevel, "All write operations done. Waiting for finish...");
|
|
3272
|
+
await w.waitForFinish();
|
|
3273
|
+
}
|
|
3274
|
+
};
|
|
3275
|
+
};
|
|
3276
|
+
|
|
3277
|
+
// src/create/matroska/create-matroska-media.ts
|
|
3278
|
+
import { MediaParserInternals as MediaParserInternals8 } from "@remotion/media-parser";
|
|
3279
|
+
|
|
3280
|
+
// src/create/matroska/cluster.ts
|
|
3281
|
+
import {
|
|
3282
|
+
MediaParserInternals as MediaParserInternals7
|
|
3283
|
+
} from "@remotion/media-parser";
|
|
3284
|
+
|
|
3285
|
+
// src/create/matroska/cluster-segment.ts
|
|
3286
|
+
var CLUSTER_MIN_VINT_WIDTH = 8;
|
|
3287
|
+
var createClusterSegment = (timestamp) => {
|
|
3288
|
+
return makeMatroskaBytes({
|
|
3289
|
+
type: "Cluster",
|
|
3290
|
+
value: [
|
|
3291
|
+
{
|
|
3292
|
+
type: "Timestamp",
|
|
3293
|
+
minVintWidth: null,
|
|
3294
|
+
value: {
|
|
3295
|
+
value: timestamp,
|
|
3296
|
+
byteLength: null
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
],
|
|
3300
|
+
minVintWidth: CLUSTER_MIN_VINT_WIDTH
|
|
3301
|
+
});
|
|
3302
|
+
};
|
|
3303
|
+
var makeSimpleBlock = ({
|
|
3304
|
+
bytes,
|
|
3305
|
+
trackNumber,
|
|
3306
|
+
timecodeRelativeToCluster,
|
|
3307
|
+
keyframe,
|
|
3308
|
+
invisible,
|
|
3309
|
+
lacing
|
|
3310
|
+
}) => {
|
|
3311
|
+
const simpleBlockHeader = matroskaToHex("0xa3");
|
|
3312
|
+
const headerByte = Number(keyframe) << 7 | Number(invisible) << 3 | lacing << 1;
|
|
3313
|
+
const body = combineUint8Arrays([
|
|
3314
|
+
getVariableInt(trackNumber, null),
|
|
3315
|
+
serializeUint16(timecodeRelativeToCluster),
|
|
3316
|
+
new Uint8Array([headerByte]),
|
|
3317
|
+
bytes
|
|
3318
|
+
]);
|
|
3319
|
+
return combineUint8Arrays([
|
|
3320
|
+
simpleBlockHeader,
|
|
3321
|
+
getVariableInt(body.length, null),
|
|
3322
|
+
body
|
|
3323
|
+
]);
|
|
3324
|
+
};
|
|
3325
|
+
|
|
3326
|
+
// src/create/matroska/cluster.ts
|
|
3327
|
+
var maxClusterTimestamp = 2 ** 15;
|
|
3328
|
+
var timestampToClusterTimestamp = (timestamp, timescale) => {
|
|
3329
|
+
return Math.round(timestamp / timescale * 1000);
|
|
3330
|
+
};
|
|
3331
|
+
var canFitInCluster = ({
|
|
3332
|
+
clusterStartTimestamp,
|
|
3333
|
+
chunk,
|
|
3334
|
+
timescale
|
|
3335
|
+
}) => {
|
|
3336
|
+
const timecodeRelativeToCluster = timestampToClusterTimestamp(chunk.timestamp, timescale) - timestampToClusterTimestamp(clusterStartTimestamp, timescale);
|
|
3337
|
+
if (timecodeRelativeToCluster < 0) {
|
|
3338
|
+
throw new Error(`timecodeRelativeToCluster is negative, tried to add ${chunk.timestamp} to ${clusterStartTimestamp}`);
|
|
3339
|
+
}
|
|
3340
|
+
return timecodeRelativeToCluster <= maxClusterTimestamp;
|
|
3341
|
+
};
|
|
3342
|
+
var makeCluster = async ({
|
|
3343
|
+
writer,
|
|
3344
|
+
clusterStartTimestamp,
|
|
3345
|
+
timescale,
|
|
3346
|
+
logLevel
|
|
3347
|
+
}) => {
|
|
3348
|
+
Log.verbose(logLevel, `Making new Matroska cluster with timestamp ${clusterStartTimestamp}`);
|
|
3349
|
+
const cluster = createClusterSegment(timestampToClusterTimestamp(clusterStartTimestamp, timescale));
|
|
3350
|
+
const clusterVIntPosition = writer.getWrittenByteCount() + cluster.offsets.offset + matroskaToHex(MediaParserInternals7.matroskaElements.Cluster).byteLength;
|
|
3351
|
+
let clusterSize = cluster.bytes.byteLength - matroskaToHex(MediaParserInternals7.matroskaElements.Cluster).byteLength - CLUSTER_MIN_VINT_WIDTH;
|
|
3352
|
+
await writer.write(cluster.bytes);
|
|
3353
|
+
const addSample = async (chunk, trackNumber) => {
|
|
3354
|
+
const timecodeRelativeToCluster = timestampToClusterTimestamp(chunk.timestamp, timescale) - timestampToClusterTimestamp(clusterStartTimestamp, timescale);
|
|
3355
|
+
if (!canFitInCluster({ clusterStartTimestamp, chunk, timescale })) {
|
|
3356
|
+
throw new Error(`timecodeRelativeToCluster is too big: ${timecodeRelativeToCluster} > ${maxClusterTimestamp}`);
|
|
3357
|
+
}
|
|
3358
|
+
const keyframe = chunk.type === "key";
|
|
3359
|
+
const simpleBlock = makeSimpleBlock({
|
|
3360
|
+
bytes: chunk.data,
|
|
3361
|
+
invisible: false,
|
|
3362
|
+
keyframe,
|
|
3363
|
+
lacing: 0,
|
|
3364
|
+
trackNumber,
|
|
3365
|
+
timecodeRelativeToCluster
|
|
3366
|
+
});
|
|
3367
|
+
clusterSize += simpleBlock.byteLength;
|
|
3368
|
+
await writer.updateDataAt(clusterVIntPosition, getVariableInt(clusterSize, CLUSTER_MIN_VINT_WIDTH));
|
|
3369
|
+
await writer.write(simpleBlock);
|
|
3370
|
+
return { timecodeRelativeToCluster };
|
|
3371
|
+
};
|
|
3372
|
+
const shouldMakeNewCluster = ({
|
|
3373
|
+
isVideo,
|
|
3374
|
+
chunk,
|
|
3375
|
+
newT
|
|
3376
|
+
}) => {
|
|
3377
|
+
const newTimestamp = timestampToClusterTimestamp(newT, timescale);
|
|
3378
|
+
const oldTimestamp = timestampToClusterTimestamp(clusterStartTimestamp, timescale);
|
|
3379
|
+
const canFit = canFitInCluster({
|
|
3380
|
+
chunk,
|
|
3381
|
+
clusterStartTimestamp,
|
|
3382
|
+
timescale
|
|
3383
|
+
});
|
|
3384
|
+
if (!canFit) {
|
|
3385
|
+
Log.verbose(logLevel, `Cannot fit ${chunk.timestamp} in cluster ${clusterStartTimestamp}. Creating new cluster`);
|
|
3386
|
+
return true;
|
|
3387
|
+
}
|
|
3388
|
+
const keyframe = chunk.type === "key";
|
|
3389
|
+
return newTimestamp - oldTimestamp >= 2000 && keyframe && isVideo;
|
|
3390
|
+
};
|
|
3391
|
+
return {
|
|
3392
|
+
addSample,
|
|
3393
|
+
shouldMakeNewCluster,
|
|
3394
|
+
startTimestamp: clusterStartTimestamp
|
|
3395
|
+
};
|
|
3396
|
+
};
|
|
3397
|
+
|
|
3398
|
+
// src/create/matroska/make-duration-with-padding.ts
|
|
3399
|
+
var makeDurationWithPadding = (newDuration) => {
|
|
3400
|
+
return makeMatroskaBytes({
|
|
3401
|
+
type: "Duration",
|
|
3402
|
+
value: {
|
|
3403
|
+
value: newDuration,
|
|
3404
|
+
size: "64"
|
|
3405
|
+
},
|
|
3406
|
+
minVintWidth: 8
|
|
3407
|
+
});
|
|
3408
|
+
};
|
|
3409
|
+
|
|
3410
|
+
// src/create/matroska/matroska-cues.ts
|
|
3411
|
+
var createMatroskaCues = (cues) => {
|
|
3412
|
+
return makeMatroskaBytes({
|
|
3413
|
+
type: "Cues",
|
|
3414
|
+
minVintWidth: null,
|
|
3415
|
+
value: cues.map((cue) => {
|
|
3416
|
+
return {
|
|
3417
|
+
type: "CuePoint",
|
|
3418
|
+
value: [
|
|
3419
|
+
{
|
|
3420
|
+
type: "CueTime",
|
|
3421
|
+
minVintWidth: null,
|
|
3422
|
+
value: {
|
|
3423
|
+
value: cue.time,
|
|
3424
|
+
byteLength: null
|
|
3425
|
+
}
|
|
3426
|
+
},
|
|
3427
|
+
{
|
|
3428
|
+
type: "CueTrackPositions",
|
|
3429
|
+
value: [
|
|
3430
|
+
{
|
|
3431
|
+
type: "CueTrack",
|
|
3432
|
+
minVintWidth: null,
|
|
3433
|
+
value: {
|
|
3434
|
+
value: cue.trackNumber,
|
|
3435
|
+
byteLength: null
|
|
3436
|
+
}
|
|
3437
|
+
},
|
|
3438
|
+
{
|
|
3439
|
+
type: "CueClusterPosition",
|
|
3440
|
+
minVintWidth: null,
|
|
3441
|
+
value: {
|
|
3442
|
+
value: cue.clusterPosition,
|
|
3443
|
+
byteLength: null
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
],
|
|
3447
|
+
minVintWidth: null
|
|
3448
|
+
}
|
|
3449
|
+
],
|
|
3450
|
+
minVintWidth: null
|
|
3451
|
+
};
|
|
3452
|
+
})
|
|
3453
|
+
});
|
|
3454
|
+
};
|
|
3455
|
+
|
|
3456
|
+
// src/create/matroska/matroska-header.ts
|
|
3457
|
+
var makeMatroskaHeader = () => {
|
|
3458
|
+
return makeMatroskaBytes({
|
|
3459
|
+
type: "Header",
|
|
3460
|
+
value: [
|
|
3461
|
+
{
|
|
3462
|
+
minVintWidth: null,
|
|
3463
|
+
type: "EBMLVersion",
|
|
3464
|
+
value: {
|
|
3465
|
+
value: 1,
|
|
3466
|
+
byteLength: null
|
|
3467
|
+
}
|
|
3468
|
+
},
|
|
3469
|
+
{
|
|
3470
|
+
minVintWidth: null,
|
|
3471
|
+
type: "EBMLReadVersion",
|
|
3472
|
+
value: {
|
|
3473
|
+
value: 1,
|
|
3474
|
+
byteLength: null
|
|
3475
|
+
}
|
|
3476
|
+
},
|
|
3477
|
+
{
|
|
3478
|
+
type: "EBMLMaxIDLength",
|
|
3479
|
+
value: {
|
|
3480
|
+
byteLength: null,
|
|
3481
|
+
value: 4
|
|
3482
|
+
},
|
|
3483
|
+
minVintWidth: null
|
|
3484
|
+
},
|
|
3485
|
+
{
|
|
3486
|
+
type: "EBMLMaxSizeLength",
|
|
3487
|
+
value: {
|
|
3488
|
+
byteLength: null,
|
|
3489
|
+
value: 8
|
|
3490
|
+
},
|
|
3491
|
+
minVintWidth: null
|
|
3492
|
+
},
|
|
3493
|
+
{
|
|
3494
|
+
type: "DocType",
|
|
3495
|
+
value: "webm",
|
|
3496
|
+
minVintWidth: null
|
|
3497
|
+
},
|
|
3498
|
+
{
|
|
3499
|
+
type: "DocTypeVersion",
|
|
3500
|
+
value: {
|
|
3501
|
+
byteLength: null,
|
|
3502
|
+
value: 4
|
|
3503
|
+
},
|
|
3504
|
+
minVintWidth: null
|
|
3505
|
+
},
|
|
3506
|
+
{
|
|
3507
|
+
type: "DocTypeReadVersion",
|
|
3508
|
+
value: {
|
|
3509
|
+
byteLength: null,
|
|
3510
|
+
value: 2
|
|
3511
|
+
},
|
|
3512
|
+
minVintWidth: null
|
|
3513
|
+
}
|
|
3514
|
+
],
|
|
3515
|
+
minVintWidth: null
|
|
3516
|
+
});
|
|
3517
|
+
};
|
|
3518
|
+
|
|
3519
|
+
// src/create/matroska/matroska-info.ts
|
|
3520
|
+
var makeMatroskaInfo = ({ timescale }) => {
|
|
3521
|
+
return makeMatroskaBytes({
|
|
3522
|
+
type: "Info",
|
|
3523
|
+
value: [
|
|
3524
|
+
{
|
|
3525
|
+
type: "TimestampScale",
|
|
3526
|
+
value: {
|
|
3527
|
+
value: timescale,
|
|
3528
|
+
byteLength: null
|
|
3529
|
+
},
|
|
3530
|
+
minVintWidth: null
|
|
3531
|
+
},
|
|
3532
|
+
{
|
|
3533
|
+
type: "MuxingApp",
|
|
3534
|
+
value: "@remotion/media-parser",
|
|
3535
|
+
minVintWidth: null
|
|
3536
|
+
},
|
|
3537
|
+
{
|
|
3538
|
+
type: "WritingApp",
|
|
3539
|
+
value: "@remotion/media-parser",
|
|
3540
|
+
minVintWidth: null
|
|
3541
|
+
},
|
|
3542
|
+
makeDurationWithPadding(0)
|
|
3543
|
+
],
|
|
3544
|
+
minVintWidth: null
|
|
3545
|
+
});
|
|
3546
|
+
};
|
|
3547
|
+
|
|
3548
|
+
// src/create/matroska/matroska-seek.ts
|
|
3549
|
+
var createMatroskaSeekHead = (seeks) => {
|
|
3550
|
+
return padMatroskaBytes(makeMatroskaBytes({
|
|
3551
|
+
type: "SeekHead",
|
|
3552
|
+
minVintWidth: null,
|
|
3553
|
+
value: seeks.map((seek) => {
|
|
3554
|
+
return {
|
|
3555
|
+
type: "Seek",
|
|
3556
|
+
minVintWidth: null,
|
|
3557
|
+
value: [
|
|
3558
|
+
{
|
|
3559
|
+
type: "SeekID",
|
|
3560
|
+
minVintWidth: null,
|
|
3561
|
+
value: seek.hexString
|
|
3562
|
+
},
|
|
3563
|
+
{
|
|
3564
|
+
type: "SeekPosition",
|
|
3565
|
+
minVintWidth: null,
|
|
3566
|
+
value: {
|
|
3567
|
+
value: seek.byte,
|
|
3568
|
+
byteLength: null
|
|
3569
|
+
}
|
|
3570
|
+
}
|
|
3571
|
+
]
|
|
3572
|
+
};
|
|
3573
|
+
})
|
|
3574
|
+
}), 200);
|
|
3575
|
+
};
|
|
3576
|
+
|
|
3577
|
+
// src/create/matroska/matroska-segment.ts
|
|
3578
|
+
var MATROSKA_SEGMENT_MIN_VINT_WIDTH = 8;
|
|
3579
|
+
var createMatroskaSegment = (children) => {
|
|
3580
|
+
return makeMatroskaBytes({
|
|
3581
|
+
type: "Segment",
|
|
3582
|
+
value: children,
|
|
3583
|
+
minVintWidth: MATROSKA_SEGMENT_MIN_VINT_WIDTH
|
|
3584
|
+
});
|
|
3585
|
+
};
|
|
3586
|
+
|
|
3587
|
+
// src/create/matroska/color.ts
|
|
3588
|
+
var makeMatroskaColorBytes = ({
|
|
3589
|
+
transferCharacteristics,
|
|
3590
|
+
matrixCoefficients,
|
|
3591
|
+
primaries,
|
|
3592
|
+
fullRange
|
|
3593
|
+
}) => {
|
|
3594
|
+
const rangeValue = transferCharacteristics && matrixCoefficients ? 3 : fullRange === true ? 2 : fullRange === false ? 1 : 0;
|
|
3595
|
+
const primariesValue = primaries === "bt709" ? 1 : primaries === "smpte170m" ? 6 : primaries === "bt470bg" ? 5 : 2;
|
|
3596
|
+
const transferChracteristicsValue = transferCharacteristics === "bt709" ? 1 : transferCharacteristics === "smpte170m" ? 6 : transferCharacteristics === "iec61966-2-1" ? 13 : 2;
|
|
3597
|
+
if (matrixCoefficients === "rgb") {
|
|
3598
|
+
throw new Error("Cannot encode Matroska in RGB");
|
|
3599
|
+
}
|
|
3600
|
+
const matrixCoefficientsValue = matrixCoefficients === "bt709" ? 1 : matrixCoefficients === "bt470bg" ? 5 : matrixCoefficients === "smpte170m" ? 6 : 2;
|
|
3601
|
+
return makeMatroskaBytes({
|
|
3602
|
+
type: "Colour",
|
|
3603
|
+
minVintWidth: null,
|
|
3604
|
+
value: [
|
|
3605
|
+
transferChracteristicsValue === 2 ? null : {
|
|
3606
|
+
type: "TransferCharacteristics",
|
|
3607
|
+
value: {
|
|
3608
|
+
value: transferChracteristicsValue,
|
|
3609
|
+
byteLength: null
|
|
3610
|
+
},
|
|
3611
|
+
minVintWidth: null
|
|
3612
|
+
},
|
|
3613
|
+
matrixCoefficientsValue === 2 ? null : {
|
|
3614
|
+
type: "MatrixCoefficients",
|
|
3615
|
+
value: {
|
|
3616
|
+
value: matrixCoefficientsValue,
|
|
3617
|
+
byteLength: null
|
|
3618
|
+
},
|
|
3619
|
+
minVintWidth: null
|
|
3620
|
+
},
|
|
3621
|
+
primariesValue === 2 ? null : {
|
|
3622
|
+
type: "Primaries",
|
|
3623
|
+
value: {
|
|
3624
|
+
value: primariesValue,
|
|
3625
|
+
byteLength: null
|
|
3626
|
+
},
|
|
3627
|
+
minVintWidth: null
|
|
3628
|
+
},
|
|
3629
|
+
{
|
|
3630
|
+
type: "Range",
|
|
3631
|
+
value: {
|
|
3632
|
+
value: rangeValue,
|
|
3633
|
+
byteLength: null
|
|
3634
|
+
},
|
|
3635
|
+
minVintWidth: null
|
|
3636
|
+
}
|
|
3637
|
+
].filter(truthy)
|
|
3638
|
+
});
|
|
3639
|
+
};
|
|
3640
|
+
|
|
3641
|
+
// src/create/matroska/matroska-trackentry.ts
|
|
3642
|
+
var makeMatroskaVideoBytes = ({
|
|
3643
|
+
color,
|
|
3644
|
+
width,
|
|
3645
|
+
height
|
|
3646
|
+
}) => {
|
|
3647
|
+
return makeMatroskaBytes({
|
|
3648
|
+
type: "Video",
|
|
3649
|
+
value: [
|
|
3650
|
+
{
|
|
3651
|
+
type: "PixelWidth",
|
|
3652
|
+
value: {
|
|
3653
|
+
value: width,
|
|
3654
|
+
byteLength: null
|
|
3655
|
+
},
|
|
3656
|
+
minVintWidth: null
|
|
3657
|
+
},
|
|
3658
|
+
{
|
|
3659
|
+
type: "PixelHeight",
|
|
3660
|
+
value: {
|
|
3661
|
+
value: height,
|
|
3662
|
+
byteLength: null
|
|
3663
|
+
},
|
|
3664
|
+
minVintWidth: null
|
|
3665
|
+
},
|
|
3666
|
+
{
|
|
3667
|
+
type: "FlagInterlaced",
|
|
3668
|
+
value: {
|
|
3669
|
+
value: 2,
|
|
3670
|
+
byteLength: null
|
|
3671
|
+
},
|
|
3672
|
+
minVintWidth: null
|
|
3673
|
+
},
|
|
3674
|
+
makeMatroskaColorBytes(color)
|
|
3675
|
+
],
|
|
3676
|
+
minVintWidth: null
|
|
3677
|
+
});
|
|
3678
|
+
};
|
|
3679
|
+
var makeVideoCodecId = (codecId) => {
|
|
3680
|
+
if (codecId === "vp8") {
|
|
3681
|
+
return "V_VP8";
|
|
3682
|
+
}
|
|
3683
|
+
if (codecId === "vp9") {
|
|
3684
|
+
return "V_VP9";
|
|
3685
|
+
}
|
|
3686
|
+
if (codecId === "h264") {
|
|
3687
|
+
return "V_MPEG4/ISO/AVC";
|
|
3688
|
+
}
|
|
3689
|
+
if (codecId === "av1") {
|
|
3690
|
+
return "V_AV1";
|
|
3691
|
+
}
|
|
3692
|
+
if (codecId === "h265") {
|
|
3693
|
+
return "V_MPEGH/ISO/HEVC";
|
|
3694
|
+
}
|
|
3695
|
+
if (codecId === "prores") {
|
|
3696
|
+
return "V_PRORES";
|
|
3697
|
+
}
|
|
3698
|
+
throw new Error(`Unknown codec: ${codecId}`);
|
|
3699
|
+
};
|
|
3700
|
+
var makeAudioCodecId = (codecId) => {
|
|
3701
|
+
if (codecId === "opus") {
|
|
3702
|
+
return "A_OPUS";
|
|
3703
|
+
}
|
|
3704
|
+
if (codecId === "aac") {
|
|
3705
|
+
return "A_AAC";
|
|
3706
|
+
}
|
|
3707
|
+
if (codecId === "mp3") {
|
|
3708
|
+
return "A_MPEG/L3";
|
|
3709
|
+
}
|
|
3710
|
+
if (codecId === "vorbis") {
|
|
3711
|
+
return "A_VORBIS";
|
|
3712
|
+
}
|
|
3713
|
+
if (codecId === "pcm-u8") {
|
|
3714
|
+
return "A_PCM/INT/LIT";
|
|
3715
|
+
}
|
|
3716
|
+
if (codecId === "pcm-s16") {
|
|
3717
|
+
return "A_PCM/INT/LIT";
|
|
3718
|
+
}
|
|
3719
|
+
if (codecId === "pcm-s24") {
|
|
3720
|
+
return "A_PCM/INT/LIT";
|
|
3721
|
+
}
|
|
3722
|
+
if (codecId === "pcm-s32") {
|
|
3723
|
+
return "A_PCM/INT/LIT";
|
|
3724
|
+
}
|
|
3725
|
+
if (codecId === "pcm-f32") {
|
|
3726
|
+
return "A_PCM/INT/LIT";
|
|
3727
|
+
}
|
|
3728
|
+
if (codecId === "aiff") {
|
|
3729
|
+
throw new Error("aiff is not supported in Matroska");
|
|
3730
|
+
}
|
|
3731
|
+
throw new Error(`Unknown codec: ${codecId}`);
|
|
3732
|
+
};
|
|
3733
|
+
var makeMatroskaAudioTrackEntryBytes = ({
|
|
3734
|
+
trackNumber,
|
|
3735
|
+
codec,
|
|
3736
|
+
numberOfChannels,
|
|
3737
|
+
sampleRate,
|
|
3738
|
+
codecPrivate
|
|
3739
|
+
}) => {
|
|
3740
|
+
return makeMatroskaBytes({
|
|
3741
|
+
type: "TrackEntry",
|
|
3742
|
+
minVintWidth: null,
|
|
3743
|
+
value: [
|
|
3744
|
+
{
|
|
3745
|
+
type: "TrackNumber",
|
|
3746
|
+
value: {
|
|
3747
|
+
value: trackNumber,
|
|
3748
|
+
byteLength: null
|
|
3749
|
+
},
|
|
3750
|
+
minVintWidth: null
|
|
3751
|
+
},
|
|
3752
|
+
{
|
|
3753
|
+
type: "TrackUID",
|
|
3754
|
+
value: "0x188FEB95C8EFABA",
|
|
3755
|
+
minVintWidth: null
|
|
3756
|
+
},
|
|
3757
|
+
{
|
|
3758
|
+
type: "TrackType",
|
|
3759
|
+
value: {
|
|
3760
|
+
value: 2,
|
|
3761
|
+
byteLength: null
|
|
3762
|
+
},
|
|
3763
|
+
minVintWidth: null
|
|
3764
|
+
},
|
|
3765
|
+
{
|
|
3766
|
+
type: "CodecID",
|
|
3767
|
+
value: makeAudioCodecId(codec),
|
|
3768
|
+
minVintWidth: null
|
|
3769
|
+
},
|
|
3770
|
+
{
|
|
3771
|
+
type: "Audio",
|
|
3772
|
+
value: [
|
|
3773
|
+
{
|
|
3774
|
+
type: "Channels",
|
|
3775
|
+
minVintWidth: null,
|
|
3776
|
+
value: {
|
|
3777
|
+
value: numberOfChannels,
|
|
3778
|
+
byteLength: null
|
|
3779
|
+
}
|
|
3780
|
+
},
|
|
3781
|
+
{
|
|
3782
|
+
type: "SamplingFrequency",
|
|
3783
|
+
minVintWidth: null,
|
|
3784
|
+
value: {
|
|
3785
|
+
value: sampleRate,
|
|
3786
|
+
size: "64"
|
|
3787
|
+
}
|
|
3788
|
+
},
|
|
3789
|
+
{
|
|
3790
|
+
type: "BitDepth",
|
|
3791
|
+
minVintWidth: null,
|
|
3792
|
+
value: {
|
|
3793
|
+
value: 32,
|
|
3794
|
+
byteLength: null
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
],
|
|
3798
|
+
minVintWidth: null
|
|
3799
|
+
},
|
|
3800
|
+
codecPrivate ? {
|
|
3801
|
+
type: "CodecPrivate",
|
|
3802
|
+
minVintWidth: null,
|
|
3803
|
+
value: codecPrivate
|
|
3804
|
+
} : null
|
|
3805
|
+
].filter(Boolean)
|
|
3806
|
+
});
|
|
3807
|
+
};
|
|
3808
|
+
var makeMatroskaVideoTrackEntryBytes = ({
|
|
3809
|
+
color,
|
|
3810
|
+
width,
|
|
3811
|
+
height,
|
|
3812
|
+
trackNumber,
|
|
3813
|
+
codec,
|
|
3814
|
+
codecPrivate
|
|
3815
|
+
}) => {
|
|
3816
|
+
return makeMatroskaBytes({
|
|
3817
|
+
type: "TrackEntry",
|
|
3818
|
+
minVintWidth: null,
|
|
3819
|
+
value: [
|
|
3820
|
+
{
|
|
3821
|
+
type: "TrackNumber",
|
|
3822
|
+
value: {
|
|
3823
|
+
value: trackNumber,
|
|
3824
|
+
byteLength: null
|
|
3825
|
+
},
|
|
3826
|
+
minVintWidth: null
|
|
3827
|
+
},
|
|
3828
|
+
{
|
|
3829
|
+
type: "TrackUID",
|
|
3830
|
+
value: "0xab2171012bb9020a",
|
|
3831
|
+
minVintWidth: null
|
|
3832
|
+
},
|
|
3833
|
+
{
|
|
3834
|
+
type: "FlagLacing",
|
|
3835
|
+
value: {
|
|
3836
|
+
value: 0,
|
|
3837
|
+
byteLength: null
|
|
3838
|
+
},
|
|
3839
|
+
minVintWidth: null
|
|
3840
|
+
},
|
|
3841
|
+
{
|
|
3842
|
+
type: "Language",
|
|
3843
|
+
value: "und",
|
|
3844
|
+
minVintWidth: null
|
|
3845
|
+
},
|
|
3846
|
+
{
|
|
3847
|
+
type: "FlagDefault",
|
|
3848
|
+
value: {
|
|
3849
|
+
value: 0,
|
|
3850
|
+
byteLength: null
|
|
3851
|
+
},
|
|
3852
|
+
minVintWidth: null
|
|
3853
|
+
},
|
|
3854
|
+
{
|
|
3855
|
+
type: "CodecID",
|
|
3856
|
+
value: makeVideoCodecId(codec),
|
|
3857
|
+
minVintWidth: null
|
|
3858
|
+
},
|
|
3859
|
+
{
|
|
3860
|
+
type: "TrackType",
|
|
3861
|
+
value: {
|
|
3862
|
+
value: 1,
|
|
3863
|
+
byteLength: null
|
|
3864
|
+
},
|
|
3865
|
+
minVintWidth: null
|
|
3866
|
+
},
|
|
3867
|
+
makeMatroskaVideoBytes({
|
|
3868
|
+
color,
|
|
3869
|
+
width,
|
|
3870
|
+
height
|
|
3871
|
+
}),
|
|
3872
|
+
codecPrivate ? {
|
|
3873
|
+
type: "CodecPrivate",
|
|
3874
|
+
minVintWidth: null,
|
|
3875
|
+
value: codecPrivate
|
|
3876
|
+
} : null
|
|
3877
|
+
].filter(Boolean)
|
|
3878
|
+
});
|
|
3879
|
+
};
|
|
3880
|
+
var makeMatroskaTracks = (tracks) => {
|
|
3881
|
+
const bytesArr = tracks.map((t) => {
|
|
3882
|
+
const bytes = t.type === "video" ? makeMatroskaVideoTrackEntryBytes(t) : makeMatroskaAudioTrackEntryBytes(t);
|
|
3883
|
+
return bytes;
|
|
3884
|
+
});
|
|
3885
|
+
return padMatroskaBytes(makeMatroskaBytes({
|
|
3886
|
+
type: "Tracks",
|
|
3887
|
+
value: bytesArr,
|
|
3888
|
+
minVintWidth: null
|
|
3889
|
+
}), 500);
|
|
3890
|
+
};
|
|
3891
|
+
|
|
3892
|
+
// src/create/matroska/create-matroska-media.ts
|
|
3893
|
+
var { matroskaElements } = MediaParserInternals8;
|
|
3894
|
+
var timescale = 1e6;
|
|
3895
|
+
var createMatroskaMedia = async ({
|
|
3896
|
+
writer,
|
|
3897
|
+
onBytesProgress,
|
|
3898
|
+
onMillisecondsProgress,
|
|
3899
|
+
filename,
|
|
3900
|
+
logLevel,
|
|
3901
|
+
progressTracker
|
|
3902
|
+
}) => {
|
|
3903
|
+
const header = makeMatroskaHeader();
|
|
3904
|
+
const w = await writer.createContent({ filename, mimeType: "video/webm" });
|
|
3905
|
+
await w.write(header.bytes);
|
|
3906
|
+
const matroskaInfo = makeMatroskaInfo({
|
|
3907
|
+
timescale
|
|
3908
|
+
});
|
|
3909
|
+
const currentTracks = [];
|
|
3910
|
+
const seeks = [];
|
|
3911
|
+
const cues = [];
|
|
3912
|
+
const trackNumbers = [];
|
|
3913
|
+
const matroskaSegment = createMatroskaSegment([
|
|
3914
|
+
...createMatroskaSeekHead(seeks),
|
|
3915
|
+
matroskaInfo,
|
|
3916
|
+
...makeMatroskaTracks(currentTracks)
|
|
3917
|
+
]);
|
|
3918
|
+
const infoSegment = matroskaSegment.offsets.children.find((o) => o.field === "Info");
|
|
3919
|
+
const durationOffset = (infoSegment?.children.find((c) => c.field === "Duration")?.offset ?? 0) + w.getWrittenByteCount();
|
|
3920
|
+
const tracksOffset = (matroskaSegment.offsets.children.find((o) => o.field === "Tracks")?.offset ?? 0) + w.getWrittenByteCount();
|
|
3921
|
+
const seekHeadOffset = (matroskaSegment.offsets.children.find((o) => o.field === "SeekHead")?.offset ?? 0) + w.getWrittenByteCount();
|
|
3922
|
+
const infoOffset = (infoSegment?.offset ?? 0) + w.getWrittenByteCount();
|
|
3923
|
+
if (!seekHeadOffset) {
|
|
3924
|
+
throw new Error("could not get seek offset");
|
|
3925
|
+
}
|
|
3926
|
+
if (!durationOffset) {
|
|
3927
|
+
throw new Error("could not get duration offset");
|
|
3928
|
+
}
|
|
3929
|
+
if (!tracksOffset) {
|
|
3930
|
+
throw new Error("could not get tracks offset");
|
|
3931
|
+
}
|
|
3932
|
+
if (!infoOffset) {
|
|
3933
|
+
throw new Error("could not get tracks offset");
|
|
3934
|
+
}
|
|
3935
|
+
seeks.push({
|
|
3936
|
+
hexString: matroskaElements.Info,
|
|
3937
|
+
byte: infoOffset - seekHeadOffset
|
|
3938
|
+
});
|
|
3939
|
+
seeks.push({
|
|
3940
|
+
hexString: matroskaElements.Tracks,
|
|
3941
|
+
byte: tracksOffset - seekHeadOffset
|
|
3942
|
+
});
|
|
3943
|
+
const updateSeekWrite = async () => {
|
|
3944
|
+
const updatedSeek = createMatroskaSeekHead(seeks);
|
|
3945
|
+
await w.updateDataAt(seekHeadOffset, combineUint8Arrays(updatedSeek.map((b) => b.bytes)));
|
|
3946
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3947
|
+
};
|
|
3948
|
+
const segmentOffset = w.getWrittenByteCount();
|
|
3949
|
+
const updateSegmentSize = async (size) => {
|
|
3950
|
+
const data = getVariableInt(size, MATROSKA_SEGMENT_MIN_VINT_WIDTH);
|
|
3951
|
+
await w.updateDataAt(segmentOffset + matroskaToHex(matroskaElements.Segment).byteLength, data);
|
|
3952
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3953
|
+
};
|
|
3954
|
+
await w.write(matroskaSegment.bytes);
|
|
3955
|
+
const clusterOffset = w.getWrittenByteCount();
|
|
3956
|
+
let currentCluster = await makeCluster({
|
|
3957
|
+
writer: w,
|
|
3958
|
+
clusterStartTimestamp: 0,
|
|
3959
|
+
timescale,
|
|
3960
|
+
logLevel
|
|
3961
|
+
});
|
|
3962
|
+
seeks.push({
|
|
3963
|
+
hexString: matroskaElements.Cluster,
|
|
3964
|
+
byte: clusterOffset - seekHeadOffset
|
|
3965
|
+
});
|
|
3966
|
+
const getClusterOrMakeNew = async ({
|
|
3967
|
+
chunk,
|
|
3968
|
+
isVideo
|
|
3969
|
+
}) => {
|
|
3970
|
+
progressTracker.setPossibleLowestTimestamp(Math.min(chunk.timestamp, chunk.cts ?? Infinity, chunk.dts ?? Infinity));
|
|
3971
|
+
const smallestProgress = progressTracker.getSmallestProgress();
|
|
3972
|
+
if (!currentCluster.shouldMakeNewCluster({
|
|
3973
|
+
newT: smallestProgress,
|
|
3974
|
+
isVideo,
|
|
3975
|
+
chunk
|
|
3976
|
+
})) {
|
|
3977
|
+
return { cluster: currentCluster, isNew: false, smallestProgress };
|
|
3978
|
+
}
|
|
3979
|
+
currentCluster = await makeCluster({
|
|
3980
|
+
writer: w,
|
|
3981
|
+
clusterStartTimestamp: smallestProgress,
|
|
3982
|
+
timescale,
|
|
3983
|
+
logLevel
|
|
3984
|
+
});
|
|
3985
|
+
return { cluster: currentCluster, isNew: true, smallestProgress };
|
|
3986
|
+
};
|
|
3987
|
+
const updateDuration = async (newDuration) => {
|
|
3988
|
+
const blocks = makeDurationWithPadding(newDuration);
|
|
3989
|
+
await w.updateDataAt(durationOffset, blocks.bytes);
|
|
3990
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3991
|
+
};
|
|
3992
|
+
const addSample = async ({
|
|
3993
|
+
chunk,
|
|
3994
|
+
trackNumber,
|
|
3995
|
+
isVideo
|
|
3996
|
+
}) => {
|
|
3997
|
+
const { cluster, isNew, smallestProgress } = await getClusterOrMakeNew({
|
|
3998
|
+
chunk,
|
|
3999
|
+
isVideo
|
|
4000
|
+
});
|
|
4001
|
+
const newDuration = Math.round((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
4002
|
+
await updateDuration(newDuration);
|
|
4003
|
+
const { timecodeRelativeToCluster } = await cluster.addSample(chunk, trackNumber);
|
|
4004
|
+
if (isNew) {
|
|
4005
|
+
const newCluster = w.getWrittenByteCount();
|
|
4006
|
+
cues.push({
|
|
4007
|
+
time: timestampToClusterTimestamp(smallestProgress, timescale) + timecodeRelativeToCluster,
|
|
4008
|
+
clusterPosition: newCluster - seekHeadOffset,
|
|
4009
|
+
trackNumber
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
4012
|
+
if (chunk.type === "key") {
|
|
4013
|
+
progressTracker.updateTrackProgress(trackNumber, chunk.timestamp);
|
|
4014
|
+
}
|
|
4015
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
4016
|
+
onMillisecondsProgress(newDuration);
|
|
4017
|
+
};
|
|
4018
|
+
const addTrack = async (track) => {
|
|
4019
|
+
currentTracks.push(track);
|
|
4020
|
+
const newTracks = makeMatroskaTracks(currentTracks);
|
|
4021
|
+
progressTracker.registerTrack(track.trackNumber);
|
|
4022
|
+
await w.updateDataAt(tracksOffset, combineUint8Arrays(newTracks.map((b) => b.bytes)));
|
|
4023
|
+
};
|
|
4024
|
+
const operationProm = { current: Promise.resolve() };
|
|
4025
|
+
const waitForFinishPromises = [];
|
|
4026
|
+
return {
|
|
4027
|
+
updateTrackSampleRate: ({ sampleRate, trackNumber }) => {
|
|
4028
|
+
currentTracks.forEach((track) => {
|
|
4029
|
+
if (track.trackNumber === trackNumber) {
|
|
4030
|
+
if (track.type !== "audio") {
|
|
4031
|
+
throw new Error("track is not audio");
|
|
4032
|
+
}
|
|
4033
|
+
track.sampleRate = sampleRate;
|
|
4034
|
+
}
|
|
4035
|
+
});
|
|
4036
|
+
},
|
|
4037
|
+
save: () => {
|
|
4038
|
+
return w.save();
|
|
4039
|
+
},
|
|
4040
|
+
remove: async () => {
|
|
4041
|
+
await w.remove();
|
|
4042
|
+
},
|
|
4043
|
+
addSample: ({ chunk, trackNumber, isVideo }) => {
|
|
4044
|
+
operationProm.current = operationProm.current.then(() => addSample({ chunk, trackNumber, isVideo }));
|
|
4045
|
+
return operationProm.current;
|
|
4046
|
+
},
|
|
4047
|
+
addTrack: (track) => {
|
|
4048
|
+
const trackNumber = currentTracks.length + 1;
|
|
4049
|
+
operationProm.current = operationProm.current.then(() => addTrack({ ...track, trackNumber }));
|
|
4050
|
+
trackNumbers.push(trackNumber);
|
|
4051
|
+
return operationProm.current.then(() => ({ trackNumber }));
|
|
4052
|
+
},
|
|
4053
|
+
addWaitForFinishPromise: (promise) => {
|
|
4054
|
+
waitForFinishPromises.push(promise);
|
|
4055
|
+
},
|
|
4056
|
+
async waitForFinish() {
|
|
4057
|
+
await Promise.all(waitForFinishPromises.map((p) => p()));
|
|
4058
|
+
await operationProm.current;
|
|
4059
|
+
seeks.push({
|
|
4060
|
+
hexString: matroskaElements.Cues,
|
|
4061
|
+
byte: w.getWrittenByteCount() - seekHeadOffset
|
|
4062
|
+
});
|
|
4063
|
+
await updateSeekWrite();
|
|
4064
|
+
await w.write(createMatroskaCues(cues).bytes);
|
|
4065
|
+
await w.waitForFinish();
|
|
4066
|
+
const segmentSize = w.getWrittenByteCount() - segmentOffset - matroskaToHex(matroskaElements.Segment).byteLength - MATROSKA_SEGMENT_MIN_VINT_WIDTH;
|
|
4067
|
+
await updateSegmentSize(segmentSize);
|
|
4068
|
+
}
|
|
4069
|
+
};
|
|
4070
|
+
};
|
|
4071
|
+
|
|
4072
|
+
// src/create/wav/create-wav.ts
|
|
4073
|
+
var numberTo32BiIntLittleEndian = (num) => {
|
|
4074
|
+
return new Uint8Array([
|
|
4075
|
+
num & 255,
|
|
4076
|
+
num >> 8 & 255,
|
|
4077
|
+
num >> 16 & 255,
|
|
4078
|
+
num >> 24 & 255
|
|
4079
|
+
]);
|
|
4080
|
+
};
|
|
4081
|
+
var numberTo16BitLittleEndian = (num) => {
|
|
4082
|
+
return new Uint8Array([num & 255, num >> 8 & 255]);
|
|
4083
|
+
};
|
|
4084
|
+
var BIT_DEPTH = 16;
|
|
4085
|
+
var BYTES_PER_SAMPLE = BIT_DEPTH / 8;
|
|
4086
|
+
var createWav = async ({
|
|
4087
|
+
filename,
|
|
4088
|
+
logLevel,
|
|
4089
|
+
onBytesProgress,
|
|
4090
|
+
onMillisecondsProgress,
|
|
4091
|
+
writer,
|
|
4092
|
+
progressTracker
|
|
4093
|
+
}) => {
|
|
4094
|
+
const w = await writer.createContent({ filename, mimeType: "audio/wav" });
|
|
4095
|
+
await w.write(new Uint8Array([82, 73, 70, 70]));
|
|
4096
|
+
const sizePosition = w.getWrittenByteCount();
|
|
4097
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
4098
|
+
await w.write(new Uint8Array([87, 65, 86, 69]));
|
|
4099
|
+
await w.write(new Uint8Array([102, 109, 116, 32]));
|
|
4100
|
+
await w.write(new Uint8Array([16, 0, 0, 0]));
|
|
4101
|
+
await w.write(new Uint8Array([1, 0]));
|
|
4102
|
+
const channelNumPosition = w.getWrittenByteCount();
|
|
4103
|
+
await w.write(new Uint8Array([1, 0]));
|
|
4104
|
+
const sampleRatePosition = w.getWrittenByteCount();
|
|
4105
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
4106
|
+
const byteRatePosition = w.getWrittenByteCount();
|
|
4107
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
4108
|
+
const blockAlignPosition = w.getWrittenByteCount();
|
|
4109
|
+
await w.write(new Uint8Array([0, 0]));
|
|
4110
|
+
await w.write(numberTo16BitLittleEndian(BIT_DEPTH));
|
|
4111
|
+
await w.write(new Uint8Array([100, 97, 116, 97]));
|
|
4112
|
+
const dataSizePosition = w.getWrittenByteCount();
|
|
4113
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
4114
|
+
const operationProm = { current: Promise.resolve() };
|
|
4115
|
+
const updateSize = async () => {
|
|
4116
|
+
const size = w.getWrittenByteCount() - sizePosition - 4;
|
|
4117
|
+
await w.updateDataAt(sizePosition, numberTo32BiIntLittleEndian(size));
|
|
4118
|
+
const dataSize = w.getWrittenByteCount() - dataSizePosition - 4;
|
|
4119
|
+
await w.updateDataAt(dataSizePosition, numberTo32BiIntLittleEndian(dataSize));
|
|
4120
|
+
};
|
|
4121
|
+
const updateChannelNum = async (numberOfChannels) => {
|
|
4122
|
+
await w.updateDataAt(channelNumPosition, new Uint8Array([numberOfChannels, 0]));
|
|
4123
|
+
};
|
|
4124
|
+
const updateSampleRate = async (sampleRate) => {
|
|
4125
|
+
await w.updateDataAt(sampleRatePosition, numberTo32BiIntLittleEndian(sampleRate));
|
|
4126
|
+
};
|
|
4127
|
+
const updateByteRate = async ({
|
|
4128
|
+
sampleRate,
|
|
4129
|
+
numberOfChannels
|
|
4130
|
+
}) => {
|
|
4131
|
+
await w.updateDataAt(byteRatePosition, numberTo32BiIntLittleEndian(sampleRate * numberOfChannels + BYTES_PER_SAMPLE));
|
|
4132
|
+
};
|
|
4133
|
+
const updateBlockAlign = async (numberOfChannels) => {
|
|
4134
|
+
await w.updateDataAt(blockAlignPosition, new Uint8Array(numberTo16BitLittleEndian(numberOfChannels * BYTES_PER_SAMPLE)));
|
|
4135
|
+
};
|
|
4136
|
+
const addSample = async (chunk) => {
|
|
4137
|
+
Log.verbose(logLevel, "Adding sample", chunk);
|
|
4138
|
+
await w.write(chunk.data);
|
|
4139
|
+
onMillisecondsProgress((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
4140
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
4141
|
+
};
|
|
4142
|
+
const waitForFinishPromises = [];
|
|
4143
|
+
return {
|
|
4144
|
+
save: () => {
|
|
4145
|
+
return w.save();
|
|
4146
|
+
},
|
|
4147
|
+
remove: () => {
|
|
4148
|
+
return w.remove();
|
|
4149
|
+
},
|
|
4150
|
+
addSample: ({ chunk, trackNumber }) => {
|
|
4151
|
+
if (trackNumber !== 1) {
|
|
4152
|
+
throw new Error("Only one track supported for WAV");
|
|
4153
|
+
}
|
|
4154
|
+
operationProm.current = operationProm.current.then(() => addSample(chunk));
|
|
4155
|
+
progressTracker.updateTrackProgress(trackNumber, chunk.timestamp);
|
|
4156
|
+
return operationProm.current;
|
|
4157
|
+
},
|
|
4158
|
+
updateTrackSampleRate: () => {
|
|
4159
|
+
throw new Error("updateTrackSampleRate() not implemented for WAV encoder");
|
|
4160
|
+
},
|
|
4161
|
+
addWaitForFinishPromise: (promise) => {
|
|
4162
|
+
waitForFinishPromises.push(promise);
|
|
4163
|
+
},
|
|
4164
|
+
async waitForFinish() {
|
|
4165
|
+
Log.verbose(logLevel, "All write operations queued. Waiting for finish...");
|
|
4166
|
+
await Promise.all(waitForFinishPromises.map((p) => p()));
|
|
4167
|
+
await operationProm.current;
|
|
4168
|
+
await updateSize();
|
|
4169
|
+
await w.waitForFinish();
|
|
4170
|
+
},
|
|
4171
|
+
addTrack: async (track) => {
|
|
4172
|
+
if (track.type !== "audio") {
|
|
4173
|
+
throw new Error("Only audio tracks supported for WAV");
|
|
4174
|
+
}
|
|
4175
|
+
await updateChannelNum(track.numberOfChannels);
|
|
4176
|
+
await updateSampleRate(track.sampleRate);
|
|
4177
|
+
await updateByteRate({
|
|
4178
|
+
sampleRate: track.sampleRate,
|
|
4179
|
+
numberOfChannels: track.numberOfChannels
|
|
4180
|
+
});
|
|
4181
|
+
await updateBlockAlign(track.numberOfChannels);
|
|
4182
|
+
progressTracker.registerTrack(1);
|
|
4183
|
+
return Promise.resolve({ trackNumber: 1 });
|
|
4184
|
+
}
|
|
4185
|
+
};
|
|
4186
|
+
};
|
|
4187
|
+
|
|
4188
|
+
// src/select-container-creator.ts
|
|
1711
4189
|
var selectContainerCreator = (container) => {
|
|
1712
4190
|
if (container === "mp4") {
|
|
1713
|
-
return
|
|
4191
|
+
return createIsoBaseMedia;
|
|
1714
4192
|
}
|
|
1715
4193
|
if (container === "wav") {
|
|
1716
|
-
return
|
|
4194
|
+
return createWav;
|
|
1717
4195
|
}
|
|
1718
4196
|
if (container === "webm") {
|
|
1719
|
-
return
|
|
4197
|
+
return createMatroskaMedia;
|
|
1720
4198
|
}
|
|
1721
4199
|
throw new Error(`Unsupported container: ${container}`);
|
|
1722
4200
|
};
|
|
@@ -1821,7 +4299,7 @@ var convertMedia = async function({
|
|
|
1821
4299
|
if (videoCodec && videoCodec !== "vp8" && videoCodec !== "vp9") {
|
|
1822
4300
|
return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
|
|
1823
4301
|
}
|
|
1824
|
-
const { resolve, reject, getPromiseToImmediatelyReturn } =
|
|
4302
|
+
const { resolve, reject, getPromiseToImmediatelyReturn } = withResolversAndWaitForReturn();
|
|
1825
4303
|
const controller = new AbortController;
|
|
1826
4304
|
const abortConversion = (errCause) => {
|
|
1827
4305
|
reject(errCause);
|
|
@@ -1839,7 +4317,7 @@ var convertMedia = async function({
|
|
|
1839
4317
|
everyMilliseconds: progressIntervalInMs ?? 100,
|
|
1840
4318
|
signal: controller.signal
|
|
1841
4319
|
});
|
|
1842
|
-
const progressTracker =
|
|
4320
|
+
const progressTracker = makeProgressTracker();
|
|
1843
4321
|
const state = await creator({
|
|
1844
4322
|
filename: generateOutputFilename(src, container),
|
|
1845
4323
|
writer: await autoSelectWriter(writer, logLevel),
|