polotno-node 2.9.37 → 2.9.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/video-parallel.js +32 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polotno-node",
3
- "version": "2.9.37",
3
+ "version": "2.9.38",
4
4
  "description": "Polotno workflow from NodeJS",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/video-parallel.js CHANGED
@@ -278,6 +278,8 @@ module.exports.jsonToVideo = async function jsonToVideo(
278
278
  .outputOptions('-pix_fmt yuv420p')
279
279
  .videoFilters('scale=trunc(iw/2)*2:trunc(ih/2)*2'); // Ensure dimensions are divisible by 2
280
280
 
281
+ const audioInputs = [];
282
+
281
283
  // Add each audio segment as a separate input
282
284
  inputs.forEach((input, index) => {
283
285
  const inputStartSec = (input.inputStartTime / 1000).toFixed(3);
@@ -285,35 +287,50 @@ module.exports.jsonToVideo = async function jsonToVideo(
285
287
  (input.inputEndTime - input.inputStartTime) /
286
288
  1000
287
289
  ).toFixed(3);
288
- const outputOffsetSec = (input.outputStartTime / 1000).toFixed(3);
290
+ const outputOffsetMs = Math.round(input.outputStartTime);
291
+ console.log({ outputOffsetMs });
289
292
  const volume = input.volume !== undefined ? input.volume : 1;
290
293
 
291
- // Apply `-itsoffset` before each input file to shift its audio stream
292
294
  ffmpegCmd
293
- .inputOptions([`-itsoffset ${outputOffsetSec}`]) // Shift the input time
294
- .input(input.mp4File) // Add the actual input file
295
- .inputOptions([`-ss ${inputStartSec}`, `-t ${inputDurationSec}`]); // Specify the timing to cut the audio
296
-
297
- // Apply volume filter to respect the input volume
298
- ffmpegCmd.audioFilters(`volume=${volume}`);
295
+ .input(input.mp4File)
296
+ .inputOptions([`-ss ${inputStartSec}`, `-t ${inputDurationSec}`]);
297
+
298
+ audioInputs.push({
299
+ index: index + 1, // +1 because the first input is the image sequence
300
+ delay: outputOffsetMs,
301
+ volume: volume,
302
+ });
299
303
  });
300
304
 
301
305
  // Map the video stream from the image sequence
302
306
  ffmpegCmd.outputOptions(['-map 0:v']);
303
307
 
304
- // Map each audio stream
305
- inputs.forEach((_, index) => {
306
- ffmpegCmd.outputOptions([`-map ${index + 1}:a?`]);
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
+ }
308
324
 
309
325
  ffmpegCmd
310
326
  .format(format)
311
327
  .audioCodec('aac')
328
+ .on('start', (command) => console.log('FFmpeg command:', command))
312
329
  .on('end', () => resolve())
313
330
  .on('error', (err, stdout, stderr) => {
314
- console.log(err.message);
315
- console.log('stdout:\n' + stdout);
316
- console.log('stderr:\n' + stderr);
331
+ console.error('Error:', err.message);
332
+ console.error('stdout:', stdout);
333
+ console.error('stderr:', stderr);
317
334
  reject(err);
318
335
  })
319
336
  .save(attrs.out);