Reputation: 3219
I'm trying to write a simple js application that takes all video files in a directory and the produce one single video consisting of all the clips combined one after another into one timeline.
To test the application I have download for random short stock video clips from pexels:
Shown in order: clip 1, clip 2, clip 3, clip 4
Each of the clips plays perfectly in vlc on windows (no broken or frozen frames)
I use the following script to concat the clips:
const ffmpeg = require('fluent-ffmpeg');
ffmpeg()
.input(concatFilePath)
.inputOptions(['-f concat', '-safe 0'])
.outputOptions(['-c copy', '-c:v libx264', '-b:v 5M', '-r 30', '-preset', 'slow'])
.on('end', () => {
console.log('Video clips concatenated successfully.');
})
.on('error', (err) => {
console.error('Error concatenating video clips:', err);
// Cleanup: Delete the output folder
console.log('Cleaning up...');
deleteOutputFolder(outputDir);
})
.save(outputPath);
The contect of my concatFilePath
(concat.txt) file looks like this:
file src\input\d69de4a3-2b72-462c-be70-f8b8287b45e0\pexels-fred-c-19065853 (Original).mp4
file src\input\d69de4a3-2b72-462c-be70-f8b8287b45e0\pexels-imad-clicks-16270463 (2160p).mp4
file src\input\d69de4a3-2b72-462c-be70-f8b8287b45e0\pexels-peter-fowler-9683061 (2160p).mp4
file src\input\d69de4a3-2b72-462c-be70-f8b8287b45e0\pexels-sascha-5799767 (1080p).mp4
The problem
When I run the program it takes about 15 seconds to render the output video. The first clip looks as the stock clip, but when I get to the 2nd clip it just sits frozen at the first fram of that video, and only runs for 3-4 seconds despite the stock clip is 8 seconds long. It then transitions into the 3rd clip which is renderd correctly but the rest of the video is frozen on the last frame of clip 3 instead of showing clip 4.
I'm assuming that my input options are to blame for the result of the output, I have tried various other input options suggested from github thread and other sources, but none of them have produces a reasonable result.
Upvotes: 0
Views: 200
Reputation: 3219
I found a working solution. The problem seemed to be that the videos are of different encoding, and doesn't just concat perfectly - some of them did, some of them didn't. So I decided to try to streamline the video format by first converting every clip individually to the same h264 format, and that had a positive effect.
I also decided to ditch fluent-ffmpeg
since there's not much documentation or information online compared to the native ffmpeg
commands. So instead I interact directly with ffmpeg
through exec
.
// step 1. convert videos to h264
const tempFolder = path.join(outputDir, 'temp');
if (!fs.existsSync(tempFolder)) {
fs.mkdirSync(tempFolder, { recursive: true });
}
for (let i = 0; i < videoClipPaths.length; i++) {
const inputVideo = videoClipPaths[i];
const outputVideo = `${tempFolder}/video_${i}.mp4`;
await exec(`ffmpeg -i "${inputVideo}" -c:v libx264 -b:v 5M -r 22 -preset slow -c:a aac -b:a 192k "${outputVideo}"`);
}
// step 2. create concat file
const concatFilePath = path.join(tempFolder, 'concat.txt');
const fileList = videoClipPaths.map((_, i) => `file 'video_${i}.mp4'`).join('\n');
await fs.promises.writeFile(concatFilePath, fileList);
// step 3. compile and render final video
await exec(`ffmpeg -f concat -safe 0 -i ${concatFilePath} -c copy ${outputPath}`);
Upvotes: 1