Skip to content

Instantly share code, notes, and snippets.

@mechalynx
Last active July 3, 2018 00:07
Show Gist options
  • Save mechalynx/85ce55375c61d290da6cd6d3b3520790 to your computer and use it in GitHub Desktop.
Save mechalynx/85ce55375c61d290da6cd6d3b3520790 to your computer and use it in GitHub Desktop.
Handy ffmpeg stuff

None of these operations are destructive. That means they give you a new file, they don't write over the old one, so they're safe to try as long as you're not low on HDD space. If something goes wrong and it seems to be taking too long, just Ctrl+C and it'll stop.

Convert to mp4 and keep only one audio stream:

ffmpeg -i #VIDEOFILE -codec copy -map 0:v:0 -map 0:a:#N output.mp4

Where #VIDEOFILE is your video's filename (quote it if it has spaces in it) and #N is the index of the audio track you want to keep, starting with 0 for the first audio track (so if you have 3 tracks, they're 0, 1 and 2).

Name the output file anything out want (it's just output in this case) but make sure it ends in .mp4 so ffmpeg knows to use that container automatically.

Doing it this way avoids transcoding the entire thing, it'll just copy the streams from one file to another. Quick and clean.

Split files:

This is useful only if you just want to do a hard cut and remove parts of the video entirely and then optionally put them together (if you just want to cut out a middle section or something). If you want to do transitions, add overlays etc. this is useless, you might as well just open the video in an editor and do it that way.

Keep in mind, this can only cut at keyframes because we're not transcoding. This means that you may not get exactly the times you want because the nearest keyframe is a bit further ahead. Ffmpeg will cut to the nearest keyframe before the time you specify though. Usually keyframing happens every few frames by default so it shouldn't deviate much. More keyframes means a bigger file though.

If you really want super-precise cuts just remove the -codec copy part and it'll transcode.

There's several ways to do it:

  • If you know start and end times:
ffmpeg -i #VIDEOFILE -codec copy -ss 00:12:54.000 -to 00:15:33.434 output.mp4

This will take #VIDEOFILE and give you a output.mp4 starting with 12 minutes and 54 seconds in and ending at 15 minutes 33 seconds and 434 milliseconds.

  • If you know the start time and want a duration, you can need to do the calculation yourself or ask ffmpeg to cut after a duration. There's some handy tools for this like this but usually it's an easy calculation anyway.

To specify a duration you can replace -to with -t. Instead of stopping the processing at a specific time, it will seek to the start time and stop after the duration specified by -t:

ffmpeg -i #VIDEOFILE -codec copy -ss 00:15:00 -t 00:08:00 output.mp4

This will give you an output from 15 minutes in and 8 minutes after that, so 00:15:00-00:23:00.

You can also specify durations and seek points in seconds, including fractional seconds. Here is the exact syntax specification.

  • If you want to split a file into equal segments for whatever reason:
ffmpeg -i #VIDEOFILE -codec copy -map 0 -reset_timestamps 1 -segment_time #N -f segment output%03d.mp4

Keep in mind that on Windows you'll have to use %% instead of % because Windows sucks shit from a straw (yes that is the technical term for it).

This will give you segmented output of the video file, where #N is in seconds. The output file format just specifies that it should add a number in the file name as an index, in this case 3 digits long.

Splicing files together:

Without transcoding:

This only works if the video files are exactly the same codec on both audio and video. That generally means either encoded exactly the same or that they used to be part of the same video originally.

Make a file with the filenames of all the video files. You can have relative path names but that is a bit finicky and I don't know exactly how to resolve issues with it. This is how to do it if all the files are all in the same directory you're going to run the command from.

The file format is like this:

file 'video1.mp4'
file 'video2.mp4'
file 'video3.mp4'

Note that each line starts with file and the file names are single-quoted. Just save that as files.txt or something like that.

Then:

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

If all of them are encoded exactly the same, this should work.

If they're not all encoded exactly the same:

You'll have to transcode, which means you might as well do it in a video editor but if you want a command-line solution here it is:

ffmpeg -i video1.mkv -i video2.mkv -i video3.mkv -filter_complex "[0:v] [0:a] [1:v] [1:a] [2:v] [2:a] concat=n=3:v=1:a=1 [v] [a]" -map "[v]" -map "[a]" output.mkv

This will take the three input videos, use the video and audio streams from each one (that's what first part of the filter_complex thing is) and concatenate them together. The n=3 number is the same as the number of input files. The rest just ensures you get one video and audio output stream. You can do lots with this filter so I'm not going to go into more detail as I don't understand it well enough myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment