Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to write multiple output files from a complex filter? #1269

Open
ChrisMICDUP opened this issue May 2, 2024 · 1 comment
Open

Comments

@ChrisMICDUP
Copy link

ChrisMICDUP commented May 2, 2024

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

@ChrisMICDUP
Copy link
Author

ChrisMICDUP commented May 3, 2024

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...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant