Cutting videos at exact frames with ffmpeg select filter

Instead of using -ss and -to seeking parameters, which seem not very accurate, can I cut videos for given frame numbers? For example;

ffmpeg -i video.webm -startingframe 80 -endingframe 560 output.webm

[80th frame and 560th frame included. So, as total it makes (560 - 80 +1) frames]

After the answers and a bit search, I have tried some commands. But so far I couldn't find an acceptable way.

If someone wants to cut video stream between 250th and 750th frames, this is the way to go. It will give 501 frames as output:

Note: movie.mp4 has 25 fps, and its audio sample rate 48k

ffmpeg -i movie.mp4 -an -vf "select=between(n\,250\,750),setpts=PTS-STARTPTS" v_stream.webm

As expected, the output is 20 seconds long, exactly.

Using the same method for audio:

ffmpeg -i movie.mp4 -vn -af "aselect=between(n\,480\,1440),setpts=PTS-STARTPTS" a_stream.webm

Unexpectedly, this one has very poor accuracy. It should have given me 960001 (960k+1) samples which equal 20 seconds audio. But instead, the output was 20.505 seconds long and has 984240 samples. Also, if I increase the duration, error increases as well.

Then I tried to use -ss -to parameters for cutting audio stream:

ffmpeg -i movie.mp4 -vn -ss 10.000 -to 30.000 a_stream.webm

The old classic way works much better. Output was 20.003 seconds long and has 960144 samples. Plus, increasing duration does not increase the error, the error is constant, there is always 144 samples surplus with that input file.

Summing up: select filter works well most of the time but aselect is not. The classic -ss parameters work better for audio but not sample-accurate. Also, it is not possible to use -vf select and -ss parameters together, because -ss will affect both audio and video streams while we want it only affect audio.

So, to precisely cut a media file I have to do these 3 steps:

ffmpeg -i movie.mp4 -an -vf "select=between(n\,250\,750),setpts=PTS-STARTPTS" v_stream.webm 
ffmpeg -i movie.mp4 -vn -ss 10.000 -to 30.000 a_stream.webm 
ffmpeg -i v_stream.webm -i a_stream.webm -c:v copy -c:a copy  movie-between_10th_and 20th_seconds.webm

This gives the most accurate results. Video is 20.000 seconds long and frame-acurate Audio is 20.003 seconds long and has 960144 sample. Not exactly matches with the video stream, but it is OK. There is only 144 samples surplus. The biggest downside is, whenever I want to cut a file, I have to send 3 commands for a simple job and it creates two unnecessary files: a_stream.webm and v_stream.webm. And the select filter is not working on some input files I have tried. It does the job successfully (?) but never stops the encoding process, so I have to close command prompt every time.


Audio comes from seconds, not frames, so if you want to cut a video you have to calculate video fps × 20 second like this: 20 second of 23.97 fps = 479.4

Frame cutting is not accurate because you can't get full fps for the last second, so the audio will get more seconds or only a half second or a bit more or less!  Maybe you should use seconds instead of frames to get exact cut you tell the ffmpeg to do it for you.  And if you get 1 extra frame, what about to change 250th and 750th frames to 250th and 749th frames?!  Use minus 1 there to always get how many frames you ask for!