@remotion/webcodecs 4.0.231 → 4.0.233
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/README.md +2 -2
- package/dist/audio-decoder-config.d.ts +2 -1
- package/dist/audio-decoder-config.js +44 -3
- package/dist/audio-decoder.d.ts +6 -3
- package/dist/audio-decoder.js +26 -4
- package/dist/audio-encoder-config.d.ts +4 -1
- package/dist/audio-encoder-config.js +6 -0
- package/dist/audio-encoder.d.ts +6 -4
- package/dist/audio-encoder.js +15 -3
- package/dist/browser-quirks.d.ts +1 -0
- package/dist/browser-quirks.js +5 -1
- package/dist/can-copy-audio-track.d.ts +1 -1
- package/dist/can-copy-audio-track.js +3 -0
- package/dist/can-copy-video-track.d.ts +4 -2
- package/dist/can-copy-video-track.js +10 -2
- package/dist/can-reencode-audio-track.d.ts +4 -3
- package/dist/can-reencode-audio-track.js +5 -2
- package/dist/can-reencode-video-track.d.ts +1 -1
- package/dist/codec-id.d.ts +2 -2
- package/dist/codec-id.js +8 -2
- package/dist/convert-media.d.ts +5 -2
- package/dist/convert-media.js +11 -8
- package/dist/convert-to-correct-videoframe.d.ts +1 -1
- package/dist/convert-to-correct-videoframe.js +8 -0
- package/dist/default-on-video-track-handler.js +12 -2
- package/dist/esm/index.mjs +463 -160
- package/dist/generate-output-filename.d.ts +1 -1
- package/dist/get-available-audio-codecs.d.ts +7 -0
- package/dist/get-available-audio-codecs.js +18 -0
- package/dist/get-available-containers.d.ts +4 -0
- package/dist/get-available-containers.js +8 -0
- package/dist/get-available-video-codecs.d.ts +7 -0
- package/dist/get-available-video-codecs.js +18 -0
- package/dist/get-default-audio-codec.d.ts +2 -1
- package/dist/get-default-audio-codec.js +3 -0
- package/dist/get-default-video-codec.d.ts +3 -2
- package/dist/get-default-video-codec.js +7 -1
- package/dist/get-wave-audio-decoder.d.ts +2 -0
- package/dist/get-wave-audio-decoder.js +29 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +12 -5
- package/dist/io-manager/event-emitter.d.ts +4 -0
- package/dist/io-manager/event-emitter.js +1 -0
- package/dist/io-manager/io-synchronizer.d.ts +8 -2
- package/dist/io-manager/io-synchronizer.js +31 -14
- package/dist/io-manager/make-timeout-promise.d.ts +4 -0
- package/dist/io-manager/make-timeout-promise.js +18 -0
- package/dist/on-audio-track-handler.d.ts +2 -1
- package/dist/on-audio-track.d.ts +5 -3
- package/dist/on-audio-track.js +9 -4
- package/dist/on-frame.d.ts +3 -2
- package/dist/on-frame.js +24 -19
- package/dist/on-video-track-handler.d.ts +4 -1
- package/dist/on-video-track.d.ts +6 -3
- package/dist/on-video-track.js +20 -5
- package/dist/rotate-video-frame.d.ts +5 -0
- package/dist/rotate-video-frame.js +48 -0
- package/dist/rotate-video.d.ts +4 -0
- package/dist/rotate-video.js +43 -0
- package/dist/rotation.d.ts +8 -0
- package/dist/rotation.js +10 -0
- package/dist/select-container-creator.d.ts +2 -0
- package/dist/select-container-creator.js +17 -0
- package/dist/test/avi-to-mp4.test.js +15 -0
- package/dist/video-decoder.d.ts +3 -2
- package/dist/video-decoder.js +11 -3
- package/dist/video-encoder-config.d.ts +1 -1
- package/dist/video-encoder.d.ts +4 -3
- package/dist/video-encoder.js +7 -2
- package/dist/wav-audio-encoder.d.ts +2 -0
- package/dist/wav-audio-encoder.js +26 -0
- package/package.json +5 -3
package/dist/esm/index.mjs
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
|
+
// src/rotation.ts
|
|
2
|
+
var calculateNewDimensionsFromDimensions = ({
|
|
3
|
+
width,
|
|
4
|
+
height,
|
|
5
|
+
rotation
|
|
6
|
+
}) => {
|
|
7
|
+
const switchDimensions = rotation % 90 === 0 && rotation % 180 !== 0;
|
|
8
|
+
const newHeight = switchDimensions ? width : height;
|
|
9
|
+
const newWidth = switchDimensions ? height : width;
|
|
10
|
+
return { height: newHeight, width: newWidth };
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/rotate-video-frame.ts
|
|
14
|
+
var normalizeVideoRotation = (rotation) => {
|
|
15
|
+
return (rotation % 360 + 360) % 360;
|
|
16
|
+
};
|
|
17
|
+
var rotateVideoFrame = ({
|
|
18
|
+
frame,
|
|
19
|
+
rotation
|
|
20
|
+
}) => {
|
|
21
|
+
const normalized = (rotation % 360 + 360) % 360;
|
|
22
|
+
if (normalized % 360 === 0) {
|
|
23
|
+
return frame;
|
|
24
|
+
}
|
|
25
|
+
if (normalized % 90 !== 0) {
|
|
26
|
+
throw new Error("Only 90 degree rotations are supported");
|
|
27
|
+
}
|
|
28
|
+
const { height, width } = calculateNewDimensionsFromDimensions({
|
|
29
|
+
height: frame.displayHeight,
|
|
30
|
+
width: frame.displayWidth,
|
|
31
|
+
rotation
|
|
32
|
+
});
|
|
33
|
+
const canvas = new OffscreenCanvas(width, height);
|
|
34
|
+
const ctx = canvas.getContext("2d");
|
|
35
|
+
if (!ctx) {
|
|
36
|
+
throw new Error("Could not get 2d context");
|
|
37
|
+
}
|
|
38
|
+
canvas.width = width;
|
|
39
|
+
canvas.height = height;
|
|
40
|
+
if (normalized === 90) {
|
|
41
|
+
ctx.translate(width, 0);
|
|
42
|
+
} else if (normalized === 180) {
|
|
43
|
+
ctx.translate(width, height);
|
|
44
|
+
} else if (normalized === 270) {
|
|
45
|
+
ctx.translate(0, height);
|
|
46
|
+
}
|
|
47
|
+
ctx.rotate(normalized * (Math.PI / 180));
|
|
48
|
+
ctx.drawImage(frame, 0, 0);
|
|
49
|
+
return new VideoFrame(canvas, {
|
|
50
|
+
displayHeight: height,
|
|
51
|
+
displayWidth: width,
|
|
52
|
+
duration: frame.duration ?? undefined,
|
|
53
|
+
timestamp: frame.timestamp
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
1
57
|
// src/set-remotion-imported.ts
|
|
2
58
|
import { VERSION } from "@remotion/media-parser";
|
|
3
59
|
var setRemotionImported = () => {
|
|
@@ -13,58 +69,65 @@ var setRemotionImported = () => {
|
|
|
13
69
|
}
|
|
14
70
|
};
|
|
15
71
|
|
|
16
|
-
// src/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const { promise: returnPromise, resolve: resolveReturn } = withResolvers();
|
|
72
|
+
// src/get-wave-audio-decoder.ts
|
|
73
|
+
var getWaveAudioDecoder = ({
|
|
74
|
+
onFrame,
|
|
75
|
+
track
|
|
76
|
+
}) => {
|
|
77
|
+
let queue = Promise.resolve();
|
|
78
|
+
const processSample = async (audioSample) => {
|
|
79
|
+
await onFrame(new AudioData({
|
|
80
|
+
data: audioSample.data,
|
|
81
|
+
format: "s16",
|
|
82
|
+
numberOfChannels: track.numberOfChannels,
|
|
83
|
+
numberOfFrames: audioSample.data.byteLength / 2,
|
|
84
|
+
sampleRate: track.sampleRate,
|
|
85
|
+
timestamp: audioSample.timestamp
|
|
86
|
+
}));
|
|
87
|
+
};
|
|
33
88
|
return {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return promise;
|
|
89
|
+
close() {
|
|
90
|
+
return Promise.resolve();
|
|
37
91
|
},
|
|
38
|
-
|
|
39
|
-
|
|
92
|
+
processSample(audioSample) {
|
|
93
|
+
queue = queue.then(() => processSample(audioSample));
|
|
94
|
+
return queue;
|
|
40
95
|
},
|
|
41
|
-
resolve
|
|
96
|
+
flush: () => Promise.resolve(),
|
|
97
|
+
waitForFinish: () => Promise.resolve()
|
|
42
98
|
};
|
|
43
99
|
};
|
|
44
100
|
|
|
45
|
-
// src/io-manager/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
101
|
+
// src/io-manager/io-synchronizer.ts
|
|
102
|
+
import { MediaParserInternals as MediaParserInternals3 } from "@remotion/media-parser";
|
|
103
|
+
|
|
104
|
+
// src/log.ts
|
|
105
|
+
import { MediaParserInternals } from "@remotion/media-parser";
|
|
106
|
+
var { Log } = MediaParserInternals;
|
|
107
|
+
|
|
108
|
+
// src/io-manager/make-timeout-promise.ts
|
|
109
|
+
import { MediaParserInternals as MediaParserInternals2 } from "@remotion/media-parser";
|
|
110
|
+
var makeTimeoutPromise = (label, ms) => {
|
|
111
|
+
const { promise, reject, resolve } = MediaParserInternals2.withResolvers();
|
|
112
|
+
const timeout = setTimeout(() => {
|
|
113
|
+
reject(new Error(`${label} (timed out after ${ms}ms)`));
|
|
114
|
+
}, ms);
|
|
115
|
+
return {
|
|
116
|
+
timeoutPromise: promise,
|
|
117
|
+
clear: () => {
|
|
118
|
+
clearTimeout(timeout);
|
|
119
|
+
resolve();
|
|
120
|
+
}
|
|
51
121
|
};
|
|
52
|
-
|
|
53
|
-
this.listeners[name].push(callback);
|
|
54
|
-
}
|
|
55
|
-
removeEventListener(name, callback) {
|
|
56
|
-
this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
|
|
57
|
-
}
|
|
58
|
-
dispatchEvent(dispatchName, context) {
|
|
59
|
-
this.listeners[dispatchName].forEach((callback) => {
|
|
60
|
-
callback({ detail: context });
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
122
|
+
};
|
|
64
123
|
|
|
65
124
|
// src/io-manager/io-synchronizer.ts
|
|
66
|
-
var makeIoSynchronizer = (
|
|
67
|
-
|
|
125
|
+
var makeIoSynchronizer = ({
|
|
126
|
+
logLevel,
|
|
127
|
+
label,
|
|
128
|
+
progress
|
|
129
|
+
}) => {
|
|
130
|
+
const eventEmitter = new MediaParserInternals3.IoEventEmitter;
|
|
68
131
|
let lastInput = 0;
|
|
69
132
|
let lastInputKeyframe = 0;
|
|
70
133
|
let lastOutput = 0;
|
|
@@ -108,7 +171,7 @@ var makeIoSynchronizer = (logLevel, label) => {
|
|
|
108
171
|
printState("Got output");
|
|
109
172
|
};
|
|
110
173
|
const waitForOutput = () => {
|
|
111
|
-
const { promise, resolve } = withResolvers();
|
|
174
|
+
const { promise, resolve } = MediaParserInternals3.withResolvers();
|
|
112
175
|
const on = () => {
|
|
113
176
|
eventEmitter.removeEventListener("output", on);
|
|
114
177
|
resolve();
|
|
@@ -117,7 +180,7 @@ var makeIoSynchronizer = (logLevel, label) => {
|
|
|
117
180
|
return promise;
|
|
118
181
|
};
|
|
119
182
|
const waitForProcessed = () => {
|
|
120
|
-
const { promise, resolve } = withResolvers();
|
|
183
|
+
const { promise, resolve } = MediaParserInternals3.withResolvers();
|
|
121
184
|
const on = () => {
|
|
122
185
|
eventEmitter.removeEventListener("processed", on);
|
|
123
186
|
resolve();
|
|
@@ -127,17 +190,33 @@ var makeIoSynchronizer = (logLevel, label) => {
|
|
|
127
190
|
};
|
|
128
191
|
const waitFor = async ({
|
|
129
192
|
_unprocessed,
|
|
130
|
-
unemitted
|
|
193
|
+
unemitted,
|
|
194
|
+
minimumProgress
|
|
131
195
|
}) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
196
|
+
const { timeoutPromise, clear } = makeTimeoutPromise(`Waited too long for ${label}`, 1e4);
|
|
197
|
+
await Promise.race([
|
|
198
|
+
timeoutPromise,
|
|
199
|
+
Promise.all([
|
|
200
|
+
(async () => {
|
|
201
|
+
while (getUnemittedItems() > unemitted) {
|
|
202
|
+
await waitForOutput();
|
|
203
|
+
}
|
|
204
|
+
})(),
|
|
205
|
+
(async () => {
|
|
206
|
+
while (getUnprocessed() > _unprocessed) {
|
|
207
|
+
await waitForProcessed();
|
|
208
|
+
}
|
|
209
|
+
})(),
|
|
210
|
+
minimumProgress === null ? Promise.resolve() : (async () => {
|
|
211
|
+
while (progress.getSmallestProgress() < minimumProgress) {
|
|
212
|
+
await progress.waitForProgress();
|
|
213
|
+
}
|
|
214
|
+
})()
|
|
215
|
+
])
|
|
216
|
+
]).finally(() => clear());
|
|
138
217
|
};
|
|
139
218
|
const waitForFinish = async () => {
|
|
140
|
-
await waitFor({ _unprocessed: 0, unemitted: 0 });
|
|
219
|
+
await waitFor({ _unprocessed: 0, unemitted: 0, minimumProgress: null });
|
|
141
220
|
};
|
|
142
221
|
const onProcessed = () => {
|
|
143
222
|
eventEmitter.dispatchEvent("processed", {});
|
|
@@ -159,12 +238,21 @@ var createAudioDecoder = ({
|
|
|
159
238
|
onError,
|
|
160
239
|
signal,
|
|
161
240
|
config,
|
|
162
|
-
logLevel
|
|
241
|
+
logLevel,
|
|
242
|
+
track,
|
|
243
|
+
progressTracker
|
|
163
244
|
}) => {
|
|
164
245
|
if (signal.aborted) {
|
|
165
246
|
throw new Error("Not creating audio decoder, already aborted");
|
|
166
247
|
}
|
|
167
|
-
|
|
248
|
+
if (config.codec === "pcm-s16") {
|
|
249
|
+
return getWaveAudioDecoder({ onFrame, track });
|
|
250
|
+
}
|
|
251
|
+
const ioSynchronizer = makeIoSynchronizer({
|
|
252
|
+
logLevel,
|
|
253
|
+
label: "Audio decoder",
|
|
254
|
+
progress: progressTracker
|
|
255
|
+
});
|
|
168
256
|
let outputQueue = Promise.resolve();
|
|
169
257
|
const audioDecoder = new AudioDecoder({
|
|
170
258
|
output(inputFrame) {
|
|
@@ -207,7 +295,11 @@ var createAudioDecoder = ({
|
|
|
207
295
|
if (audioDecoder.state === "closed") {
|
|
208
296
|
return;
|
|
209
297
|
}
|
|
210
|
-
await ioSynchronizer.waitFor({
|
|
298
|
+
await ioSynchronizer.waitFor({
|
|
299
|
+
unemitted: 20,
|
|
300
|
+
_unprocessed: 20,
|
|
301
|
+
minimumProgress: audioSample.timestamp - 1e7
|
|
302
|
+
});
|
|
211
303
|
const chunk = new EncodedAudioChunk(audioSample);
|
|
212
304
|
audioDecoder.decode(chunk);
|
|
213
305
|
ioSynchronizer.inputItem(chunk.timestamp, audioSample.type === "key");
|
|
@@ -215,11 +307,18 @@ var createAudioDecoder = ({
|
|
|
215
307
|
let queue = Promise.resolve();
|
|
216
308
|
return {
|
|
217
309
|
processSample: (sample) => {
|
|
310
|
+
if (sample.data.length === 0) {
|
|
311
|
+
return queue;
|
|
312
|
+
}
|
|
218
313
|
queue = queue.then(() => processSample(sample));
|
|
219
314
|
return queue;
|
|
220
315
|
},
|
|
221
316
|
waitForFinish: async () => {
|
|
222
|
-
|
|
317
|
+
try {
|
|
318
|
+
await audioDecoder.flush();
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
await queue;
|
|
223
322
|
await ioSynchronizer.waitForFinish();
|
|
224
323
|
await outputQueue;
|
|
225
324
|
},
|
|
@@ -229,6 +328,33 @@ var createAudioDecoder = ({
|
|
|
229
328
|
}
|
|
230
329
|
};
|
|
231
330
|
};
|
|
331
|
+
// src/wav-audio-encoder.ts
|
|
332
|
+
var getWaveAudioEncoder = ({
|
|
333
|
+
onChunk,
|
|
334
|
+
signal
|
|
335
|
+
}) => {
|
|
336
|
+
return {
|
|
337
|
+
close: () => {
|
|
338
|
+
return Promise.resolve();
|
|
339
|
+
},
|
|
340
|
+
encodeFrame: (audioData) => {
|
|
341
|
+
if (signal.aborted) {
|
|
342
|
+
return Promise.resolve();
|
|
343
|
+
}
|
|
344
|
+
const chunk = {
|
|
345
|
+
timestamp: audioData.timestamp,
|
|
346
|
+
duration: audioData.duration,
|
|
347
|
+
type: "key",
|
|
348
|
+
copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0, format: "s16" }),
|
|
349
|
+
byteLength: audioData.allocationSize({ planeIndex: 0, format: "s16" })
|
|
350
|
+
};
|
|
351
|
+
return onChunk(chunk);
|
|
352
|
+
},
|
|
353
|
+
flush: () => Promise.resolve(),
|
|
354
|
+
waitForFinish: () => Promise.resolve()
|
|
355
|
+
};
|
|
356
|
+
};
|
|
357
|
+
|
|
232
358
|
// src/audio-encoder.ts
|
|
233
359
|
var createAudioEncoder = ({
|
|
234
360
|
onChunk,
|
|
@@ -237,12 +363,20 @@ var createAudioEncoder = ({
|
|
|
237
363
|
signal,
|
|
238
364
|
config: audioEncoderConfig,
|
|
239
365
|
logLevel,
|
|
240
|
-
onNewAudioSampleRate
|
|
366
|
+
onNewAudioSampleRate,
|
|
367
|
+
progressTracker
|
|
241
368
|
}) => {
|
|
242
369
|
if (signal.aborted) {
|
|
243
370
|
throw new Error("Not creating audio encoder, already aborted");
|
|
244
371
|
}
|
|
245
|
-
|
|
372
|
+
if (codec === "wav") {
|
|
373
|
+
return getWaveAudioEncoder({ onChunk, signal });
|
|
374
|
+
}
|
|
375
|
+
const ioSynchronizer = makeIoSynchronizer({
|
|
376
|
+
logLevel,
|
|
377
|
+
label: "Audio encoder",
|
|
378
|
+
progress: progressTracker
|
|
379
|
+
});
|
|
246
380
|
let prom = Promise.resolve();
|
|
247
381
|
const encoder = new AudioEncoder({
|
|
248
382
|
output: (chunk) => {
|
|
@@ -282,7 +416,11 @@ var createAudioEncoder = ({
|
|
|
282
416
|
if (encoder.state === "closed") {
|
|
283
417
|
return;
|
|
284
418
|
}
|
|
285
|
-
await ioSynchronizer.waitFor({
|
|
419
|
+
await ioSynchronizer.waitFor({
|
|
420
|
+
unemitted: 20,
|
|
421
|
+
_unprocessed: 20,
|
|
422
|
+
minimumProgress: audioData.timestamp - 1e7
|
|
423
|
+
});
|
|
286
424
|
if (encoder.state === "closed") {
|
|
287
425
|
return;
|
|
288
426
|
}
|
|
@@ -328,31 +466,94 @@ var canCopyAudioTrack = ({
|
|
|
328
466
|
if (container === "mp4") {
|
|
329
467
|
return inputCodec === "aac";
|
|
330
468
|
}
|
|
469
|
+
if (container === "wav") {
|
|
470
|
+
return false;
|
|
471
|
+
}
|
|
331
472
|
throw new Error(`Unhandled codec: ${container}`);
|
|
332
473
|
};
|
|
333
474
|
// src/can-copy-video-track.ts
|
|
334
475
|
var canCopyVideoTrack = ({
|
|
335
476
|
inputCodec,
|
|
336
|
-
container
|
|
477
|
+
container,
|
|
478
|
+
inputRotation,
|
|
479
|
+
rotationToApply
|
|
337
480
|
}) => {
|
|
481
|
+
if (normalizeVideoRotation(inputRotation) !== normalizeVideoRotation(rotationToApply)) {
|
|
482
|
+
return false;
|
|
483
|
+
}
|
|
338
484
|
if (container === "webm") {
|
|
339
485
|
return inputCodec === "vp8" || inputCodec === "vp9";
|
|
340
486
|
}
|
|
341
487
|
if (container === "mp4") {
|
|
342
|
-
return inputCodec === "h264"
|
|
488
|
+
return inputCodec === "h264";
|
|
489
|
+
}
|
|
490
|
+
if (container === "wav") {
|
|
491
|
+
return false;
|
|
343
492
|
}
|
|
344
493
|
throw new Error(`Unhandled codec: ${container}`);
|
|
345
494
|
};
|
|
495
|
+
// src/browser-quirks.ts
|
|
496
|
+
var isFirefox = () => {
|
|
497
|
+
return navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
|
498
|
+
};
|
|
499
|
+
var isSafari = () => {
|
|
500
|
+
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
501
|
+
};
|
|
502
|
+
var isChrome = () => {
|
|
503
|
+
return navigator.userAgent.toLowerCase().indexOf("chrome") > -1;
|
|
504
|
+
};
|
|
505
|
+
|
|
346
506
|
// src/audio-decoder-config.ts
|
|
347
|
-
var
|
|
507
|
+
var overrideBrowserQuirks = ({
|
|
508
|
+
config,
|
|
509
|
+
logLevel
|
|
510
|
+
}) => {
|
|
511
|
+
const bytes = config.description;
|
|
512
|
+
if (!bytes) {
|
|
513
|
+
return config;
|
|
514
|
+
}
|
|
515
|
+
if (bytes[0] === 18 && bytes[1] === 8) {
|
|
516
|
+
if (isFirefox()) {
|
|
517
|
+
return {
|
|
518
|
+
...config,
|
|
519
|
+
codec: "mp4a.40.2",
|
|
520
|
+
description: bytes
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
if (!isChrome()) {
|
|
524
|
+
return config;
|
|
525
|
+
}
|
|
526
|
+
Log.warn(logLevel, "Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330");
|
|
527
|
+
return {
|
|
528
|
+
...config,
|
|
529
|
+
description: new Uint8Array([18, 16])
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
|
|
533
|
+
Log.warn(logLevel, "Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330");
|
|
534
|
+
return {
|
|
535
|
+
...config,
|
|
536
|
+
description: new Uint8Array([18, 144])
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
return config;
|
|
540
|
+
};
|
|
541
|
+
var getAudioDecoderConfig = async (config, logLevel) => {
|
|
542
|
+
if (config.codec === "pcm-s16") {
|
|
543
|
+
return config;
|
|
544
|
+
}
|
|
348
545
|
if (typeof AudioDecoder === "undefined") {
|
|
349
546
|
return null;
|
|
350
547
|
}
|
|
351
548
|
if (typeof EncodedAudioChunk === "undefined") {
|
|
352
549
|
return null;
|
|
353
550
|
}
|
|
354
|
-
|
|
355
|
-
|
|
551
|
+
const realConfig = overrideBrowserQuirks({
|
|
552
|
+
config,
|
|
553
|
+
logLevel
|
|
554
|
+
});
|
|
555
|
+
if ((await AudioDecoder.isConfigSupported(realConfig)).supported) {
|
|
556
|
+
return realConfig;
|
|
356
557
|
}
|
|
357
558
|
return null;
|
|
358
559
|
};
|
|
@@ -365,6 +566,9 @@ var getCodecString = (audioCodec) => {
|
|
|
365
566
|
if (audioCodec === "aac") {
|
|
366
567
|
return "mp4a.40.02";
|
|
367
568
|
}
|
|
569
|
+
if (audioCodec === "wav") {
|
|
570
|
+
return "wav-should-not-to-into-audio-encoder";
|
|
571
|
+
}
|
|
368
572
|
throw new Error(`Unsupported audio codec: ${audioCodec}`);
|
|
369
573
|
};
|
|
370
574
|
var getAudioEncoderConfig = async (config) => {
|
|
@@ -372,6 +576,9 @@ var getAudioEncoderConfig = async (config) => {
|
|
|
372
576
|
...config,
|
|
373
577
|
codec: getCodecString(config.codec)
|
|
374
578
|
};
|
|
579
|
+
if (config.codec === "wav") {
|
|
580
|
+
return actualConfig;
|
|
581
|
+
}
|
|
375
582
|
if (typeof AudioEncoder === "undefined") {
|
|
376
583
|
return null;
|
|
377
584
|
}
|
|
@@ -385,9 +592,13 @@ var getAudioEncoderConfig = async (config) => {
|
|
|
385
592
|
var canReencodeAudioTrack = async ({
|
|
386
593
|
track,
|
|
387
594
|
audioCodec,
|
|
388
|
-
bitrate
|
|
595
|
+
bitrate,
|
|
596
|
+
logLevel = "info"
|
|
389
597
|
}) => {
|
|
390
|
-
const audioDecoderConfig = await getAudioDecoderConfig(track);
|
|
598
|
+
const audioDecoderConfig = await getAudioDecoderConfig(track, logLevel);
|
|
599
|
+
if (audioCodec === "wav" && audioDecoderConfig) {
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
391
602
|
const audioEncoderConfig = await getAudioEncoderConfig({
|
|
392
603
|
codec: audioCodec,
|
|
393
604
|
numberOfChannels: track.numberOfChannels,
|
|
@@ -418,14 +629,6 @@ var getVideoDecoderConfigWithHardwareAcceleration = async (config) => {
|
|
|
418
629
|
return null;
|
|
419
630
|
};
|
|
420
631
|
|
|
421
|
-
// src/browser-quirks.ts
|
|
422
|
-
var isFirefox = () => {
|
|
423
|
-
return navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
|
424
|
-
};
|
|
425
|
-
var isSafari = () => {
|
|
426
|
-
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
427
|
-
};
|
|
428
|
-
|
|
429
632
|
// src/choose-correct-avc1-profile.ts
|
|
430
633
|
var chooseCorrectAvc1Profile = ({
|
|
431
634
|
width,
|
|
@@ -508,32 +711,9 @@ var canReencodeVideoTrack = async ({
|
|
|
508
711
|
const videoDecoderConfig = await getVideoDecoderConfigWithHardwareAcceleration(track);
|
|
509
712
|
return Boolean(videoDecoderConfig && videoEncoderConfig);
|
|
510
713
|
};
|
|
511
|
-
// src/codec-id.ts
|
|
512
|
-
var availableContainers = ["webm", "mp4"];
|
|
513
|
-
var getAvailableContainers = () => {
|
|
514
|
-
return availableContainers;
|
|
515
|
-
};
|
|
516
|
-
var getAvailableVideoCodecs = (container) => {
|
|
517
|
-
if (container === "mp4") {
|
|
518
|
-
return ["h264"];
|
|
519
|
-
}
|
|
520
|
-
if (container === "webm") {
|
|
521
|
-
return ["vp8", "vp9"];
|
|
522
|
-
}
|
|
523
|
-
throw new Error(`Unsupported container: ${container}`);
|
|
524
|
-
};
|
|
525
|
-
var getAvailableAudioCodecs = (container) => {
|
|
526
|
-
if (container === "mp4") {
|
|
527
|
-
return ["aac"];
|
|
528
|
-
}
|
|
529
|
-
if (container === "webm") {
|
|
530
|
-
return ["opus"];
|
|
531
|
-
}
|
|
532
|
-
throw new Error(`Unsupported container: ${container}`);
|
|
533
|
-
};
|
|
534
714
|
// src/convert-media.ts
|
|
535
715
|
import {
|
|
536
|
-
MediaParserInternals as
|
|
716
|
+
MediaParserInternals as MediaParserInternals7,
|
|
537
717
|
parseMedia
|
|
538
718
|
} from "@remotion/media-parser";
|
|
539
719
|
|
|
@@ -592,7 +772,7 @@ var convertEncodedChunk = (chunk, trackId) => {
|
|
|
592
772
|
};
|
|
593
773
|
|
|
594
774
|
// src/default-on-audio-track-handler.ts
|
|
595
|
-
import { MediaParserInternals as
|
|
775
|
+
import { MediaParserInternals as MediaParserInternals4 } from "@remotion/media-parser";
|
|
596
776
|
|
|
597
777
|
// src/get-default-audio-codec.ts
|
|
598
778
|
var getDefaultAudioCodec = ({
|
|
@@ -604,6 +784,9 @@ var getDefaultAudioCodec = ({
|
|
|
604
784
|
if (container === "mp4") {
|
|
605
785
|
return "aac";
|
|
606
786
|
}
|
|
787
|
+
if (container === "wav") {
|
|
788
|
+
return "wav";
|
|
789
|
+
}
|
|
607
790
|
throw new Error(`Unhandled container: ${container}`);
|
|
608
791
|
};
|
|
609
792
|
|
|
@@ -621,7 +804,7 @@ var defaultOnAudioTrackHandler = async ({
|
|
|
621
804
|
container
|
|
622
805
|
});
|
|
623
806
|
if (canCopy) {
|
|
624
|
-
|
|
807
|
+
MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can copy track, therefore copying`);
|
|
625
808
|
return Promise.resolve({ type: "copy" });
|
|
626
809
|
}
|
|
627
810
|
const audioCodec = defaultAudioCodec ?? getDefaultAudioCodec({ container });
|
|
@@ -631,14 +814,14 @@ var defaultOnAudioTrackHandler = async ({
|
|
|
631
814
|
bitrate
|
|
632
815
|
});
|
|
633
816
|
if (canReencode) {
|
|
634
|
-
|
|
817
|
+
MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
|
|
635
818
|
return Promise.resolve({
|
|
636
819
|
type: "reencode",
|
|
637
820
|
bitrate,
|
|
638
821
|
audioCodec
|
|
639
822
|
});
|
|
640
823
|
}
|
|
641
|
-
|
|
824
|
+
MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
|
|
642
825
|
return Promise.resolve({ type: "fail" });
|
|
643
826
|
};
|
|
644
827
|
|
|
@@ -651,7 +834,8 @@ var makeAudioTrackHandler = ({
|
|
|
651
834
|
onMediaStateUpdate,
|
|
652
835
|
onAudioTrack,
|
|
653
836
|
logLevel,
|
|
654
|
-
container
|
|
837
|
+
container,
|
|
838
|
+
progressTracker
|
|
655
839
|
}) => async (track) => {
|
|
656
840
|
const audioOperation = await (onAudioTrack ?? defaultOnAudioTrackHandler)({
|
|
657
841
|
defaultAudioCodec: audioCodec,
|
|
@@ -702,7 +886,7 @@ var makeAudioTrackHandler = ({
|
|
|
702
886
|
numberOfChannels: track.numberOfChannels,
|
|
703
887
|
sampleRate: track.sampleRate,
|
|
704
888
|
description: track.description
|
|
705
|
-
});
|
|
889
|
+
}, logLevel);
|
|
706
890
|
if (!audioEncoderConfig) {
|
|
707
891
|
abortConversion(new error_cause_default(`Could not configure audio encoder of track ${track.trackId}`));
|
|
708
892
|
return null;
|
|
@@ -714,7 +898,7 @@ var makeAudioTrackHandler = ({
|
|
|
714
898
|
const codecPrivate = audioOperation.audioCodec === "aac" ? new Uint8Array([17, 144]) : null;
|
|
715
899
|
const { trackNumber } = await state.addTrack({
|
|
716
900
|
type: "audio",
|
|
717
|
-
codec: audioOperation.audioCodec,
|
|
901
|
+
codec: audioOperation.audioCodec === "wav" ? "pcm-s16" : audioOperation.audioCodec,
|
|
718
902
|
numberOfChannels: track.numberOfChannels,
|
|
719
903
|
sampleRate: track.sampleRate,
|
|
720
904
|
codecPrivate,
|
|
@@ -747,7 +931,8 @@ var makeAudioTrackHandler = ({
|
|
|
747
931
|
codec: audioOperation.audioCodec,
|
|
748
932
|
signal: controller.signal,
|
|
749
933
|
config: audioEncoderConfig,
|
|
750
|
-
logLevel
|
|
934
|
+
logLevel,
|
|
935
|
+
progressTracker
|
|
751
936
|
});
|
|
752
937
|
const audioDecoder = createAudioDecoder({
|
|
753
938
|
onFrame: async (frame) => {
|
|
@@ -761,13 +946,15 @@ var makeAudioTrackHandler = ({
|
|
|
761
946
|
frame.close();
|
|
762
947
|
},
|
|
763
948
|
onError(error) {
|
|
764
|
-
abortConversion(new error_cause_default(`Audio decoder of track ${track.trackId} failed (see .cause of this error)`, {
|
|
949
|
+
abortConversion(new error_cause_default(`Audio decoder of track ${track.trackId} failed. Config: ${JSON.stringify(audioDecoderConfig)} (see .cause of this error)`, {
|
|
765
950
|
cause: error
|
|
766
951
|
}));
|
|
767
952
|
},
|
|
768
953
|
signal: controller.signal,
|
|
769
954
|
config: audioDecoderConfig,
|
|
770
|
-
logLevel
|
|
955
|
+
logLevel,
|
|
956
|
+
track,
|
|
957
|
+
progressTracker
|
|
771
958
|
});
|
|
772
959
|
state.addWaitForFinishPromise(async () => {
|
|
773
960
|
await audioDecoder.waitForFinish();
|
|
@@ -786,7 +973,7 @@ var arrayBufferToUint8Array = (buffer) => {
|
|
|
786
973
|
};
|
|
787
974
|
|
|
788
975
|
// src/default-on-video-track-handler.ts
|
|
789
|
-
import { MediaParserInternals as
|
|
976
|
+
import { MediaParserInternals as MediaParserInternals5 } from "@remotion/media-parser";
|
|
790
977
|
|
|
791
978
|
// src/get-default-video-codec.ts
|
|
792
979
|
var getDefaultVideoCodec = ({
|
|
@@ -795,7 +982,13 @@ var getDefaultVideoCodec = ({
|
|
|
795
982
|
if (container === "webm") {
|
|
796
983
|
return "vp8";
|
|
797
984
|
}
|
|
798
|
-
|
|
985
|
+
if (container === "mp4") {
|
|
986
|
+
return "h264";
|
|
987
|
+
}
|
|
988
|
+
if (container === "wav") {
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
throw new Error(`Unhandled container: ${container}`);
|
|
799
992
|
};
|
|
800
993
|
|
|
801
994
|
// src/default-on-video-track-handler.ts
|
|
@@ -803,26 +996,37 @@ var defaultOnVideoTrackHandler = async ({
|
|
|
803
996
|
track,
|
|
804
997
|
defaultVideoCodec,
|
|
805
998
|
logLevel,
|
|
806
|
-
container
|
|
999
|
+
container,
|
|
1000
|
+
rotate
|
|
807
1001
|
}) => {
|
|
808
1002
|
const canCopy = canCopyVideoTrack({
|
|
809
1003
|
inputCodec: track.codecWithoutConfig,
|
|
810
|
-
container
|
|
1004
|
+
container,
|
|
1005
|
+
inputRotation: track.rotation,
|
|
1006
|
+
rotationToApply: rotate
|
|
811
1007
|
});
|
|
812
1008
|
if (canCopy) {
|
|
813
|
-
|
|
1009
|
+
MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
|
|
814
1010
|
return Promise.resolve({ type: "copy" });
|
|
815
1011
|
}
|
|
816
1012
|
const videoCodec = defaultVideoCodec ?? getDefaultVideoCodec({ container });
|
|
1013
|
+
if (videoCodec === null) {
|
|
1014
|
+
MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): No default video codec, therefore dropping`);
|
|
1015
|
+
return Promise.resolve({ type: "drop" });
|
|
1016
|
+
}
|
|
817
1017
|
const canReencode = await canReencodeVideoTrack({
|
|
818
1018
|
videoCodec,
|
|
819
1019
|
track
|
|
820
1020
|
});
|
|
821
1021
|
if (canReencode) {
|
|
822
|
-
|
|
823
|
-
return Promise.resolve({
|
|
1022
|
+
MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
|
|
1023
|
+
return Promise.resolve({
|
|
1024
|
+
type: "reencode",
|
|
1025
|
+
videoCodec,
|
|
1026
|
+
rotation: rotate - track.rotation
|
|
1027
|
+
});
|
|
824
1028
|
}
|
|
825
|
-
|
|
1029
|
+
MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
|
|
826
1030
|
return Promise.resolve({ type: "fail" });
|
|
827
1031
|
};
|
|
828
1032
|
|
|
@@ -831,6 +1035,12 @@ var needsToCorrectVideoFrame = ({
|
|
|
831
1035
|
videoFrame,
|
|
832
1036
|
outputCodec
|
|
833
1037
|
}) => {
|
|
1038
|
+
if (videoFrame.format === null) {
|
|
1039
|
+
return true;
|
|
1040
|
+
}
|
|
1041
|
+
if (videoFrame.format === "I420P10") {
|
|
1042
|
+
return true;
|
|
1043
|
+
}
|
|
834
1044
|
return isFirefox() && videoFrame.format === "BGRX" && outputCodec === "h264";
|
|
835
1045
|
};
|
|
836
1046
|
var convertToCorrectVideoFrame = ({
|
|
@@ -858,41 +1068,43 @@ var convertToCorrectVideoFrame = ({
|
|
|
858
1068
|
|
|
859
1069
|
// src/on-frame.ts
|
|
860
1070
|
var onFrame = async ({
|
|
861
|
-
frame,
|
|
1071
|
+
frame: unrotatedFrame,
|
|
862
1072
|
onVideoFrame,
|
|
863
1073
|
videoEncoder,
|
|
864
1074
|
track,
|
|
865
|
-
outputCodec
|
|
1075
|
+
outputCodec,
|
|
1076
|
+
rotation
|
|
866
1077
|
}) => {
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
}
|
|
871
|
-
if (
|
|
872
|
-
|
|
1078
|
+
const rotated = rotateVideoFrame({
|
|
1079
|
+
rotation,
|
|
1080
|
+
frame: unrotatedFrame
|
|
1081
|
+
});
|
|
1082
|
+
if (unrotatedFrame !== rotated) {
|
|
1083
|
+
unrotatedFrame.close();
|
|
873
1084
|
}
|
|
874
|
-
|
|
875
|
-
|
|
1085
|
+
const userProcessedFrame = onVideoFrame ? await onVideoFrame({ frame: rotated, track }) : rotated;
|
|
1086
|
+
if (userProcessedFrame.displayWidth !== rotated.displayWidth) {
|
|
1087
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${userProcessedFrame.displayWidth}) than the input frame (${userProcessedFrame.displayHeight})`);
|
|
876
1088
|
}
|
|
877
|
-
if (
|
|
878
|
-
throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${
|
|
1089
|
+
if (userProcessedFrame.displayHeight !== rotated.displayHeight) {
|
|
1090
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${userProcessedFrame.displayHeight}) than the input frame (${userProcessedFrame.displayHeight})`);
|
|
879
1091
|
}
|
|
880
|
-
if (
|
|
881
|
-
throw new Error(`Returned VideoFrame of track ${track.trackId} has different timestamp (${
|
|
1092
|
+
if (userProcessedFrame.timestamp !== rotated.timestamp) {
|
|
1093
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different timestamp (${userProcessedFrame.timestamp}) than the input frame (${rotated.timestamp}). When calling new VideoFrame(), pass {timestamp: frame.timestamp} as second argument`);
|
|
882
1094
|
}
|
|
883
|
-
if (
|
|
884
|
-
throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${
|
|
1095
|
+
if ((userProcessedFrame.duration ?? 0) !== (rotated.duration ?? 0)) {
|
|
1096
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${userProcessedFrame.duration}) than the input frame (${rotated.duration}). When calling new VideoFrame(), pass {duration: frame.duration} as second argument`);
|
|
885
1097
|
}
|
|
886
1098
|
const fixedFrame = convertToCorrectVideoFrame({
|
|
887
|
-
videoFrame:
|
|
1099
|
+
videoFrame: userProcessedFrame,
|
|
888
1100
|
outputCodec
|
|
889
1101
|
});
|
|
890
1102
|
await videoEncoder.encodeFrame(fixedFrame, fixedFrame.timestamp);
|
|
891
1103
|
fixedFrame.close();
|
|
892
|
-
if (
|
|
893
|
-
|
|
1104
|
+
if (rotated !== userProcessedFrame) {
|
|
1105
|
+
rotated.close();
|
|
894
1106
|
}
|
|
895
|
-
if (fixedFrame !==
|
|
1107
|
+
if (fixedFrame !== userProcessedFrame) {
|
|
896
1108
|
fixedFrame.close();
|
|
897
1109
|
}
|
|
898
1110
|
};
|
|
@@ -903,9 +1115,14 @@ var createVideoDecoder = ({
|
|
|
903
1115
|
onError,
|
|
904
1116
|
signal,
|
|
905
1117
|
config,
|
|
906
|
-
logLevel
|
|
1118
|
+
logLevel,
|
|
1119
|
+
progress
|
|
907
1120
|
}) => {
|
|
908
|
-
const ioSynchronizer = makeIoSynchronizer(
|
|
1121
|
+
const ioSynchronizer = makeIoSynchronizer({
|
|
1122
|
+
logLevel,
|
|
1123
|
+
label: "Video decoder",
|
|
1124
|
+
progress
|
|
1125
|
+
});
|
|
909
1126
|
let outputQueue = Promise.resolve();
|
|
910
1127
|
const videoDecoder = new VideoDecoder({
|
|
911
1128
|
output(inputFrame) {
|
|
@@ -951,7 +1168,11 @@ var createVideoDecoder = ({
|
|
|
951
1168
|
if (videoDecoder.state === "closed") {
|
|
952
1169
|
return;
|
|
953
1170
|
}
|
|
954
|
-
await ioSynchronizer.waitFor({
|
|
1171
|
+
await ioSynchronizer.waitFor({
|
|
1172
|
+
unemitted: 20,
|
|
1173
|
+
_unprocessed: 2,
|
|
1174
|
+
minimumProgress: sample.timestamp - 5000000
|
|
1175
|
+
});
|
|
955
1176
|
if (sample.type === "key") {
|
|
956
1177
|
await videoDecoder.flush();
|
|
957
1178
|
}
|
|
@@ -988,12 +1209,17 @@ var createVideoEncoder = ({
|
|
|
988
1209
|
signal,
|
|
989
1210
|
config,
|
|
990
1211
|
logLevel,
|
|
991
|
-
outputCodec
|
|
1212
|
+
outputCodec,
|
|
1213
|
+
progress
|
|
992
1214
|
}) => {
|
|
993
1215
|
if (signal.aborted) {
|
|
994
1216
|
throw new Error("Not creating video encoder, already aborted");
|
|
995
1217
|
}
|
|
996
|
-
const ioSynchronizer = makeIoSynchronizer(
|
|
1218
|
+
const ioSynchronizer = makeIoSynchronizer({
|
|
1219
|
+
logLevel,
|
|
1220
|
+
label: "Video encoder",
|
|
1221
|
+
progress
|
|
1222
|
+
});
|
|
997
1223
|
let outputQueue = Promise.resolve();
|
|
998
1224
|
const encoder = new VideoEncoder({
|
|
999
1225
|
error(error) {
|
|
@@ -1035,7 +1261,8 @@ var createVideoEncoder = ({
|
|
|
1035
1261
|
}
|
|
1036
1262
|
await ioSynchronizer.waitFor({
|
|
1037
1263
|
unemitted: 10,
|
|
1038
|
-
_unprocessed: 10
|
|
1264
|
+
_unprocessed: 10,
|
|
1265
|
+
minimumProgress: frame.timestamp - 5000000
|
|
1039
1266
|
});
|
|
1040
1267
|
if (encoder.state === "closed") {
|
|
1041
1268
|
return;
|
|
@@ -1075,7 +1302,9 @@ var makeVideoTrackHandler = ({
|
|
|
1075
1302
|
defaultVideoCodec,
|
|
1076
1303
|
onVideoTrack,
|
|
1077
1304
|
logLevel,
|
|
1078
|
-
container
|
|
1305
|
+
container,
|
|
1306
|
+
rotate,
|
|
1307
|
+
progress
|
|
1079
1308
|
}) => async (track) => {
|
|
1080
1309
|
if (controller.signal.aborted) {
|
|
1081
1310
|
throw new error_cause_default("Aborted");
|
|
@@ -1084,7 +1313,8 @@ var makeVideoTrackHandler = ({
|
|
|
1084
1313
|
track,
|
|
1085
1314
|
defaultVideoCodec,
|
|
1086
1315
|
logLevel,
|
|
1087
|
-
container
|
|
1316
|
+
container,
|
|
1317
|
+
rotate
|
|
1088
1318
|
});
|
|
1089
1319
|
if (videoOperation.type === "drop") {
|
|
1090
1320
|
return null;
|
|
@@ -1119,10 +1349,19 @@ var makeVideoTrackHandler = ({
|
|
|
1119
1349
|
});
|
|
1120
1350
|
};
|
|
1121
1351
|
}
|
|
1352
|
+
if (videoOperation.type !== "reencode") {
|
|
1353
|
+
throw new error_cause_default(`Video track with ID ${track.trackId} could not be resolved with a valid operation. Received ${JSON.stringify(videoOperation)}, but must be either "copy", "reencode", "drop" or "fail"`);
|
|
1354
|
+
}
|
|
1355
|
+
const rotation = videoOperation.rotate ?? -track.rotation;
|
|
1356
|
+
const { height: newHeight, width: newWidth } = calculateNewDimensionsFromDimensions({
|
|
1357
|
+
width: track.codedWidth,
|
|
1358
|
+
height: track.codedHeight,
|
|
1359
|
+
rotation
|
|
1360
|
+
});
|
|
1122
1361
|
const videoEncoderConfig = await getVideoEncoderConfig({
|
|
1123
1362
|
codec: videoOperation.videoCodec,
|
|
1124
|
-
height:
|
|
1125
|
-
width:
|
|
1363
|
+
height: newHeight,
|
|
1364
|
+
width: newWidth,
|
|
1126
1365
|
fps: track.fps
|
|
1127
1366
|
});
|
|
1128
1367
|
const videoDecoderConfig = await getVideoDecoderConfigWithHardwareAcceleration(track);
|
|
@@ -1137,8 +1376,8 @@ var makeVideoTrackHandler = ({
|
|
|
1137
1376
|
const { trackNumber } = await state.addTrack({
|
|
1138
1377
|
type: "video",
|
|
1139
1378
|
color: track.color,
|
|
1140
|
-
width:
|
|
1141
|
-
height:
|
|
1379
|
+
width: newWidth,
|
|
1380
|
+
height: newHeight,
|
|
1142
1381
|
codec: videoOperation.videoCodec,
|
|
1143
1382
|
codecPrivate: null,
|
|
1144
1383
|
timescale: track.timescale
|
|
@@ -1168,7 +1407,8 @@ var makeVideoTrackHandler = ({
|
|
|
1168
1407
|
signal: controller.signal,
|
|
1169
1408
|
config: videoEncoderConfig,
|
|
1170
1409
|
logLevel,
|
|
1171
|
-
outputCodec: videoOperation.videoCodec
|
|
1410
|
+
outputCodec: videoOperation.videoCodec,
|
|
1411
|
+
progress
|
|
1172
1412
|
});
|
|
1173
1413
|
const videoDecoder = createVideoDecoder({
|
|
1174
1414
|
config: videoDecoderConfig,
|
|
@@ -1178,7 +1418,8 @@ var makeVideoTrackHandler = ({
|
|
|
1178
1418
|
track,
|
|
1179
1419
|
videoEncoder,
|
|
1180
1420
|
onVideoFrame,
|
|
1181
|
-
outputCodec: videoOperation.videoCodec
|
|
1421
|
+
outputCodec: videoOperation.videoCodec,
|
|
1422
|
+
rotation
|
|
1182
1423
|
});
|
|
1183
1424
|
},
|
|
1184
1425
|
onError: (err) => {
|
|
@@ -1187,7 +1428,8 @@ var makeVideoTrackHandler = ({
|
|
|
1187
1428
|
}));
|
|
1188
1429
|
},
|
|
1189
1430
|
signal: controller.signal,
|
|
1190
|
-
logLevel
|
|
1431
|
+
logLevel,
|
|
1432
|
+
progress
|
|
1191
1433
|
});
|
|
1192
1434
|
state.addWaitForFinishPromise(async () => {
|
|
1193
1435
|
Log.verbose(logLevel, "Waiting for video decoder to finish");
|
|
@@ -1203,6 +1445,21 @@ var makeVideoTrackHandler = ({
|
|
|
1203
1445
|
};
|
|
1204
1446
|
};
|
|
1205
1447
|
|
|
1448
|
+
// src/select-container-creator.ts
|
|
1449
|
+
import { MediaParserInternals as MediaParserInternals6 } from "@remotion/media-parser";
|
|
1450
|
+
var selectContainerCreator = (container) => {
|
|
1451
|
+
if (container === "mp4") {
|
|
1452
|
+
return MediaParserInternals6.createIsoBaseMedia;
|
|
1453
|
+
}
|
|
1454
|
+
if (container === "wav") {
|
|
1455
|
+
return MediaParserInternals6.createWav;
|
|
1456
|
+
}
|
|
1457
|
+
if (container === "webm") {
|
|
1458
|
+
return MediaParserInternals6.createMatroskaMedia;
|
|
1459
|
+
}
|
|
1460
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
1461
|
+
};
|
|
1462
|
+
|
|
1206
1463
|
// src/throttled-state-update.ts
|
|
1207
1464
|
var throttledStateUpdate = ({
|
|
1208
1465
|
updateFn,
|
|
@@ -1271,18 +1528,19 @@ var convertMedia = async function({
|
|
|
1271
1528
|
logLevel = "info",
|
|
1272
1529
|
writer,
|
|
1273
1530
|
progressIntervalInMs,
|
|
1531
|
+
rotate,
|
|
1274
1532
|
...more
|
|
1275
1533
|
}) {
|
|
1276
1534
|
if (userPassedAbortSignal?.aborted) {
|
|
1277
1535
|
return Promise.reject(new error_cause_default("Aborted"));
|
|
1278
1536
|
}
|
|
1279
|
-
if (container !== "webm" && container !== "mp4") {
|
|
1280
|
-
return Promise.reject(new TypeError('Only `to: "webm"` and `to: "
|
|
1537
|
+
if (container !== "webm" && container !== "mp4" && container !== "wav") {
|
|
1538
|
+
return Promise.reject(new TypeError('Only `to: "webm"`, `to: "mp4"` and `to: "wav"` is supported currently'));
|
|
1281
1539
|
}
|
|
1282
1540
|
if (videoCodec && videoCodec !== "vp8" && videoCodec !== "vp9") {
|
|
1283
1541
|
return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
|
|
1284
1542
|
}
|
|
1285
|
-
const { resolve, reject, getPromiseToImmediatelyReturn } = withResolversAndWaitForReturn();
|
|
1543
|
+
const { resolve, reject, getPromiseToImmediatelyReturn } = MediaParserInternals7.withResolversAndWaitForReturn();
|
|
1286
1544
|
const controller = new AbortController;
|
|
1287
1545
|
const abortConversion = (errCause) => {
|
|
1288
1546
|
reject(errCause);
|
|
@@ -1294,12 +1552,13 @@ var convertMedia = async function({
|
|
|
1294
1552
|
abortConversion(new error_cause_default("Conversion aborted by user"));
|
|
1295
1553
|
};
|
|
1296
1554
|
userPassedAbortSignal?.addEventListener("abort", onUserAbort);
|
|
1297
|
-
const creator = container
|
|
1555
|
+
const creator = selectContainerCreator(container);
|
|
1298
1556
|
const throttledState = throttledStateUpdate({
|
|
1299
1557
|
updateFn: onProgressDoNotCallDirectly ?? null,
|
|
1300
1558
|
everyMilliseconds: progressIntervalInMs ?? 100,
|
|
1301
1559
|
signal: controller.signal
|
|
1302
1560
|
});
|
|
1561
|
+
const progressTracker = MediaParserInternals7.makeProgressTracker();
|
|
1303
1562
|
const state = await creator({
|
|
1304
1563
|
filename: generateOutputFilename(src, container),
|
|
1305
1564
|
writer: await autoSelectWriter(writer, logLevel),
|
|
@@ -1326,7 +1585,8 @@ var convertMedia = async function({
|
|
|
1326
1585
|
return prevState;
|
|
1327
1586
|
});
|
|
1328
1587
|
},
|
|
1329
|
-
logLevel
|
|
1588
|
+
logLevel,
|
|
1589
|
+
progressTracker
|
|
1330
1590
|
});
|
|
1331
1591
|
const onVideoTrack = makeVideoTrackHandler({
|
|
1332
1592
|
state,
|
|
@@ -1337,7 +1597,9 @@ var convertMedia = async function({
|
|
|
1337
1597
|
defaultVideoCodec: videoCodec ?? null,
|
|
1338
1598
|
onVideoTrack: userVideoResolver ?? null,
|
|
1339
1599
|
logLevel,
|
|
1340
|
-
container
|
|
1600
|
+
container,
|
|
1601
|
+
rotate: rotate ?? 0,
|
|
1602
|
+
progress: progressTracker
|
|
1341
1603
|
});
|
|
1342
1604
|
const onAudioTrack = makeAudioTrackHandler({
|
|
1343
1605
|
abortConversion,
|
|
@@ -1347,7 +1609,8 @@ var convertMedia = async function({
|
|
|
1347
1609
|
state,
|
|
1348
1610
|
onAudioTrack: userAudioResolver ?? null,
|
|
1349
1611
|
logLevel,
|
|
1350
|
-
container
|
|
1612
|
+
container,
|
|
1613
|
+
progressTracker
|
|
1351
1614
|
});
|
|
1352
1615
|
parseMedia({
|
|
1353
1616
|
logLevel,
|
|
@@ -1398,7 +1661,46 @@ var convertMedia = async function({
|
|
|
1398
1661
|
userPassedAbortSignal?.removeEventListener("abort", onUserAbort);
|
|
1399
1662
|
});
|
|
1400
1663
|
};
|
|
1664
|
+
// src/get-available-audio-codecs.ts
|
|
1665
|
+
var getAvailableAudioCodecs = ({
|
|
1666
|
+
container
|
|
1667
|
+
}) => {
|
|
1668
|
+
if (container === "mp4") {
|
|
1669
|
+
return ["aac"];
|
|
1670
|
+
}
|
|
1671
|
+
if (container === "webm") {
|
|
1672
|
+
return ["opus"];
|
|
1673
|
+
}
|
|
1674
|
+
if (container === "wav") {
|
|
1675
|
+
return ["wav"];
|
|
1676
|
+
}
|
|
1677
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
1678
|
+
};
|
|
1679
|
+
// src/get-available-containers.ts
|
|
1680
|
+
var availableContainers = ["webm", "mp4", "wav"];
|
|
1681
|
+
var getAvailableContainers = () => {
|
|
1682
|
+
return availableContainers;
|
|
1683
|
+
};
|
|
1684
|
+
// src/get-available-video-codecs.ts
|
|
1685
|
+
var getAvailableVideoCodecs = ({
|
|
1686
|
+
container
|
|
1687
|
+
}) => {
|
|
1688
|
+
if (container === "mp4") {
|
|
1689
|
+
return ["h264"];
|
|
1690
|
+
}
|
|
1691
|
+
if (container === "webm") {
|
|
1692
|
+
return ["vp8", "vp9"];
|
|
1693
|
+
}
|
|
1694
|
+
if (container === "wav") {
|
|
1695
|
+
return [];
|
|
1696
|
+
}
|
|
1697
|
+
throw new Error(`Unsupported container: ${container}`);
|
|
1698
|
+
};
|
|
1401
1699
|
// src/index.ts
|
|
1700
|
+
var WebCodecsInternals = {
|
|
1701
|
+
rotateVideoFrame,
|
|
1702
|
+
normalizeVideoRotation
|
|
1703
|
+
};
|
|
1402
1704
|
setRemotionImported();
|
|
1403
1705
|
export {
|
|
1404
1706
|
getDefaultVideoCodec,
|
|
@@ -1416,5 +1718,6 @@ export {
|
|
|
1416
1718
|
canReencodeVideoTrack,
|
|
1417
1719
|
canReencodeAudioTrack,
|
|
1418
1720
|
canCopyVideoTrack,
|
|
1419
|
-
canCopyAudioTrack
|
|
1721
|
+
canCopyAudioTrack,
|
|
1722
|
+
WebCodecsInternals
|
|
1420
1723
|
};
|