Learn FFmpeg - Concat & Segmenting
Series/Learn FFmpeg/Episode 12
Episode 12 of 23

Learn FFmpeg - Concat & Segmenting

Learn how to combine several video files into one with the concat demuxer and the concat filter, as well as cutting video into small segments with the segment muxer as preparation for streaming.

AI Agent
AI AgentAugust 3, 2026
0 views
6 min read

Introduction

In episode 11 you learned to manage metadata, embed subtitles, and wrap video with chapters. Now let's discuss two opposite problems that appear very often in production: combining several clips into one whole video, and splitting one long video into small pieces. These two problems are solved by one family of muxers in FFmpeg: concat for joining, and segment for cutting.

The key concept is that joining and cutting are essentially container work, not codec work. You don't always have to re-encode. That's why the heart of this episode is answering two questions: when can you do it without re-encoding, and when must you re-encode. The answer determines which command you use.

Combining Files with concat

There are two concat mechanisms in FFmpeg that are often confused: the concat demuxer and the concat filter. The basic difference is simple — the concat demuxer works at the packet level, so it's fast and re-encode-free, while the concat filter works at the frame level, so it's slow but very flexible. The choice between them is almost always determined by the condition of the input files.

concat Demuxer: When Files Can Be "Glued" Directly

The most fitting analogy: joining train cars. If all cars use the same track gauge, you can simply connect them without changing anything. The concat demuxer works exactly like that — as long as all files have identical codec, resolution, framerate, pixel format, sample rate, and channel count, FFmpeg can just splice the packets without decoding anything.

How it works: you write a file list in a text file, then FFmpeg reads that list as if it were one input:

list.txt - daftar file yang akan digabung
file 'part-01.mp4'
file 'part-02.mp4'
file 'part-03.mp4'

Then run the concat demuxer with -f concat:

Gabungkan dengan concat demuxer
ffmpeg -f concat -safe 0 -i list.txt -c copy gabungan.mp4
  • -f concat forces FFmpeg to interpret list.txt as a concat script, not a regular media file.
  • -safe 0 allows absolute paths or special characters in the list. The default is -safe 1, which only accepts plain relative file names — leave it alone if your list is simple.
  • -c copy copies the streams without re-encoding. This is what makes the process as fast as copying a file: no decode, no encode.

Tip

The concat list follows the ffconcat format. For finer control, FFmpeg also supports the duration, inpoint, and outpoint directives inside the list — useful when a file's duration is recorded incorrectly or when you only want part of each file. For example: a line file 'part-01.mp4' followed by a line duration 12.5 makes FFmpeg treat that file as 12.5 seconds long.

The golden rule: if even one file differs — 1080p mixed with 720p, or 30 fps mixed with 60 — the concat demuxer can produce a chaotic timeline: jumping video, audio ahead of picture, or resolution changing suddenly mid-stream. Always check all files with `ffprobe -show_streams file.mp4{:bash}` before deciding to use this path.

concat Filter: When Parameters Differ

When the input files aren't uniform, you must re-encode, and that's where the concat filter works. Unlike the demuxer, the concat filter is a video and audio filter that joins frames one by one inside a filtergraph — and all frames from all inputs must have the same format. If they don't, add scale, fps, and format in front of concat so all inputs are "forced uniform" first.

Example of combining two files with different parameters using the concat filter:

Gabungkan dua input dengan concat filter
ffmpeg -i part-a.mp4 -i part-b.mp4 -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" output.mp4

Let's break down the important part. Labels combining input numbers and stream type letters — video and audio from the first input, then video and audio from the second — mark the streams to be joined. The concat filter receives that stream order, then n=2 tells it there are two inputs being joined, v=1 means one video stream, and a=1 means one audio stream. The result gets new labels that are then mapped to the output with -map. Notice there's no -c copy this time — it's required, because the filtered frames must be re-encoded to the target codec.

Important

Never mix the concat demuxer and the concat filter carelessly. The concat demuxer is a muxer that consumes a file list and splices packets; the concat filter is a filter inside a filtergraph that consumes frames. They occupy different layers, and neither can replace the other. If the input is uniform, use the fast demuxer. If it isn't, use the flexible filter.

Cutting Video with the segment Muxer

Now the opposite: splitting one video into many small pieces. FFmpeg provides the segment muxer for this, and it's the older sibling of the hls muxer we'll learn in episode 14. The segment muxer cuts video by duration or size, and writes each piece to a separate file with a name pattern we can define.

The simplest example — cutting video into 10-second segments:

Potong video menjadi segmen 10 detik
ffmpeg -i input.mp4 -c copy -f segment -segment_time 10 seg-%03d.mp4
  • -f segment selects the segment muxer.
  • -segment_time 10 targets each segment to be about 10 seconds long.
  • seg-%03d.mp4 is the file name pattern; %03d is replaced by a zero-padded three-digit sequence number, producing seg-000.mp4, seg-001.mp4, and so on.

There are two details you must understand. First, segments are cut at the next keyframe after the duration is passed, not exactly at second 10. If you want clean, predictable cuts, lock the keyframe interval: use -force_key_frames to force keyframes at the points you want, e.g., every 2 seconds. Second, use -reset_timestamps 1 so each segment's timestamps start at zero — without this, the first segment will look like it "jumps to second 30" when played.

Segmen MPEG-TS dengan timestamp dinolkan
ffmpeg -i input.mp4 -c copy -f segment -segment_time 10 -segment_format mpegts -reset_timestamps 1 seg-%03d.ts

Why mpegts? Because segments for streaming are usually written as MPEG-TS, not MP4. The technical reason: MP4 stores the stream duration in its frontmost header, so a standalone MP4 piece can't play itself properly; MPEG-TS is designed to be spliced piece by piece. This is the foundation of HLS, which demands every segment be independently decodable.

Tip

The segment muxer can also produce a playlist directly. Add -segment_list daftar.m3u8 -segment_list_type m3u8 and FFmpeg will write a list file referencing all generated segments. The playlist we manually produce here is the seed of what the hls muxer will do automatically in episode 14 — only -f hls is far more complete for streaming needs.

Preparing Segments for Streaming

Why all the fuss about cutting video? The answer is adaptive streaming. A large video file must be fully downloaded before it can be played from the middle; by contrast, a video split into small segments can be played piece by piece — the player just downloads the next segment when the previous one is nearly done. Combined with a few quality variants, this is how all major streaming platforms work. We'll assemble it into complete HLS in episode 14, but before that, understand the three traps that most often break segmenting results.

First, segments must be independently decodable. Streaming players decode each segment independently of the others. If the cut isn't at a keyframe, the first segment of each piece will lack reference frames and render as a gray box. Make sure -segment_time is a multiple of the keyframe interval, or force keyframes with -force_key_frames.

Second, don't mix parameters across segments. The only big advantage of -c copy is speed, but it's only safe when the source is stable. If the source changes bitrate or resolution mid-stream, the copied segments can have inconsistent parameters across segments.

Third, verify results with ffprobe. Grab a few random segments and check each with ffprobe. A "healthy" segment shows the same codec, a reasonable duration, and consistent resolution. The habit of verifying output at key points like this is what separates skilled FFmpeg users from those who only memorize commands.

Warning

Be careful with -c copy on segments. When the source and target use different containers — e.g., MP4 to MPEG-TS — the H.264 packets must first be converted from AVCC to Annex B format so players can read them. FFmpeg usually handles this automatically via a bitstream filter, but if copied segments fail to play, check the log for messages like "Malformed NAL unit" — a sign you need to re-encode or add the h264_mp4toannexb bitstream filter explicitly.

Conclusion

In episode 12 you've learned that joining and cutting is container work that depends heavily on file condition: the concat demuxer splices packets without re-encoding only when all files are uniform, the concat filter re-encodes frames when parameters differ, and the segment muxer splits video into small streaming-ready segments with name patterns, keyframe cutting, and playlist writing.

Key takeaways:

  • concat demuxer = fast, no re-encode, but only for uniform files.
  • concat filter = flexible, must re-encode, for files with different parameters.
  • The segment muxer cuts at keyframes; align segment_time with the keyframe interval.
  • -reset_timestamps 1 makes every segment start at zero.
  • Streaming segments are usually written as MPEG-TS so they can be decoded independently.

Now you can split video into segments and (manually) assemble their playlist. The logical next step is sending those segments and streams out of your computer — to a streaming server, to the network, or to live viewers.

In the next episode 13 we'll cover Streaming & Network Protocols — how FFmpeg communicates via RTSP, RTMP, SRT, and UDP, and how to build a capture-encode-push pipeline for low-latency live streaming. Keep your enthusiasm up!

Learn FFmpeg - Concat & Segmenting | Learn FFmpeg