19

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.

6
  • I have read that page before I posted this question. That page didn't help me. If an input has variable fps can we simply calculate by using that equation? I dont think so. Also still I don't think '-ss' will give me accurate position. Frame by frame seeking would be better I guess.
    – destor
    Commented Jan 18, 2015 at 4:04
  • Note that -ss is frame-accurate (see here). Do you actually have variable-fps input? My answer links to the mailing list thread which mentions using select filters where you can specify the frame number. Have you tried that?
    – slhck
    Commented Jan 18, 2015 at 10:25
  • I have tried using select and aselect filters for video and audio streams. Select is frame-accurate for video, but aselect is not sample-accurate. Actually it is far from being accurate. It gives much more worse results than using the simple -ss -to paramaters. Because of that, for now, i use combination of select filter and -ss -to parameters to achive most accurate cutting. But it is a grungy way to do it. Please look at my first post i have added some commandlines and their results
    – destor
    Commented Jan 21, 2015 at 1:35
  • ffmpeg version?
    – fie
    Commented Mar 15, 2017 at 13:54
  • Why are you trying to cut by a frame number anyhow. If one needs that sort of accuracy then why not use avidemux? Also maybe your original problems are because it selects the closest key frame?
    – fie
    Commented Mar 15, 2017 at 14:08

2 Answers 2

2

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!

1
  • 2
    Actually audio comes from samples, not seconds...
    – Anubioz
    Commented Sep 7, 2019 at 15:26
-1

Seeking based on frame numbers is not possible. The only way to start at specific frames is to convert a number of frames to ss.ms syntax, or hh:mm:ss.ms. So, if your video is at 25 fps, and you want to start at 250 frames, and end at 750, you would need to first calculate the timestamp:

250/25 = 10

750/25 = 30

You can use the trim filter along with setpts,asetpts filter cut the video at the precise location, e.g.

ffmpeg -i movie.mp4 \
 -filter_complex '[0:v]setpts=(PTS-STARTPTS),trim=10:30 \
  [0:a]asetpts=(PTS-STARTPTS),atrim=10:30' \
 movie-between_10th_and 20th_seconds.webm

Please make sure to add setpts=(PTS-STARTPTS) and asetpts=(PTS-STARTPTS) before the trim filter to make sure the counting of pts starts from 0, in order to produce frame accurate output

1
  • So ffmpeg can't even cut a video properly using frames, great. Such a good software. Commented Aug 31, 2023 at 5:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .