55

I'm trying to use ffmpeg to cut video files at precise times. The ffmpeg help shows an option -timecode_frame_start to specify the starting frame but I am unable to get this command to work. The resulting video always starts at the beginning of the original video. Here's an example of the command I'm running:

ffmpeg -i input.mpg -acodec copy -vcodec copy -timecode_frame_start 200 -vframes 210 -n ouput.mpg

I've moved the timecode_frame_start option before and after the other options with no change in results. Is there an additional option I need to specify? I've tried various file formats, mkv, avi, mp4, and it doesn't appear the problem is codec related. Here is one file I've tried:

http://www.seaotter.com/marine/movies/hermit-long-01.mpg

Am I missing something?

pseyfert
  • 103
  • 2
curmil
  • 1,025
  • 2
  • 9
  • 8
  • appears this was answered on the mailing list (and NB that with -vcodec copy you can't "really" get frame specific cutting, since it can only resynchronize on i-frames – rogerdpack Aug 09 '12 at 11:46
  • @user39364 I asked on the mailing list and it turns out that this option doesn't do what the OP wants. I also learned something new :) – slhck Aug 09 '12 at 11:46
  • Just wanted to note that I found a method for cutting at exact frames using `melt`, see [Accurately cut video files from command line - Super User](https://superuser.com/questions/458761/accurately-cut-video-files-from-command-line/1289110#1289110) – sdaau Jan 26 '18 at 02:26

4 Answers4

74

timecode_frame_start does not work like this.

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 133 frames, you would need to first calculate the timestamp:

133 / 25 = 5.32

Then run:

ffmpeg -ss 5.32 -i input.mp4 -c:v libx264 -c:a aac out.mp4

Note that cutting on exact frames with bitstream copy (-c:v copy) is not possible, since not all frames are intra-coded ("keyframes"). A video must begin with a keyframe to be decoded properly. You will therefore have to re-encode the video, e.g. to H.264 using -c:v libx264 as shown above. You can also choose a lossless codec like -c:v ffv1 which preserves the quality of the input video.

To summarize, -ss will always be frame-accurate when performing re-encoding.

If you further want to encode a specific number of frames, use -frames:v, for example:

ffmpeg -ss 5.32 -i input.mp4 -c:v libx264 -c:a aac -frames:v 60 out.mp4

Note that you you also have the choice to use the select/aselect filters to select frames/audio samples.

ffmpeg -i input.mp4 -vf 'select=gte(n\,100)' -c:v libx264 -c:a aac out.mp4

This, however, is slower than the -ss option shown above, since the entire video will be decoded.

slhck
  • 223,558
  • 70
  • 607
  • 592
  • 7
    for videos with drop frames (e.g. 29.97fps) that are over 10 minutes; how would you go about accurately calculating the time for a particular frame? – GFoley83 Sep 05 '16 at 20:53
  • 2
    the `select=gte(n\,100)` method works but the seeking is eating up performance. If you test by encoding just 30 frames at a time, The further into the video I start, the longer ffmpeg takes to complete because of the seeking. – Adam Grant Jan 29 '17 at 09:32
  • 1
    After applying this method to a video file, in my player (VLC), there's some lingering audio that plays after the video frames have stopped playing. I'm thinking I need to somehow apply this same method to "audio frames". Or simply tell ffmpeg to halt adding more audio once the video has stopped. How do I do that? – t-mart Feb 14 '20 at 23:11
  • 2
    @t-mart Add `-shortest` to make it stop encoding when the shortest stream is finished (i.e. the video stream in your case). – slhck Feb 16 '20 at 15:52
  • how can i trim at an exact frame but only re-encode from the starting frame until the first keyframe after that, then copy? – Michael Oct 07 '20 at 01:47
  • @Michael You can't. If you use the `select` or `trim` filters, everything is re-encoded. If you do a bitstream copy via `-c copy` then you can't selectively re-encode. You could try to splice the videos into pieces and merge them with the concat demuxer: https://trac.ffmpeg.org/wiki/Concatenate#demuxer — this *may* work if you have the exact same codec and codec settings. – slhck Oct 07 '20 at 20:03
  • Why is it not possible for ffmpeg to reencode just the portion of the video up to the first keyframe, so that the video itself starts with a keyframe, and then just `-vcodec copy` everything after the first keyframe? Why does it have to reencode the entire video? – BallpointBen Jun 29 '23 at 20:22
  • @BallpointBen Because codec settings are hard to replicate from just reading an input stream. To ensure smooth playback you have to encode a whole stream in one go with the same settings. It's not always guaranteed to be possible to encode a stream the same way as an existing one so they can just be "glued" together on a bitstream level, without potentially causing glitches in the decoder. – slhck Jun 30 '23 at 11:25
16

The option

-vf select="between(n\,start_frame_num\,end_frame_num),setpts=PTS-STARTPTS"

e.g.,

-vf select="between(n\,200\,300),setpts=PTS-STARTPTS"

cuts video from(includes) 200th to(includes) 300th frame, the sequence counting starts from 0.

Tim Krief
  • 103
  • 3
Nuo Chen
  • 169
  • 1
  • 2
  • 1
    bash: syntax error near unexpected token `(' – mLstudent33 Mar 05 '20 at 17:47
  • 2
    What does `setpts=PTS-STARTPTS` do? – Kingsley Jul 17 '20 at 00:23
  • For reference, here's the documentation on ffmpeg filters: https://ffmpeg.org/ffmpeg-filters.html. In particular, see the section on Multimedia Filters for descriptions of the select and setpts filters (as at 15 Jan 2021 sections 16.14 and 16.16, respectively). – Simon Elms Jan 14 '21 at 20:57
4

LosslessCut is a cross-platform GUI tool that uses FFmpeg as a backend and losslessly cuts your video. You can choose to cut at a keyframe or any frame.

mwfearnley
  • 7,172
  • 5
  • 26
  • 38
Expectator
  • 141
  • 2
  • 2
    I don't think this is the case. [LosslessCut's README](https://github.com/mifi/lossless-cut#known-issues--limitations) states that it rounds to nearest keyframe. – matthew-e-brown Feb 21 '22 at 04:36
  • @matthew-e-brown Using their experimental [smart cut](https://github.com/mifi/lossless-cut/issues/126) feature, any frame can be chosen, and only the frames up to the next keyframe will be re-encoded. It worked great for the one video I tested. – Nicolai Weitkemper Aug 15 '23 at 21:35
0

I have a solution, but I don't know how to do it using current ffmpeg commands (my trials to copy at keyframes didn't come accurate too. I want to know how ffmpeg decides the cutpoints).

I suggested suggest this algorithm, to divide the segment (t1, t2) that we want to copy to 3 parts:

  1. a part (t1-x, t1+y), which is a complete encoded block that should be re-encoded to be able to copy the part (t1, y) precisely.
  2. a part (t2-z, t3+w), which is a complete encoded block that should be re-encoded to be able to copy the part (z, t2) precisely.
  3. a middle part (y, z) which contains complete encoded blocks, where it can be copied as is.
  4. Join the 3 parts resulted from the above steps.

Note that the first two parts are expected to be small (and one of them or both can be zero length), so, the re-encoding process will be fast. This will make us able to have exact cuts with slightly slower operation but still super faster than re-encoding the full video. It can be even faster if we can do multiple cuts with one command, so we traverse the frames once. I hope if someone can apply this, and tell us how, or mention some of the ffmpeg team, or deliver it to them anyhow.

  • I agree with your suggestion (and i virtually had such an idea years ago). Such a feature should be provided with options. Before such a feature exists we might manage to do it with shell scripts but I'd rather avoid the troubles such as shell compatibility. I am concerned that codecs or muxers might not support well a variability in the rate (conversely delay) of key frames near the extremities. I learnt recently about Instantaneous Decode Refresh frames and their opposite whatsoever which may cause troubles like interrupted buffered video streams on internet. – Link-akro Aug 30 '20 at 15:32