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.
Asked
Active
Viewed 1.1k times
4 Answers
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
-
1If 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

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