Cutting video with FFmpeg – The good, the bad, and the ugly

FFmpeg is able to cut, trim and extract videos without transcoding the media. This is a great way to maintain the original quality, thus avoiding generation loss.

However, FFmpeg cannot cut at exact points in time unless it re-encodes the video. Instead, FFmpeg tries to find the closest keyframe and cut it there. To understand why this happens you can read more about keyframes.

Cutting video (exactly) with transcoding

By re-encoding the video, FFmpeg is able to cut the video at exact points in time. Unfortunately this will introduce generation loss, depending on the settings.

There are a million ways to transcode video, so in this example, we will use the most common video encoder H.264/AVC.

This example will cut the video at the start and end point, and convert the result to an MP4 file.

ffmpeg -i input.mp4 -ss 01:50:00 -to 01:55:00 -c:a copy -c:v libx264 -preset slow -crf 18 output.mp4

You can read more on how to encode video to H.264 with FFmpeg if you want. These are the values explained:

  • -i input.mp4 is the input file.
  • -ss 01:50:00 is the start position.
  • -to 01:55:00 is the end position.
  • -c:a copy means we will not be transcoding the audio.
  • -c:v libx264 means we want to transcode the video to H.264/AVC format.
  • -preset slow means we will use more time to encode the video, thus better quality.
  • -crf 18 sets the video CRF to quality preset 18. This will give a pretty decent video quality, close to lossless.

Cutting video (roughly) without transcoding

As explained above, without transcoding the video, it is impossible to cut at an exact point in time, because of how keyframes work. You can only cut at the closest keyframe. This is known as stream copying.

We set the start time and end time for the clip, but note that the cut will jump to the nearest keyframe.

ffmpeg -i input.mp4 -ss 01:50:00 -to 01:55:00 -c copy output.mp4

In this case, we use -ss for the start time and -to for the end time.

We could also set the start time and the duration of the clip (instead of the end time), like this:

ffmpeg -i input.mp4 -ss 01:50:00 -t 10 -c copy output.mp4

-ss is the start point. -t is the duration of the clip in seconds, if you prefer using that. You can also specify the duration with HH:MM:SS (hours, minutes, seconds).

You can also add milliseconds, but then you have to use a dot (punctuation) to separate instead of a comma. For example 01:44:53.434. That is 1 hour, 44 minutes, 53 seconds, and 434 milliseconds.

Make sure the -ss comes after -i input.mp4!

Alternatives

If you want to cut a video file exactly and do not want to transcode it, you are fighting the laws of video compression, but there may be some software alternatives.

Usually, I don’t like to recommend software alternatives, but since it took me literally hours of research and testing I would recommend TMPGEnc MPEG Smart Renderer.

It can cut video regardless of keyframes, and without transcoding. It uses what is called smart encoding to avoid re-encoding the whole file. Instead, it will only convert the one missing keyframe (as far as I understand). It also supports HDR up to 8K resolution. This was the only software I could find that didn’t have severe performance issues with 4K HDR video files.

The disadvantage is that it is not free. 👎 But you wanted the real deal, right? 😂

Bonus tip: Cut video at every keyframe

A lot of times a keyframe is placed at places in the video where there is a change in the scene. Instead of manually trying to find these keyframes you can have FFmpeg extract video portions at each keyframe:

If you are using Windows, make a folder in the same directory as your video file called “segments”. Use this command in the command prompt to cut the video:

ffmpeg -i input.mp4 -c copy -f segment -reset_timestamps 1 -map 0 segments/segment%d.mp4

This will extract parts of the video at each keyframe and put them in the folder called segments. This will obviously leave you with a lot of video files.


Sources

https://stackoverflow.com/questions/14005110/how-to-split-a-video-using-ffmpeg-so-that-each-chunk-starts-with-a-key-frame

https://video.stackexchange.com/questions/8106/how-to-trim-a-video-with-frame-precision-using-ffmpeg

https://stackoverflow.com/questions/14005110/how-to-split-a-video-using-ffmpeg-so-that-each-chunk-starts-with-a-key-frame

https://ottverse.com/trim-cut-video-using-start-endtime-reencoding-ffmpeg/

https://stackoverflow.com/questions/59460175/how-to-trim-a-video-file-at-a-precise-position-without-re-encoding-using-ffmpeg

https://stackoverflow.com/questions/44447775/cutting-a-video-accurately-at-a-specific-time-without-losing-quality

https://video.stackexchange.com/questions/16750/using-ffmpeg-to-cut-videos-with-more-precision-than-key-frames-allow

2 Comments

  1. Thank you for explaining how ffmpeg handles video trimming. If I understand correctly, only the video component of a video file has keyframes and the audio component does not? Therefore ffmpeg can extract a subset (any random subset) of the audio component without audio transcoding, as long as you keep the audio format the same?

    • Hi there,
      If you cut a video at a keyframe, no re-encoding is required and you can just use -c:v copy to copy the video as-is. However, if you want to cut outside a keyframe you can’t use -c:v copy because re-encoding will be required. So to answer your question yes… Regardless of these two methods, you should be able to keep the audio format untouched by using -c:a copy (note the letter “a”, indicating audio). Hope that helps. 😀

Leave a Reply

Your email address will not be published. Required fields are marked *