I use
handle.thumbnails({
filename: output,
count: 3,
timemarks: ['20%', '40%', '60%']
}, outputDir);
The resulting fluent-ffmpeg command is something like this
ffmpeg -ss 508.1740876 -i /files/6ad6f3c5bd59cee74fdacb56eec45519.mp4
-y -filter_complex split=3[screen0][screen1][screen2] -vframes 1 -map [screen0]
/files/thumbs/6ad6f3c5bd59cee74fdacb56eec45519.mp4_1.png -vframes 1 -map [screen1] -ss
508.1740876 /files/thumbs/6ad6f3c5bd59cee74fdacb56eec45519.mp4_2.png -vframes 1 -map [screen2]
-ss 1016.3481752000001 /files/thumbs/6ad6f3c5bd59cee74fdacb56eec45519.mp4_3.png
This seems to be _really_ slow with large files (~1gb).
Instead, if i launch the same ffmpeg executable like this (only asking 1 screenshot)
ffmpeg -ss 1016.3481752000001 -i /files/6ad6f3c5bd59cee74fdacb56eec45519.mp4 -y
-vframes 1 /files/thumbs/6ad6f3c5bd59cee74fdacb56eec45519.mp4_3.png
then it's SUPER fast. I am no expert when it comes to ffmpeg cli. Do you see something that is obviously wrong with the former ?
I think i got it. If i use -ss before -i then the seek is very fast. If you do it after -i the seek will decode all the frames of the files. I don't think there is a way to do multiple screenshots with -ss before -i. So i have to create multiple and separate commands.
Better ways ?
Yes it's because -ss is not before -i and you need to add that before each input.
So here's a working example that takes it out super fast.
ffmpeg -ss 10 -i test.avi -frames:v 1 -f image2 -map 0:v:0 thumbnails/output_0.png -ss 800 -i test.avi - frames:v 1 -f image2 -map 1:v:0 thumbnails/output_1.png -ss 2400 -i test.avi -frames:v 1 -f image2 -map 2:v:0 thumbnails/output_2.png
It adds the screenshots to a thumbnails folder.
Hope that helps :)
.thumbnails() is a crude approach that does the job but is not guaranteed to be the best way.
For specific needs use your own solution, @Muqito 's idea of using the same input multiple times is a good way to go. You can code that with fluent-ffmpeg without any issues.
Closing this because it has not had any activity for months. Feel free to reopen if you still have issues/questions :)
The best thing to do call the ffmpeg function after each onEnd event like below. This helped me to generate thumbnails < 1 sec which was 1/100th time before what I was using.
ffmpeg(DirectoryPath + FileName)
.on('end', function (files) {
ffmpeg(values.DirectoryPath + values.FileName)
.on('end', function (files) {
// place next ffmpeg function here
})
.screenshots({
count: 1,
timestamps: ['75%'],
filename: VideoUniqId + '_2' + thumbnailExtension,
folder: _thumbSaveLocation
});
})
})
.screenshots({
count: 1,
timestamps: ['25%'],
filename: VideoUniqId + '_1' + thumbnailExtension,
folder: _thumbSaveLocation
});
@aravindnc Oh, that's Great!
I write simpler codes by using your idea, like this:
const fs = require("fs");
const path = require("path");
const ffmpeg = require("fluent-ffmpeg");
const count = 10;
const timestamps = [];
const startPositionPercent = 5;
const endPositionPercent = 95;
const addPercent = (endPositionPercent - startPositionPercent) / (count - 1);
let i = 0;
if (!timestamps.length) {
let i = 0;
while (i < count) {
timestamps.push(`${startPositionPercent + addPercent * i}%`);
i = i + 1;
}
}
function takeScreenshots(file) {
ffmpeg(file)
.on("start", () => {
if (i < 1) {
console.log(`start taking screenshots`);
}
})
.on("end", () => {
i = i + 1;
console.log(`taken screenshot: ${i}`);
if (i < count) {
takeScreenshots(file);
}
})
.screenshots({
count: 1,
timemarks: [timestamps[i]],
filename: `%b-${i + 1}.jpg`
}, path.join(path.dirname(file), `screenshots`));
}
@matori Awesome ;)
Thank you @davibe for the question, everyone for the discussion, and @matori for a ready-to-use solution. I spent over a day trying different things and even started figuring out a way to use ffmpeg directly from my node project abandoning fluent-ffmpeg. I would highly recommend (@njoyard) sharing a link to this discussion as a caveat under screenshots to save others the headache 馃憤
Just in case anyone end here from googling "ffmpeg slow to take screenshot" this is super fast.
ffmpeg -i "$1" -ss 00:28:0.0 -vframes 1 "${1%.*}".screenshot1.png
@matori Great solution, thanks!
@aravindnc Oh, that's Great!
I write simpler codes by using your idea, like this:const fs = require("fs"); const path = require("path"); const ffmpeg = require("fluent-ffmpeg"); const count = 10; const timestamps = []; const startPositionPercent = 5; const endPositionPercent = 95; const addPercent = (endPositionPercent - startPositionPercent) / (count - 1); let i = 0; if (!timestamps.length) { let i = 0; while (i < count) { timestamps.push(`${startPositionPercent + addPercent * i}%`); i = i + 1; } } function takeScreenshots(file) { ffmpeg(file) .on("start", () => { if (i < 1) { console.log(`start taking screenshots`); } }) .on("end", () => { i = i + 1; console.log(`taken screenshot: ${i}`); if (i < count) { takeScreenshots(file); } }) .screenshots({ count: 1, timemarks: [timestamps[i]], filename: `%b-${i + 1}.jpg` }, path.join(path.dirname(file), `screenshots`)); }
Hi @matori, sorry to ask, but I am really newbie in cmd commands. So, how can I run this script in win10? I have a folder with several videos files. I want to take 6 screenshots of each video file, starting with 3 minutes and 30 seconds distance each others and save in a desktop folder.
Most helpful comment
@aravindnc Oh, that's Great!
I write simpler codes by using your idea, like this: