Video Keyframe and Iframe - ffmpeg

I have confused one thing for Video Frame extraction.
I have sample.mp4 video, 15FPS.
I tried extracting Keyframe with FFMPEG.
ffmpeg -skip_frame nokey -i sample.mp4 -vsync 0 -frame_pts true out%d.png
I get 29 Pictures and I believe I have got 29 I frames. (If I have wrong, Please correct me)
Then I tried extracting specific timeline(10 sec) frame with picture
ffmpeg -i sample.mp4 -ss 00:00:10 -frames:v 1 test1.png
This output picture, I can not find same one among my Keyframes I get.
Question: test1.png, What is frame type? Does it one of P or B frame not I?

I get 29 Pictures and I believe I have got 29 I frames. (If I have wrong, Please correct me)
Correct. See Checking keyframe interval? to verify.
Question: test1.png, What is frame type? Does it one of P or B frame not I ?
Use ffprobe:
ffprobe -select_streams v -show_entries "frame=pkt_pts_time,pict_type" -of csv input.mp4
Example output:
frame,9.968000,B
frame,10.010000,B <---
frame,10.052000,P
Note that in this example -ss 00:00:10 rounded up to the nearest frame (10.010000). This is a B-frame in this example (input.mp4).

Related

webm files created with ffmpeg are too long

I have a folder of exactly 300 images in png format (labelled 1.png, 2.png, ..., 300.png), which I'm trying to convert to a video. I would like the video to be in the webm format, but there seems to be an issue:
using the following command:
ffmpeg -start_number 1 -i ./frames/%d.png -frames:v 300 -r 30 out.webm
does generate an out.webm file, and, according to ffprobe -select_streams v -count_frames -show_entries stream=nb_read_frames,r_frame_rate out.webm (which is presumably quite an inefficient way to get that information, but that's besides the point), it does contain 300 frames and has a framerate of exactly 30/1, however, instead of the expected exactly 10 seconds (from 300 frames being played at 30 fps), the video lasts slightly longer (about 12 seconds).
This discrepancy does seem to scale up with video length; 900 frames being converted to a video the same way and with the same frame rate yield a 36 (instead of 30) second video.
For testing, I also tried generating an mp4 file instead of a webm one, with the following command (exact same as above, but out.mp4 instead of out.webm), and that worked exactly as expected, out.mp4 was a 10-second long video.
ffmpeg -start_number 1 -i ./frames/%d.png -frames:v 100 -r 30 out.mp4
How do I fix this? is my ffmpeg command off or is this a bug within the tool?
The documentation ( https://www.ffmpeg.org/ffmpeg.html ) has an example:
For creating a video from many images: ffmpeg -f image2 -framerate 12
-i foo-%03d.jpeg -s WxH foo.avi
and
To force the frame rate of the input file (valid for raw formats only)
to 1 fps and the frame rate of the output file to 24 fps: ffmpeg -r 1
-i input.m2v -r 24 output.avi
and also
As an input option, ignore any timestamps stored in the file and
instead generate timestamps assuming constant frame rate fps. This is
not the same as the -framerate option used for some input formats like
image2 or v4l2 (it used to be the same in older versions of FFmpeg).
If in doubt use -framerate instead of the input option -r.
For your case result:
ffmpeg -framerate 30 -i ./frames/%d.png output.webm

How to make tiled image from video with ffmpeg

I want to generate tiled image from video with ffmpeg.
Every part of image is screenshot of video with different moment.
The example from the documentation is:
ffmpeg -skip_frame nokey -i file.avi -vf 'scale=128:72,tile=8x8' -an -vsync 0 keyframes%03d.png
Get rid of -skip_frame nokey if you want to get every frame.

Non-consistent results between ffprobe and ffmpeg for keyframes identification

Trying to identify both thumbnails and timestamps of keyframes on a set of videos, I'm getting different results from ffmpeg and ffprobe.
Taking a 1 min. long video as an example:
youtube-dl -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' 'https://www.youtube.com/watch?v=BHlAlN3z4ss' --output "test.mp4"
1/ I extract thumbnails and write on the image the timestamp at which it was extracted:
ffmpeg -i test.mp4 -q:v 2 -vf select="eq(pict_type\,PICT_TYPE_I)","drawtext=fontfile=/path/to/Arial.ttf:fontsize=45:fontcolor=yellow:box=1:boxcolor=black:x=(W-tw)/2:y=H-th-10:text='Time\: %{pts\:hms}'" -vsync 0 thumbs/preview%05d.jpg
2/ I extract and save the timestamps of all keyframes:
ffprobe -v error -skip_frame nokey -show_entries frame=pkt_pts_time -select_streams v -of csv=p=0 test.mp4 | sort -n > keyframes_timestamps.txt
3/ Comparing results, I figure ffprobe found 29 keyframes, while ffmpeg found only 32. Comparing manually, we can see that specific keyframes are not detected by ``ffprobe` while most are very similar.
ffprobe_ts ffmpeg_ts
0.000000 00:00:00.00
5.366667 00:00:05.367
7.200000 00:00:07.200
8.666667 00:00:08.667
10.100000 00:00:10.100
11.500000 00:00:11.500
14.233333 00:00:14.233
15.333333 00:00:15.333
17.366667 00:00:17.367
NO_TS 00:00:18.833
20.800000 00:00:20.800
24.533333 00:00:24.533
25.700000 00:00:25.700
26.033333 00:00:26.033
On larger videos, this happens for around less that 5% of the keyframes.
I can't find an explanation about that, does anyone have a clue ? or an advice on where/what I should inquire further ?
Thanks for your help !
Not all I-frames are keyframes. -skip_frame nokey will skip non-KF I-frames.

Extracting the index of frame selected by ffmpeg thumbnail filter

I use the following command for extracting the representative frame out of every 10 frames from the video.
ffmpeg -i input.avi -r 10 -vf thumbnail=10 -vsync 0 ./Output/%06d.png
If i get the 4th frame selected from 10-20th frames, i want to know the 2nd frame selected was 24th in the original one.
Right now the output is continuous 1,2,3.. n.png
Use
ffmpeg -i input.avi -vf thumbnail=10 -vsync 0 -frame_pts 1 ./Output/%06d.png
You'll need ffmpeg 4.0 or later.

ffmpeg keyframe extraction

I have been trying to extract keyframes from video using ffmpeg 0.11.1 . So far all the commands I have tried do not extract keyframes but return all the frames ie 25fps*total time number of frames in the output.
I tried setting the keyint_min as 25 to make sure there is a amximum of 1 keyframe per second.
ffmpeg -vf select="eq(pict_type\,PICT_TYPE_I)" -g 250 -keyint_min 25 -i C:\test.mp4 -vsync 2 -f image2 C:\testTemp\thumbnails-%02d.jpeg
But still all the frames are returned.
Then i tried, to separate the keyframes by 20 seconds.
ffmpeg -i C:\test.mp4 -vf select='eq(pict_type\,I)*(isnan(prev_selected_t)+gte(t-prev_selected_t\,20))' -vsync 0 -f image2 C:\testTemp\%09d.jpg
Again same result, all the frames are returned.
What should I do?
In your first command you are using the filter as an input option. I don't know how ffmpeg will interpret that.
Try this:
ffmpeg -i C:\test.mp4 -vf select='eq(pict_type\,I)',setpts='N/(25*TB)' C:\testTemp\%09d.jpg
Change 25 to the frame rate of your source: 30000/1001 for NTSC video, 24000/1001 for NTSC film, 25 for PAL, etc.
Control output quality with the -q:v or -qscale:v option (just called -qscale in old ffmpeg). Range for mpeg* is 1-31 where 31 is the worst quality.
Next time remember that ffmpeg usage questions are to be asked at superuser.com since stackoverflow is specifically for programming.

Resources