Is it possible to write multiple output files from a complex filter?
ChrisMICDUP opened this issue · comments
Version information
- fluent-ffmpeg version: 2.1.2
- ffmpeg version: 6.1.1
- OS: MacOS 13.6
Code to reproduce
async function extractClipsWithComplexFilter(id, jsonClips, localMP4File) {
const startTime = Date.now();
let i = 0;
let complexFilterArray = [];
for (const clip of jsonClips.clips) {
console.log(`Extracting clip_${i}`);
complexFilterArray.push(`[0:v]trim=start=${utils.parseTime(clip.startTimestamp)/1000}:end=${utils.parseTime(clip.endTimestamp)/1000},setpts=PTS-STARTPTS[v_clip_${i}]`);
complexFilterArray.push(`[0:a]atrim=start=${utils.parseTime(clip.startTimestamp) / 1000}:end=${utils.parseTime(clip.endTimestamp) / 1000},asetpts=PTS-STARTPTS[a_clip_${i++}]`);
break; // only do one clip for now
}
let mapArray = [];
let outputArray = [];
for (let j = 0; j < i; j++) {
mapArray.push(`-map '[v_clip_${j}]' -map '[a_clip_${j}]'`);
outputArray.push(`clip_${j}.mp4`);
}
/* This CLI works
ffmpeg -i test.mp4 -filter_complex
[0:v]trim=start=1948.605:end=2038.755,setpts=PTS-STARTPTS[v_clip_0];
[0:a]atrim=start=1948.605:end=2038.755,asetpts=PTS-STARTPTS[a_clip_0];
...
[0:v]trim=start=5041.255:end=5131.045,setpts=PTS-STARTPTS[v_clip_10];
[0:a]atrim=start=5041.255:end=5131.045,asetpts=PTS-STARTPTS[a_clip_10];
-map '[v_clip_0]' -map '[a_clip_0]' clip_0.mp4
...
-map '[v_clip_10]' -map '[a_clip_10]' clip_10.mp4
*/
ffmpeg(localMP4File)
.complexFilter(complexFilterArray)
.output('clip_0.mp4')
.map('[v_clip_0]')
.map('[a_clip_0]')
.on('error', error => console.log('Error: ' + error.message))
.on('end', () => console.log('Success!'))
.run();
console.log(`Extracted ${complexFilterArray.length} clips in ${Date.now()-startTime}`);
return {status: 200} // TODO: failure
}
(note: if the problem only happens with some inputs, include a link to such an input file)
Expected results
I pass a json array of clip information with start and end timestamps. The number of clips could vary from 1-50.
What I want is a way to define an array of outputs and maps at runtime and create a number of clips.
Observed results
A single clip works as above. The ffmpeg command works for multiple clips as above. I've had various attempts to pass arrays to output and map without success.
Checklist
Forgot about ChatGPT... In the spirit of OpenAI ripping off github, I present to you a working example (note the loop on .input and .output):
const extractClipCommand = ffmpeg();
jsonClips.clips.forEach((clip, index) => {
extractClipCommand.input(localMP4File);
});
let complexFilterArray = [];
console.log("create complexFilterArray");
jsonClips.clips.forEach((clip, index) => {
complexFilterArray.push(`[0:v]trim=start=${utils.parseTime(clip.startTimestamp)/1000}:end=${utils.parseTime(clip.endTimestamp)/1000},setpts=PTS-STARTPTS[v_clip_${index}]`);
complexFilterArray.push(`[0:a]atrim=start=${utils.parseTime(clip.startTimestamp) / 1000}:end=${utils.parseTime(clip.endTimestamp) / 1000},asetpts=PTS-STARTPTS[a_clip_${index}]`);
});
extractClipCommand.complexFilter(complexFilterArray);
console.log("create output and maps");
// Map the outputs
jsonClips.clips.forEach((clip, index) => {
extractClipCommand.output(`clip_${index}.mp4`)
.map(`[v_clip_${index}]`)
.map(`[a_clip_${index}]`);
});
// Run the command
console.log("Run the command");
extractClipCommand
.on('error', function(err) {
console.log('An error occurred: ' + err.message);
})
.on('end', function() {
console.log(`Extracted ${complexFilterArray.length/2} clips in ${Date.now()-startTime}`);
})
.run();
I should point out however that with a 1GB mp4 and more than 3 clips, ffmpeg runs out of memory and is killed...