extract frames using ffmpeg and find out their offset (milliseconds) - ffmpeg

I wish to extract 10 consecutive frames every 2 seconds.
(this is because I wish to choose "best one" from the "nearby offset").
I know how to extract a frame each x seconds:
ffmpeg -i /tmp/V.MP4 -vf fps=1 %02d.jpg
I know how to extract 10 frames from some starting offset:
ffmpeg -ss 20.0 -i /tmp/V.MP4 -vframes 10 %02d.jpg
I have 2 issues:
How do I find the offset for each output image? I can try and calculate it (using the video fps, which is 29.97 in my case) but it sounds like a bad idea - the data is right there in the video for ffmpeg to grab..
Is there an efficient way to "merge" the two commands into one, therefore getting 10 consecutive frames each x seconds?

Use
ffmpeg -i source -vf select='eq(n,0)+if(mod(trunc(t)+1,2)*(trunc(t)-trunc(prev_t)),st(1,n),lt(n,ld(1)+10))' -vsync 0 -frame_pts 1 %d.jpg
How do I find the offset for each output image?
See what frame_pts values mean, at ffmpeg output images filename with time position
this is because I wish to choose "best one" from the "nearby offset"
the thumbnail filter can sort of do this.

Related

FFmpeg: create a video from a list of images, where each images stay N frames

I need to create a video from a list of images, in such a way that the final video should be 24fps, but each image should stay during 3 frames before showing the next image (and I don't want to change the fps, I really need 3 identical frames).
For now I'm using:
ffmpeg -framerate 24 -pattern_type glob -i "build/*.jpg" "$#"
but each image stays only one frame.
You need to combine the input and output frame rates to achieve this:
ffmpeg -framerate 8 -pattern_type glob -i "build/*.jpg" -r 24 "$#"
The input -framerate 8 sets to show each image for 1/8=0.125 seconds, and output -r 24 sets the output framerate to be 24 fps and use each input frame for 24/8=3 output frames.

How to extract the very first frame of a second in a video using ffmpeg?

I am trying to extract the first frame of a second from a video. I have tried different ways to achieve this, but I failed. Here the commands I tried.
ffmpeg -i input.ts -s 400x222 -q:v 3 -start_number 0 -vf fps=1 %d.jpg
Later, I am trying to extract the frames again using the below command of that particular second. Here I'm extracting the frames of 210th second.
ffmpeg -ss 210 -i input.ts -s 300x250 -t 1 -start_number 0 images.%d.jpg
I want to extract only the starting frame of the second. Let's say from 0.001 of that particular second.
When I compare the frame of 210 second extracted by my first command with the first frame extracted by second command are completely different.
For the later use, to prevent the conflicts I want to extract only the very first frame of the original input video. I tried using the command which was told by stackoverflow experts in the past here. But when I run it. It is only extracting the starting frame(only 1 frame).
How can I extract the very starting frame of the video per every second?
try this command :
ffmpeg -i input.mp4 -vf "select=between(mod(n\, 25)\, 0\, 0), setpts=N/24/TB" output-%04d.png
you have to pass your video framerate or fps in between(mod(n\, 25)\, 0\, 0) my video fps is 25 so i pass 25
if your fps 60 then you have to pass 60 in between(mod(n\, 60)\, 0\, 0)
also if you want 1st 5 frames of every second then use between(mod(n\, 25)\, 0\, 4) it will give your 1st 5 frames of every second.

FFMPEG, Extract first frame and hold for 5 seconds

I'm trying to overlay a 15 second video transition on the beginning of an image sequence (png sequence with an alpha to reveal the image below), which I can do fine with the overlay filter. But I want to hold the first frame of the image sequence for 5 seconds before playing the animation. I've tried trim/select but I can't seem to get it be a duration of 5 seconds, I also can't seem to concat it back with the other video to do the transition. So my questions are:
How do I get the first frame and hold it for 5 seconds, the method below works but doesn't seem like the cleanest option?
-framerate 30 -t 60.0 -i input1.%04d.jpg -framerate 30 -t 15.0 -i transition1_%03d.png -filter_complex "color=c=red:d=5:s=480x270:r=30[bg]; [bg][1:v]overlay[transhold]; [0:v][transhold]overlay=repeatlast=0[out]"
How can I concat that with the original before I overlay it on the main video, I can do it with two overlays with the start of the actual transition offset by the length of the hold using the command below, but it seems a bit clunky.
-framerate 30 -t 60.0 -i input1.%04d.jpg -framerate 30 -t 15.0 -i transition1_%03d.png -filter_complex "color=c=red:d=5:s=480x270:r=30[bg]; [1:v]split[trans][transhold]; [trans]setpts=PTS+5/TB[trans];[transhold]select=eq(n\0)[transhold];[bg][transhold]overlay[transhold]; [0:v][transhold]overlay=repeatlast=0[tmp1]; [tmp1][trans]overlay[out]"
This is all part of a larger command where I'm compiling four HD images into a 4k feed each with it's own transition so the cleaner I can be the better really. I'd also like to be able to vary the duration of the hold for the different HD inputs. If I need to I could bring in the first image as a different input but I would still need to concat them. I thought there must be a way to do this with filters...
This was answered in another post:
https://video.stackexchange.com/questions/23551/ffmpeg-extract-first-frame-and-hold-for-5-seconds
-framerate 30 -t 60.0 -i input1.%04d.jpg
-framerate 30 -t 15.0 -i transition1_%03d.png
-filter_complex
"[1]loop=149:1:0[trans];
[0][trans]overlay=eof_action=pass" out.mp4
The first frames of the second input is repeated 149 times, so that there are 150 instances (30 fps x 5s). The 0 at the end of loop is the starting index of the frame(s) to loop. The middle 1 is the number of frames to loop starting at the index in the 3rd argument.

FFMPEG- Convert video to images

how can i convert a video to images using ffmpeg? Example am having a video with total duration 60 seconds. I want images between different set of duration like between 2-6 seconds, then between 15-24 seconds and so on. Is that possible using ffmpeg?
Official ffmpeg documentation on this: Create a thumbnail image every X seconds of the video
Output one image every second:
ffmpeg -i input.mp4 -vf fps=1 out%d.png
Output one image every minute:
ffmpeg -i test.mp4 -vf fps=1/60 thumb%04d.png
Output one image every 10 minutes:
ffmpeg -i test.mp4 -vf fps=1/600 thumb%04d.png
You can use the select filter for a set of custom ranges:
ffmpeg -i in.mp4 -vf select='between(t,2,6)+between(t,15,24)' -vsync 0 out%d.png
Another way is to use ffmpeg library for python, particularly useful if you don't want to add ffmpeg to your pc environment. Start by installing ffmpeg on conda with:conda install ffmpeg
Then you can write a script as bellow:
import ffmpeg
input_file_name = 'input_video.mp4'
(ffmpeg
.input(input_file_name )
.filter('fps', fps=10, round = 'up')
.output("%s-%%04d.jpg"%(input_file_name[:-4]), **{'qscale:v': 3})
.run())
In addition to the select filter in Gyan's answer (which I use with eq rather than between), I came across another filter in the manual: thumbnail
Select the most representative frame in a given sequence of
consecutive frames.
The filter accepts the following options:
n: Set the frames batch size to analyze; in a set of n frames, the filter will pick one of them, and then handle the next batch of n
frames until the end. Default is 100.
Since the filter keeps track of the whole frames sequence, a bigger n
value will result in a higher memory usage, so a high value is not
recommended.
Examples
Extract one picture each 50 frames:
thumbnail=50
Complete example of a thumbnail creation with ffmpeg:
ffmpeg -i in.avi -vf thumbnail,scale=300:200 -frames:v 1 out.png

libavfilter thumbnail seems to only process first set of N frames

According to the docs (see below) the '-vf thumbnail' should handle batches of N frames and pick 1 frame from each batch but it doesn't. Am I doing something wrong? I also tried various options with "-vframes 5" and 'out%d.png" but I got the same same frame repeated many times but it did process multiple batches of N frames.
8.37 thumbnail
Select the most representative frame in a given sequence of consecutive frames.
It accepts as argument the frames batch size to analyze (default N=100); in a set of N frames, the filter will pick one of them, and then handle the next batch of N frames until the end.
Since the filter keeps track of the whole frames sequence, a bigger N value will result in a higher memory usage, so a high value is not recommended.
The following example extract one picture each 50 frames:
thumbnail=50
Complete example of a thumbnail creation with ffmpeg:
ffmpeg -i in.avi -vf thumbnail,scale=300:200 -frames:v 1 out.png
You need to set another one parameter -vsync (set it to 0 or 2), or muxer got wrong frames because by default -vsync=1
For example, correct command is
ffmpeg -i INPUT_FILE -vsync 0 -vf thumbnail,scale=300:200 -frames:v 20 -f image2 img-%04d.jpg
As for me, instead of thumbnail filter I use I-frame selector - its generate a little bit more files, but it more accurate for my purposes.
This is example with timestamp and firstly we are must find out correct fps from file (this is Mac OS X grep dialect) to set value of r=
ffmpeg -i INPUT_FILE 2>&1 | grep -Po "[^\s]+\sfps"
Also you are need select you own fontfile, I use Mac OS X files
Now all ready (f.e. save first 20 I-frames)
ffmpeg -i INPUT_FILE -someq -vsync 0 -vf \
drawtext="fontfile=/Library/Fonts/Courier\ New.ttf: \
timecode='00\:00\:00\:00':r=23.98: fontcolor=0xFFFFFFFF:fontsize=18:\
shadowcolor=0x000000EE:shadowx=1:shadowy=1",select='eq(pict_type\,I)'\
-vframes:v 20 -f image2 img-%04d.jpg
(strange, I get error on \-spitted line, but all works in one-line)

Resources