polotno-node 2.9.38 → 2.9.39
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/package.json +1 -1
- package/video-parallel.js +63 -52
package/package.json
CHANGED
package/video-parallel.js
CHANGED
|
@@ -276,64 +276,75 @@ module.exports.jsonToVideo = async function jsonToVideo(
|
|
|
276
276
|
.inputFPS(fps)
|
|
277
277
|
.videoCodec('libx264')
|
|
278
278
|
.outputOptions('-pix_fmt yuv420p')
|
|
279
|
-
.videoFilters('scale=trunc(iw/2)*2:trunc(ih/2)*2');
|
|
279
|
+
.videoFilters('scale=trunc(iw/2)*2:trunc(ih/2)*2');
|
|
280
280
|
|
|
281
281
|
const audioInputs = [];
|
|
282
282
|
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
283
|
+
// Use Promise.all to handle async ffprobe calls
|
|
284
|
+
Promise.all(
|
|
285
|
+
inputs.map((input, index) => {
|
|
286
|
+
return new Promise((resolveProbe) => {
|
|
287
|
+
const inputStartSec = (input.inputStartTime / 1000).toFixed(3);
|
|
288
|
+
const inputDurationSec = (
|
|
289
|
+
(input.inputEndTime - input.inputStartTime) /
|
|
290
|
+
1000
|
|
291
|
+
).toFixed(3);
|
|
292
|
+
const outputOffsetMs = Math.round(input.outputStartTime);
|
|
293
|
+
const volume = input.volume !== undefined ? input.volume : 1;
|
|
294
|
+
|
|
295
|
+
ffmpegCmd
|
|
296
|
+
.input(input.mp4File)
|
|
297
|
+
.inputOptions([`-ss ${inputStartSec}`, `-t ${inputDurationSec}`]);
|
|
298
|
+
|
|
299
|
+
ffmpeg.ffprobe(input.mp4File, (err, metadata) => {
|
|
300
|
+
if (
|
|
301
|
+
!err &&
|
|
302
|
+
metadata.streams.some((stream) => stream.codec_type === 'audio')
|
|
303
|
+
) {
|
|
304
|
+
audioInputs.push({
|
|
305
|
+
index: index + 1,
|
|
306
|
+
delay: outputOffsetMs,
|
|
307
|
+
volume: volume,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
resolveProbe();
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
})
|
|
314
|
+
).then(() => {
|
|
315
|
+
// Map the video stream from the image sequence
|
|
316
|
+
ffmpegCmd.outputOptions(['-map 0:v']);
|
|
317
|
+
|
|
318
|
+
// Prepare audio filter complex only if there are audio inputs
|
|
319
|
+
if (audioInputs.length > 0) {
|
|
320
|
+
const audioFilters = audioInputs.map(
|
|
321
|
+
(input, i) =>
|
|
322
|
+
`[${input.index}:a]adelay=${input.delay}|${input.delay},volume=${input.volume}[a${i}]`
|
|
323
|
+
);
|
|
324
|
+
const audioMerge = audioInputs.map((_, i) => `[a${i}]`).join('');
|
|
325
|
+
const filterComplex = `${audioFilters.join(
|
|
326
|
+
';'
|
|
327
|
+
)};${audioMerge}amix=inputs=${
|
|
328
|
+
audioInputs.length
|
|
329
|
+
}:duration=longest[aout]`;
|
|
330
|
+
|
|
331
|
+
ffmpegCmd.complexFilter(filterComplex);
|
|
332
|
+
ffmpegCmd.outputOptions(['-map [aout]']);
|
|
333
|
+
}
|
|
293
334
|
|
|
294
335
|
ffmpegCmd
|
|
295
|
-
.
|
|
296
|
-
.
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
336
|
+
.format(format)
|
|
337
|
+
.audioCodec('aac')
|
|
338
|
+
.on('start', (command) => console.log('FFmpeg command:', command))
|
|
339
|
+
.on('end', () => resolve())
|
|
340
|
+
.on('error', (err, stdout, stderr) => {
|
|
341
|
+
console.error('Error:', err.message);
|
|
342
|
+
console.error('stdout:', stdout);
|
|
343
|
+
console.error('stderr:', stderr);
|
|
344
|
+
reject(err);
|
|
345
|
+
})
|
|
346
|
+
.save(attrs.out);
|
|
303
347
|
});
|
|
304
|
-
|
|
305
|
-
// Map the video stream from the image sequence
|
|
306
|
-
ffmpegCmd.outputOptions(['-map 0:v']);
|
|
307
|
-
|
|
308
|
-
// Prepare audio filter complex
|
|
309
|
-
if (audioInputs.length > 0) {
|
|
310
|
-
const audioFilters = audioInputs.map(
|
|
311
|
-
(input, i) =>
|
|
312
|
-
`[${input.index}:a]adelay=${input.delay}|${input.delay},volume=${input.volume}[a${i}]`
|
|
313
|
-
);
|
|
314
|
-
const audioMerge = audioInputs.map((_, i) => `[a${i}]`).join('');
|
|
315
|
-
const filterComplex = `${audioFilters.join(
|
|
316
|
-
';'
|
|
317
|
-
)};${audioMerge}amix=inputs=${
|
|
318
|
-
audioInputs.length
|
|
319
|
-
}:duration=longest[aout]`;
|
|
320
|
-
|
|
321
|
-
ffmpegCmd.complexFilter(filterComplex);
|
|
322
|
-
ffmpegCmd.outputOptions(['-map [aout]']);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
ffmpegCmd
|
|
326
|
-
.format(format)
|
|
327
|
-
.audioCodec('aac')
|
|
328
|
-
.on('start', (command) => console.log('FFmpeg command:', command))
|
|
329
|
-
.on('end', () => resolve())
|
|
330
|
-
.on('error', (err, stdout, stderr) => {
|
|
331
|
-
console.error('Error:', err.message);
|
|
332
|
-
console.error('stdout:', stdout);
|
|
333
|
-
console.error('stderr:', stderr);
|
|
334
|
-
reject(err);
|
|
335
|
-
})
|
|
336
|
-
.save(attrs.out);
|
|
337
348
|
});
|
|
338
349
|
} catch (e) {
|
|
339
350
|
throw e;
|