Posted in:

FFmpeg is a remarkably versatile tool. You can use it to perform all kinds of amazing manipulations on video (and audio) files, if only you can work out the correct command line arguments. Unfortunately that’s the tricky part.

I recently needed to cut a few sections out of a pre-existing MP4 file to make it a bit shorter. It took me a few goes to find out how this can be done, but eventually I got something working.

First of all, make sure you have downloaded a build of FFmpeg. I used the static 32 bit Windows version from here. For convenience you’ll probably want to make sure ffmpeg.exe is on your PATH.

In this example, the file we want to edit is called input.mp4. And we want to keep three sections of the file: 2:00-9:28, 10:50-1:02:20 and 1:19:00-1:27:05.

We perform the operation in two stages. First we create three shorter mp4 files containing just the portions we want to keep. And then we stitch them all back together again.

Here’s the first part:

ffmpeg -i input.mp4 -ss 00:02:00 -t 00:07:28 part1.mp4
ffmpeg -i input.mp4 -ss 00:10:50 -t 00:51:30 part2.mp4
ffmpeg -i input.mp4 -ss 01:19:00 -t 00:08:05 part3.mp4

Now most of that is probably self-explanatory. The -i switch introduces the input file name, the -ss switch indicates the start time of the section we want to cut. The slightly tricky one is the -t parameter, which is not the end time of the section you want to cut, but the duration. If you’re a C# programmer like me, you’ll just fire up LINQPad and enter a quick expression to calculate the difference between the start and end times:

TimeSpan.Parse("1:02:20") - TimeSpan.Parse("0:10:50")

And of course the final parameter is the output file.

So now we have our three parts, we need to join them together. There are a few different concatenation options in FFmpeg, and in our case it is the “concat demuxer” we need, as the “concat protocol” won’t work with mp4 files.

To use the concat demuxer we first need to create a simple text file containing the details of each file we want to concatenate. Let’s create inputs.txt with the following content:

file 'part1.mp4'
file 'part2.mp4'
file 'part3.mp4'

Now we are finally ready to concatenate our files, and we can do that with the following syntax:

ffmpeg -f concat -i inputs.txt -c copy output.mp4

And that’s all there is to it. Hope someone finds this helpful, and if there is an even better way to achieve the same results (which I’m sure there is), do let me know in the comments.

Comments

Comment by Richard Evans

You should also be able to achieve the same in a single command with the -filter_complex parameter which allows you to build arbitrarily complex processing pipelines:
ffmpeg -i OverheadCam.mp4 -filter_complex "
[0:v]split=3[copy1][copy2][copy3],
[copy1]trim=10:20,setpts=PTS-STARTPTS[part1],
[copy2]trim=30:40,setpts=PTS-STARTPTS[part2],
[copy3]trim=60:80,setpts=PTS-STARTPTS[part3],
[part1][part2][part3]concat=n=3[out]" -map "[out]" out.mp4
split makes copies of the original file
trim cuts them between the second boundaries (supports partial seconds)
setpts resets the timestamps on the frames (important to stop if from having large pauses in the output)
concat stitches them back together.
https://ffmpeg.org/ffmpeg-f... are actually quite useful once you get your head around some of the syntax.

Richard Evans
Comment by ThBob

Thank you Richard for your code! I realized that it doesn't extract the sound of the parts though so I did a little research of my own and ended up with this:
ffmpeg -i "c:\Video_source.mp4" -filter_complex"
[0:v]split = 3[vcopy1][vcopy2][vcopy3],
[vcopy1] trim=10:20,setpts=PTS-STARTPTS[v1],
[vcopy2] trim=30:40,setpts=PTS-STARTPTS[v2],
[vcopy3] trim=60:80,setpts=PTS-STARTPTS[v3],
[0:a]asplit = 3[acopy1][acopy2][acopy3],
[acopy1] atrim=10:20,asetpts=PTS-STARTPTS[a1],
[acopy2] atrim=30:40,asetpts=PTS-STARTPTS[a2],
[acopy3] atrim=60:80,asetpts=PTS-STARTPTS[a3],
[v1] [a1] [v2] [a2] [v3] [a3] concat=n=3:v=1:a=1[v][a]" -map "[v]" -map "[a]" result.mp4
My only question is, is there a way to avoid re-encoding the video and just copy the video and audio streams using this way? If I understand correctly, it can be done using the concat demuxer but that requires the creation of the individual file parts that we need to join and save their addresses in a .txt file for the demuxer to work with, correct?
Thank you in advance!

ThBob
Comment by ThBob

Hello and thank you for your code!
I am having sync problems between the video and audio on the individual parts that are being generated as well as the joined result.
Do you have any idea as to why this could be happening?
Thank you!

ThBob
Comment by billposer

When I do this, the quality of the result is not as good as that of the input. This is evidently due to the quality of the parts that cut out of the original not being the same as that of the original. Any idea why this happens? Using the -crf option in an attempt to force high quality output in the initial cuts does not help.

billposer
Comment by neoe

Thank you for your hint. I improved it into more simple form: ffmpeg -i a.mkv -filter_complex "[0:v]trim=10:20,setpts=PTS-STARTPTS[p1],[0:v]trim=30:40,setpts=PTS-STARTPTS[p2],[0:v]trim=50:60,setpts=PTS-STARTPTS[p3],[p1][p2][p3]concat=n=3[out]" -map[out] b.mkv "split" is not needed so maybe more performance.

neoe
Comment by Bk Engineer

Thanos, did you find a way to avoid re-encoding the video?

Bk Engineer
Comment by ThBob

No unfortunately this was a secondary feature for me and I didn't look more into this. I am sorry and good luck!

ThBob
Comment by S Lee

If my file is mp3, not mp4 and want to achieve the same in a single command.
What should I do?
Thanks in advance.

S Lee
Comment by John Mclaren

2020 update:
Having gone through this using ffmpeg which does a good, if complicated, job I realised ffmpeg seems to be set up well to deal with .mp4 and .ts (transport stream format) files to work losslessly and avoid reencoding.
Looking at dealing with mkv/webm format files which I prefer, I realized there is a great open source package called MKVtoolNix which includes mkvmerge, and as long as you are using a single video file or multiple files with similar formats, it simply defaults to doing the piping and mapping properly, and it accepts *very simple* syntax to take multiple segments of video and concatenate them perfectly, even supporting chapter information quite easily.
And MKVtoolNix apparently does no transcoding or reencoding so it's inherently very fast and lossless. Output files seem small and optimized. Subtitles and many intricacies of this process are handled by default or with ease. I would keep around ffmpeg for doing a quick cleanup of seek indexing via a "-c copy" command option though.
MKVtoolNix may have some ability to deal with other formats as well, and a GUI version of mkvmerge which looks very impressive.

John Mclaren