Dump last frame of video file using ffmpeg/mencoder/transcode et. al
Asked Answered
L

5

18

I'd like to grab the last frame in a video (.mpg, .avi, whatever) and dump it into an image file (.jpg, .png, whatever). Toolchain is a modern Linux command-line, so things like mencoder, transcode, ffmpeg &c.

Cheers, Bob.

Lodmilla answered 9/3, 2011 at 15:48 Comment(0)
R
24

This isn't a complete solution, but it'll point you along the right path.

Use ffprobe -show_streams IN.AVI to get the number of frames in the video input. Then

ffmpeg -i IN.AVI -vf "select='eq(n,LAST_FRAME_INDEX)'" -vframes 1 LAST_FRAME.PNG

where LAST_FRAME_INDEX is the number of frames less one (frames are zero-indexed), will output the last frame.

Rodriguez answered 3/11, 2011 at 23:53 Comment(3)
Thanks. Really helped me out there. I copied your commands without any changes.Jesuit
I made a shell script out of these instructions. gist.github.com/NelsonMinar/b00693feecc3b6673e36Paleolithic
Isn't this going to decode all frames, while seeking might be able to use key frames to skip a bunch of the video?Farci
K
4

I have a mp4 / h264 matroska input video file. And none of the above solutions worked for me. (Although I sure they work for other file formats).

Combining samrad's answer above and also this great answer and came up with this working code:

input_fn='output.mp4'

image_fn='output.png'

rm -f $image_fn

frame_count=`ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames -of default=nokey=1:noprint_wrappers=1 $input_fn`

ffmpeg -i $input_fn -vf "select='eq(n,$frame_count-1)'" -vframes 1 "$image_fn" 2> /dev/null
Klapp answered 21/2, 2019 at 8:44 Comment(0)
V
1

One thing I have not seen mentioned is that the expected frame count can be off if the file contains dupes. If your method of counting frames is causing your image extraction command to come back empty, this might be what is mucking it up.

I have developed a short script to work around this problem. It is posted here.

Verda answered 18/11, 2013 at 16:54 Comment(0)
H
1

I couldn't get Nelson's solution to work. This worked for me. https://gist.github.com/samelie/32ecbdd99e07b9d8806f

EDIT (just in case the link disappears, here is the shellscript—bobbogo):

#!/bin/bash

fn="$1"
of=`echo $1 | sed s/mp4/jpg/`

lf=`ffprobe -show_streams "$fn" 2> /dev/null | grep nb_frames | head -1 | cut -d \= -f 2`
rm -f "$of"
let "lf = $lf - 1"
ffmpeg -i $fn -vf select=\'eq\(n,$lf\) -vframes 1 $of
Highway answered 18/2, 2015 at 9:51 Comment(2)
No need for grep, head, or cut. Just use ffprobe.Doucet
Downvoted. If you're going to post a script that will delete the original video (without prompt!) for any non-mp4 despite the original question specifically listening two non-mp4 video formats, at least write a disclaimer. In bold. So you don't screw other people over.Evslin
M
1

I found that I had to add -vsycn 2 to get it to work reliably. Here's the full command I use:

ffmpeg -y -sseof -3 -i $file -vsync 2 -update 1 -vf scale=640:480 -q:v 1 /tmp/test.jpg

If you write to a NFS folder then the results will be very inconsistent. So I write to /tmp then copy the file once done. If it is not done, I do a kill -9 on the process ID.

Mathewmathews answered 19/8, 2020 at 19:24 Comment(1)
It works, but others should get rid of scale=640:480.Aftercare

© 2022 - 2024 — McMap. All rights reserved.