12

I'm wondering how to use FFMpeg to grap the middle frame of a video. I've already written the C# to grab a frame at a certain time (ie pull one frame at second 3). But I've yet to figure out how to find the middle of video using the FFMpeg commands.

Jon Dewees
  • 2,957
  • 6
  • 31
  • 38

4 Answers4

11

This could be simplified, but here's some old PHP code I had lying around that should do the trick. (Add the location to ffmpeg if it's not in your path)

$output = shell_exec("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("ffmpeg -y  -i {$path} -f mjpeg -vframes 1 -ss " . ($total_seconds / 2) . " -s {$w}x{$h} {$output_filename}");   
marcusds
  • 784
  • 1
  • 7
  • 26
Derek Gathright
  • 741
  • 5
  • 10
  • @Derek Gathright Please give me basic detail to start working with ffmpeg. Please have a look my [question](http://stackoverflow.com/questions/10071408/how-to-get-frames-of-video-file-in-android). – Ashish Dwivedi Apr 25 '12 at 04:56
9

With simple shell scripting you can use ffprobe to get a machine readable duration output, bc to calculate the half point, and ffmpeg to make the frame:

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

This eliminates any need for PHP, echo, awk, tr, grep, sed, etc.

llogan
  • 121,796
  • 28
  • 232
  • 243
  • On Windows/Cygwin I had to do an ugly kludge text processing of the output of eval / ffprobe to eliminate a windows newline from the end of $format_duration: `eval "$(ffprobe -v error -of flat=s=_ -show_entries format=duration tmp.mp4)"` `echo $format_duration > tmp.txt` `echo /2 >> tmp.txt` `dos2unix tmp.txt` format_duration=``tr -d '\n' < tmp.txt`` If someone knows a more elegant means of using $format_duration on Windows, I'd be glad to know it. – Alex Hall Nov 11 '17 at 15:39
  • There's a set of backticks surrounding the variable assignment after format_duration in the last part of my comment (which is eliminated here by markdown parsing). – Alex Hall Nov 11 '17 at 15:47
  • 1
    Wish I could have upvoted more. Thanks for the simple two-liner. – Eric Chen Mar 21 '18 at 22:04
  • 1
    If the video is less than two seconds long, `bc` returns a number without the leading zero, e.g. `.987`, which causes an error: `Invalid duration specification for ss: .987`. It seems that additional leading zero is ok for `ss`, so I'm adding a `0` here: `... -ss 0"$(bc ...`. See also: https://unix.stackexchange.com/questions/197896/how-to-show-zero-before-decimal-point-in-bc – tuomassalo Jan 08 '19 at 19:36
4

FFmpeg helps you get the framerate and the length of the video, so you can multiply one by the other and divide by 2 to get the number of the middle frame.

ie for a 30 seconds video running at 15 frames per second : 30 * 15 = 450 / 2 = 225, meaning you need to grab the 225th frame.

Nicolas
  • 2,158
  • 1
  • 17
  • 25
-1

This bash command works like a charm (tested):

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
lennon310
  • 12,503
  • 11
  • 43
  • 61