FFMPEG Extract Desired Frames from video Quickly - ffmpeg

I am trying to extract desired frames from video when someone in video start to speak and extract 5 frames per second when speaking. I get the framelist I want like 0, 6,12,18 and 200,206, 212....
I try to create scripts to do it automatically using below command per frame,but it's pretty slow, is there quick to get the desired frames from list with frame num as image name?
ffmpeg -i 1.mp4 -vf select='eq(n,0)' -vsync 0 -an -y -q:v 16 0.png
ffmpeg -i 1.mp4 -vf select='eq(n,6)' -vsync 0 -an -y -q:v 16 6.png
....

Related

mp4 video written with ffmpeg has different first frame based on total number of frames

I'm trying to read and write videos using ffmpeg, and I got an interesting phenomenon where the first frame is not the same in videos I create that are made from the same frames, only with different lengths.
The commands I'm running to reproduce the problem:
ffmpeg -i <some_video>.mp4 -frames:v 20 -q:v 3 resource_images/00%04d.png
ffmpeg -hide_banner -loglevel error -framerate 30 -y -i resource_images/00%04d.png -c:v libx264 -pix_fmt yuv420p -frames:v 20 long_video.mp4 -y
ffmpeg -hide_banner -loglevel error -framerate 30 -y -i resource_images/00%04d.png -c:v libx264 -pix_fmt yuv420p -frames:v 10 short_video.mp4 -y
ffmpeg -i long_video.mp4 -vf "select=eq(n,0)" -q:v 3 long_frame0.png -y
ffmpeg -i short_video.mp4 -vf "select=eq(n,0)" -q:v 3 short_frame0.png -y
The images long_frame0.png and short_frame0.png are different (I loaded them using Python and compared them, there are many differences).
I find it very peculiar, since I create very short videos, it's those videos first frames, and they are keyframes of those videos (I checked it using ffprobe)
What is the cause of this issue and how do I overcome it to create a consistent first frame for a video, regardless of the video length?

Fastest way to output frames between 34885 and 34891 as images in ffmpeg?

I am trying to extract frames between a certain number as images
Currently I am doing it like this
ffmpeg
-i input.mp4
-vf select='eq(n\,34885)+eq(n\,34886)+eq(n\,34887)+eq(n\,34888)+eq(n\,34889)+eq(n\,34890)+eq(n\,34891)'
-vsync 0 output_frames_%d.png
Not only this the command above very cumbersome but also takes a lot of time to run, is there an easier and faster way to do this?
You may try this
ffmpeg -i input.mp4 -vf "select='between(n\,34885\,34891)'" -vsync 0 -start_number 34885 out-%02d.png
You could try this:
ffmpeg -i input.mp4 -vf select='between(n\,34885\,34891)' -vsync passthrough -frames 7 frame_%d.png
It's less cumbersome and stops once it has hit the target number of frames (7).

FFMPEG changing output framerate issues

I want to take the input, blend N frames, decimate the other frames and use those for the output with the fps of my choice.
I used this line:
ffmpeg -y -i input.mp4 -vf tmix=frames=15:weights="1",select='not(mod(n\,15))' -vsync vfr frames/output-%05d.tif
That generated images, which I combined into the video. So far, so good.
But I'd like to skip the image output and go straight to video, so I tried this:
ffmpeg -y -i input.mp4 -vf tmix=frames=15:weights="1",select='not(mod(n\,15))' -vsync vfr -r 30 -c:v prores_ks -profile:v 3 -vendor apl0 -bits_per_mb 8000 -pix_fmt yuv422p10le output.mov
That produces 1.62 fps video, instead of 30 fps.
I'm at a loss on how to get it to output 30fps without the intermediate step of outputting images.
Thanks
I think the simplest way to achieve this is to feed the input at the 15-times the desired rate and drop all intermediate frames with -r 30:
ffmpeg -y -r 450 -i input.mp4 \
-vf tmix=frames=15:weights="1" \
-r 30 sandbox/out.mp4
However, a tmix solution is somewhat inefficient for your use case because it's mixing for all frames, including those dropped. If you don't mind a longer expression, you can try:
ffmpeg -i in.mp4 \
-vf
setpts=\'floor(N/15)/(30*TB)\',select=\'mod(n,15)+1\':n=15[v0][v1][v2][v3][v4][v5][v6][v7][v8][v9][v10][v11][v12][v13][v14];\
[v0][v1][v2][v3][v4][v5][v6][v7][v8][v9][v10][v11][v12][v13][v14]mix=inputs=15:weights=1 \
-r 30 sandbox/out.mp4
[edit] setpts expression should be floor(N/15)/(30*TB) not mod(n,15)+1 for 15 successive frames to have the same pts.

FFMPEG cannot encode video with high speed change

Hi I am trying to speed up and trim clips with FFMPEG version 4.2.2. Is there a limit to how fast you can speed up a clip? If I try to speed up a clip over a certain then the output file cannot be opened.
I have tried two methods without any luck: 1. using the setPTS filter and 2. inputing the file at a faster frame rate.
1.
ffmpeg -i GH012088.MP4 -y -ss 18 -t 0.48 -an -filter:v "setpts=0.096*PTS" -r 25 output.MP4
2.
ffmpeg -r 312.1875 -i GH012088.MP4 -y -ss 18 -t 0.48 -r 25 -an output.MP4
I am trying to create a clip from the input that starts at 1 second in the original clip, plays at 10.4166 x speed and lasts for 0.48 seconds
What am I doing wrong?
Thanks
Use
ffmpeg -ss 1 -i GH012088.MP4 -y -t 0.48 -an -filter:v "setpts=0.096*PTS" -r 25 output.MP4
The seek has to be on the input side, before frames are retimed. The -t has to be on output side, after frames are retimed.
Does the movie have sound?
If yes, than we have to sync speed up audio and video by combine filter:
ffmpeg -i video.avi -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" -f avi video1.avi

Quicky output selection of video frames using ffmpeg

I would like to extract, say, 10 video frames from a given video file using ffmpeg, ideally uniformly distributed throughout the video. I know this can be done in a few ways, for example
ffmpeg -i input.mp4 -vf fps=1/10 out%03d.jpg
will output one image every 10 seconds. However, this is too slow for my liking and scales proportionally with the length of the video. I have read a bit about ffmpeg's seeking capability, for example
ffmpeg -ss 00:00:05 -i input.mp4 -frames:v 1 out001.jpg
will very quickly seek to the 5th second of the video and extract one frame. However I haven't come across a way to seek to multiple locations in the video without calling the above command repeatedly at various times.
Is there a quicker way of accomplishing this?
Using a long command, this can be done
e.g.
ffmpeg -ss 00:00:05 -i input.mp4
-ss 00:01:05 -i input.mp4
-ss 00:03:05 -i input.mp4
-ss 00:40:05 -i input.mp4
-map 0:v -frames:v 1 out001.jpg
-map 1:v -frames:v 1 out002.jpg
-map 2:v -frames:v 1 out003.jpg
-map 3:v -frames:v 1 out004.jpg

Resources