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://video.stackexchange.com/questions/8106/how-to-trim-a-video-with-frame-precision-using-ffmpeg
https://ottverse.com/trim-cut-video-using-start-endtime-reencoding-ffmpeg/
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. 😀