Is there a way to grab a video thumbnail in FFmpeg?
I'd like to grab the middle-most frame as the video and use that as the thumbnail. Video duration is unknown.
The ability to specify the dimensions of the thumbnail would also be helpful.
Is there a way to grab a video thumbnail in FFmpeg?
I'd like to grab the middle-most frame as the video and use that as the thumbnail. Video duration is unknown.
The ability to specify the dimensions of the thumbnail would also be helpful.
One line command :
ffmpeg -i input.mp4 -vcodec mjpeg -vframes 1 -an -f rawvideo -ss `ffmpeg -i input.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d , | awk -F ':' '{print ($3+$2*60+$1*3600)/2}'` output.jpg
The subcommand get the total duration of the input video
ffmpeg -i input.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,
And pipe it to awk to compute duration/2 like this
echo '00:01:30.000' | awk -F ':' '{print ($3+$2*60+$1*3600)/2}'
So it give this among of seconds to -ss option and it's done.
If you would like to specify the size, add -s option like that WxH where W and H are integer values (ex: -s 800x600 or -s svga) or read the ffmpeg man page to see other available options or format.
Here's a method using:
ffprobe to get the durationbc to calculate half the durationffmpeg to make the thumbnail imageExample:
input=input.mp4; ffmpeg -ss "$(bc -l <<< "$(ffprobe -loglevel error -of csv=p=0 -show_entries format=duration "$input")*0.5")" -i "$input" -frames:v 1 half.png
First of all, always use the latest version of FFmpeg.
If you have access to PHP, your question is perfectly answered on Stack Overflow: Use FFMpeg to get middle frame of a video?
$output = shell_exec("/usr/local/bin/ffmpeg -i {$path}");
preg_match('/Duration: ([0-9]{2}):([0-9]{2}):([^ ,])+/', $output, $matches);
$time = str_replace("Duration: ", "", $matches[0]);
$time_breakdown = explode(":", $time);
$total_seconds = round(($time_breakdown[0]*60*60) + ($time_breakdown[1]*60) + $time_breakdown[2]);
shell_exec("/usr/local/bin/ffmpeg -y -i {$path} -f mjpeg -vframes 1 -ss " . ($total_seconds / 2) . " -s {$w}x{$h} {$output_filename}";
What it'll do is just extract the duration from FFmpeg's output and use that to determine the timecode of the middle frame.
You can easily adapt that to other shells, and simply insert into the following command, where the middle frame is roughly at 534 seconds:
ffmpeg -y -i input.mp4 -f mjpeg -vframes 1 -ss 534 thumbnail.jpg
You can always change the size with -s 480x320 or similar, depending on how big you want it, inserted somewhere after the -i input.mp4 option.
The above solution is a little inaccurate. It'll immediately give you a result but you can't specify which frame you want. If you already know the exact frame you want to extract, use the select filter, e.g. with the frame number 12345:
ffmpeg -i input.mp4 -filter:v select="eq(n\,12345)" -vframes 1 thumbnail.jpg
Note that this command can take a while since it needs to skip to the specified frame before it can extract it.
ffmpeg -y -i input.mp4 -vf "crop=(ih*4/3):ih" -f mjpeg -vframes 1 -ss 534 thumbnail.jpg
– rymo
Jan 05 '14 at 03:47
-ss before -i, seeking should be much faster.
– slhck
Nov 23 '15 at 12:35
$currentVideoDuration = shell_exec("$ffmpeg -i $videoPath 2>&1 | grep Duration");
$actualDuration = substr($currentVideoDuration, 11, 12);
$arrayWithHoursMinsAndSecs = explode(":", $actualDuration);
$thisVideoDurationInSeconds = $arrayWithHoursMinsAndSecs[2] + $arrayWithHoursMinsAndSecs[1]*60 + $arrayWithHoursMinsAndSecs[0]*3600;
$halfVideoDuration = $thisVideoDurationInSeconds/2;
echo 'midpoint of this video: '. $halfVideoDuration;
echo shell_exec("$ffmpeg -i $videoPath -y -ss 00:00:$halfVideoDuration -vframes 1 thumbnail.png 2>&1");
replace $videopath with the path to your video
Simple solution is :
ffmpeg -i l1.mp4 -ss 00:00:14.435 -vframes 1 out.png
This bash command works like a charm:
avconv -i 'in.mpg' -vcodec mjpeg -vframes 1 -an -f rawvideo \
-s 420x300 -ss `avconv -i in.mpg 2>&1 | grep Duration \
| awk '{print $2}' | tr -d , \
| awk -F ':' '{print ($3+$2*60+$1*3600)/2}'` out.jpg
-vcodec mjpeg -an -f rawvideois not needed when your output is just a.jpgfile. I'd actually recommend outputting to PNG instead and doing the compression later. – slhck Oct 12 '17 at 16:13ffmpegoutput is only for informative purposes only and not intended for parsing, so therefore processing it may be considered fragile. Useffprobeto get the duration instead. See FFmpeg Wiki: FFprobe Tips. – llogan Oct 12 '17 at 18:52