ffmpeg output images filename with time position - ffmpeg

I am using ffmpeg to get some jpg from my video at a specific rate (one screenshot every 5 seconds) with this command :
ffmpeg -i source -f image2 -r 1/5 %d.jpg
This works and give me sequential filenames :
1.jpg
2.jpg
3.jpg
4.jpg
What if I need to know at which time those screenshots have been taken ? Something like a timestamp :
00:00:00.0000.jpg
00:00:05.0000.jpg
00:00:10.0000.jpg
00:00:15.0000.jpg
or the number of seconds :
0.jpg
5.jpg
10.jpg
15.jpg
I tried again with the new -frame_pts option :
ffmpeg -i source -f image2 -r 1/5 -frame_pts 1 %d.jpg
I got similar sequential filenames, but now they are starting from zero :
0.jpg
1.jpg
2.jpg
3.jpg

Use
ffmpeg -i source -vf fps=1,select='not(mod(t,5))' -vsync 0 -frame_pts 1 z%d.jpg
frame_pts will assign a serial number to the image name, where the number represents the frame position as per the output timebase. So the calculated time position is frame # x timebase. The timebase is the reciprocal of the output framerate e.g. for a 12 fps stream, timebase is 1/12. So output file image212 represents a time of 212 x 1/12 = 17.67s
To represent seconds, you need to generate a 1 fps stream and then pick every 5th frame, to get a frame from every 5th second. The vsync 0 is added to prevent ffmpeg from duplicating frames to generate a constant frame rate stream.

This may not be the best solution but it does the job
for (i = 0; i < $duration; $i += 0.5) { //where $duration is video duration
`ffmpeg -y -i video.mp4 -ss $i -vframes 1 $i.jpg`
}
Of course this would be very slow since it spawns ffmpeg for every frame but as I said may help you to get the job done.

Related

FFMPEG: extract 1 frame from an array of times

I'm trying to create a timeline of images for a video using FFMPEG.wasm. The times I want to pass in is 1/10 its total duration.
I tried:
const duration = video.current.duration;
const fps = duration / 10;
//this is the command I used on the CLI for a 1 hour video.
ffmpeg -skip_frame nokey -i temp.mp4 -vf "scale=180:-1,fps=1/600" out%d.png
but the output is really slow when it comes to long videos due to FFMPEG having to go through the entire video.
Is there a command that's like:
ffmpeg -ss "600, 1200, 1800 ... 6000" -i temp.mp4 -vf scale=180:-1 -frames:v 1 out%d.png
where it only outputs an image only at those specific times without having to loop the FFMPEG command 10 times?

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

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.

How to make ffmpeg automatically fill frames?

I want to use ffmpeg to convert a sequence of images to a video, the images are got in realtime, the interval of getting image is changeable, maybe i get next image in 1 second or even 1 millisecond.
I want the target video in a special fps(like 100), now my implement is creating a loop, which fade ffmpeg last image then sleep(like 10ms).
Do you guys know some options could let ffmpeg fill frames automatically?
If that option do exist, i wonder is that possible to make video real fps is half of it is claimed.
My ffmpeg command likes follow:
ffmpeg -f image2pipe -r 100 -i pipe:0 -f flv -r 100 pipe:1
You can use
ffmpeg -f image2pipe -use_wallclock_as_timestamps 1 -i pipe:0 -f flv -vsync cfr -r 100 pipe:1
FFmpeg will set each incoming frame's timestamp to the time it is received. SInce the output rate is set and mode is constant frame rate, ffmpeg will duplicate the last frame till next input frame is received, or drop if two frames are less than 10ms apart. Change -r to 1000 to keep frames only a millisecond apart.

Sync files timestamp with ffmpeg

I'm capturing video from 4 cameras connected with HDMI through a capture card. I'm using ffmpeg to save the video feed from the cameras to multiples jpeg files (30 jpeg per second per camera).
I want to be able to save the images with the capture time. Currently I'm using this command for one camera:
ffmpeg -f video4linux2 -pixel_format yuv420p -timestamps abs -I /dev/video0 -c:a jpeg -t 60 -ts_from_file 2 camera0-%5d.jpeg
It saves my file with the names camera0-00001.jpg, camera0-00002.jpg, etc.
Then I rename my file with camera0-HH-mm-ss-(1-30).jpeg based on the modified time of the file.
So in the end I have 4 files with the same time and same frame like this:
camera0-12-00-00-1.jpeg
camera1-12-00-00-1.jpeg
camera2-12-00-00-1.jpeg
camera3-12-00-00-1.jpeg
My issue is that the file may be offset from one to two frame. They may have the same name but sometime one or two camera may show different frame.
Is there a way to be sure that the capture frames has the actual time of the capture and not the time of the creation of the file?
You can use the mkvtimestamp_v2 muxer
ffmpeg -f video4linux2 -pixel_format yuv420p -timestamps abs -copyts -i /dev/video0 \
-vf setpts=PTS-STARTPTS -vsync 0 -vframes 1800 camera0-%5d.jpeg \
-c copy -vsync 0 -vframes 1800 -f mkvtimestamp_v2 timings.txt
timings.txt will have output like this
# timecode format v2
1521177189530
1521177189630
1521177189700
1521177189770
1521177189820
1521177189870
1521177189920
1521177189970
...
where each reading is the Unix epoch time in milliseconds.
I've switched to output frame count limit to stop the process instead of -t 60. You can use -t 60 for the first output since we are resetting timestamps there, but not for the second. If you do that, remember to only use the first N entries from the text file, where N is the number of images produced.

the output movie is too fast how to control it

i have 60 images 000001.jpeg to 000060.jpeg now this is my command:
"-f image2 -i E:\\REC\\Temp\\%06d.jpeg -r 12 E:\\REC\\Video\\" + label1.Text + ".wmv"
The output is about 3 second but i expect to get only one minute, so how to set duration for each frame to be one image = one second so 60 image = one minute?
Default frame rate for inputs is 25, so in your example ffmpeg is dropping frames to go from 25 to 12 fps (the console output will confirm this).
You can declare just an input frame rate and the output will inherit this same frame rate:
ffmpeg -framerate 1 -i %06d.jpeg output.wmv
Or both an input and an output frame rate:
ffmpeg -framerate 1 -i %06d.jpeg -r 25 output.wmv
This second example is recommended if Windows Media Player has issues with 1 fps content. You will have to experiment to see which example works best for you.
See the image2 demuxer documentation for more information.

Resources