2

I use FFmpeg to extract a keyframe at the 3rd minute. This means that it is the 3*60*25 th frame (assuming 25 FPS). Now, often this frame is not a keyframe.

I want to extract a frame closest to the above frame but ensure that it is a keyframe. This means the frame may occur a few seconds before or after the third minute of the video.

I have looked everywhere without any luck! I am doing this on Linux, so if you are using a FFmpeg with something specially installed or bundled, let me know!

slhck
  • 223,558
  • 70
  • 607
  • 592
cnfcnf
  • 263
  • 4
  • 9

2 Answers2

5

Using -ss parameter with select filter would work.

Something similar to:

ffmpeg -ss 180 -i yourvideo.mp4 -vf select="eq(pict_type\,I)" -vframes 1 thumbnails.jpeg
slhck
  • 223,558
  • 70
  • 607
  • 592
d33pika
  • 1,851
  • 4
  • 15
  • 14
  • I think it is a fair attempt! Why would you down vote it? agree i missed -vframes 1 – d33pika Jan 17 '13 at 07:43
  • 1
    The important part is the concept using -ss and the select filter to pick only I frames. the OP can workout a solution form there. I do not have to spoon feed an answer! – d33pika Jan 17 '13 at 07:46
  • I have tried it. It does generate an image!, the position of -ss before or after -i is indeed a choice one has to make. I think before is faster, I am assuming that OP is ok with finding a Key frame after 3 minutes, that is a big assumption I admit. – d33pika Jan 17 '13 at 08:02
  • Okay, I tested it again with the options placed like that (also changing `PICT_TYPE_I` to `I`), and it worked now as expected, +1 anyway (I removed a few obsolete options that don't matter in this case) – slhck Jan 17 '13 at 08:06
  • I tried this and while the code worked, it appears that my problem is a little more complex. I have a TV show in MP4 format. My hope is to extract one or more frames which are "crisp and high quality" allowing for display on a large screen. I assumed these would be keyframes, but alas I was wrong. It appears that some of the keyframes are blurry. These keyframes appear to have some ghosting - they are likely frames between 2 different scenes in the video and have elements of both scenes in them. Is there a way to prevent FFMPEG from extracting these blurry or "ghost" frames/snapshots? – cnfcnf Jan 29 '13 at 05:28
  • 1
    Did you look at this: http://superuser.com/questions/538112/meaningful-thumbnails-for-a-video-using-ffmpeg , I have shared what I use to pick good thumbnails from a video. – d33pika Jan 29 '13 at 05:43
  • Thanks! I did look at the code. I was confused about how "scene change" worked because on quite a few instances I got overlapping and blurry images like: https://docs.google.com/file/d/0Bw3aqITChAhaWkU5VUZELWFSdjg/edit I would imagine that something like this should never happen? – cnfcnf Feb 14 '13 at 16:15
  • This looks like Interlaced content.In Interlace video, alternate rows can belong to a different scene. And the image is a valid scene change, the two fields have different scenes. You can de-interlace the video before picking thumbnails. – d33pika Feb 15 '13 at 01:31
2

If you assume that the closest I-frame to 00:03:00 appears before that timestamp, you'll have to do some guessing, since the GOP length (the number of frames between each I-frame) isn't the same for each video. If you know your GOP length, e.g. 125 frames, then start 5 seconds before that, at 00:02:55, for example.

Note that this doesn't have to be a fixed length. Good encoders will place an I-frame at scene cuts rather than fixed points to achieve better compression and reliability.

So, let's shift the input by the amount of time we calculated before, using -itsoffset.

We specify the select filter to get us only I-frames, and -vframes to only receive one frame. Finally, write that to a .jpg file.

ffmpeg -itsoffset -00:02:55 -i in.mp4 -filter:v select='eq(pict_type\,I)' -vframes 1 out.jpg

I tested this with a video that originally has a P-frame at 00:03:00, and I received the 13th frame after that, which is the start of a new scene—an I-frame.

slhck
  • 223,558
  • 70
  • 607
  • 592