How to create a thumbnail from the middle of a video with FFmpeg

9

2

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.

StackOverflowNewbie

Posted 2012-09-20T06:08:10.157

Reputation: 233

Answers

9

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

Prometee

Posted 2012-09-20T06:08:10.157

Reputation: 91

1-vcodec mjpeg -an -f rawvideo is not needed when your output is just a .jpg file. I'd actually recommend outputting to PNG instead and doing the compression later. – slhck – 2017-10-12T16:13:31.353

2

The ffmpeg output is only for informative purposes only and not intended for parsing, so therefore processing it may be considered fragile. Use ffprobe to get the duration instead. See FFmpeg Wiki: FFprobe Tips.

– llogan – 2017-10-12T18:52:21.353

5

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.

slhck

Posted 2012-09-20T06:08:10.157

Reputation: 182 472

Is there a way to skip the "waiting" part? Fast-forward to the specified frame/time ? – Samson – 2015-11-20T14:38:40.477

@Samson Which solution exactly are you talking about? If you specify -ss before -i, seeking should be much faster. – slhck – 2015-11-23T12:35:18.280

An alternate way to specify thumbnail dimensions - this example crops it to a 4:3 aspect ratio: ffmpeg -y -i input.mp4 -vf "crop=(ih*4/3):ih" -f mjpeg -vframes 1 -ss 534 thumbnail.jpg – rymo – 2014-01-05T03:47:52.740

2

Here's a method using:

  • ffprobe to get the duration
  • bc to calculate half the duration
  • ffmpeg to make the thumbnail image

Example:

input=video.mp4
duration=$(ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 "$input")
ffmpeg -ss "$(echo "$duration"/2 | bc)" -i "$input" -q:v 2 -vframes 1 output.jpg
  • You can replace my lazy usage of bc with your favorite alternative, such as awk or printf, if you prefer.

  • You can scale/resize the image by adding the scale filter as an output option in your ffmpeg command, such as -vf scale=320:-1.

  • The duration supplied by ffprobe may not always be accurate depending on the input. In the unlikely case that you have such an issue you will have to fully decode the input, such as with ffmpeg -i input -f null -, and parse the output to get the correct duration value.

llogan

Posted 2012-09-20T06:08:10.157

Reputation: 31 929

0

$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

Ethan SK

Posted 2012-09-20T06:08:10.157

Reputation: 31

0

Simple solution is :

 ffmpeg -i l1.mp4 -ss 00:00:14.435 -vframes 1 out.png

Pankaj Chauhan

Posted 2012-09-20T06:08:10.157

Reputation: 101

1

This looks a lot like Prometee’s answer and LordNeckbeard’s answer except you assume that the user already knows the length of the video (the question says that they don’t) and you don’t explain anything.

– Scott – 2018-09-28T07:29:08.170

I gives just example, if no need time then try this ffmpeg -i l1.mp4 -vframes 1 out11.jpg – Pankaj Chauhan – 2018-09-28T08:23:11.627

-1

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

Георги Стефанов

Posted 2012-09-20T06:08:10.157

Reputation: 1

1My god that's complicated – Sridhar Sarnobat – 2015-03-18T18:22:07.917