Skip to content
streamneo.
Setup Guides13 min read

How to Stream Multiple Videos Continuously with FFmpeg Concat

Choose the right FFmpeg concat method, join compatible files safely, re-encode mismatched inputs, and send the result to YouTube Live.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

If you want several videos to play in order without restarting FFmpeg, use the concat demuxer when the files already have matching streams and compatible timestamps. If they differ, use the concat filter and re-encode them into a common output instead of forcing stream copy.

That distinction matters for a 24/7 channel. Concatenating files is one job; publishing the resulting media to YouTube is another. The input method chooses how files are joined, while the output options decide how the finished sequence is delivered.

Choose the concat method for your files

FFmpeg has three different mechanisms commonly described as “concat”. They are not interchangeable, and choosing the wrong one is a common reason for broken transitions or a command that works for one set of files but not the next.

Your situation Appropriate method Main constraint
Files already have the same streams, codecs and time bases Concat demuxer with stream copy Duration metadata and stream layouts must be reliable
Files differ and need resizing, frame-rate changes or audio normalisation Concat filter with re-encoding You must choose output codecs and encoding settings
The format supports file-level resource concatenation Concat protocol It is not a general-purpose container join method

The concat demuxer reads a text file and presents the listed media as one sequential input. It is usually the best starting point for a library of similarly encoded MP4 files because -c copy avoids decoding and encoding them again.

The concat filter operates inside a filter graph. It decodes the inputs, combines them, and sends the result to an encoder. That makes it suitable when one video is 720p and another is 1080p, or when their audio layouts and timing do not match. The cost is additional processing and another encode.

The concat protocol is a lower-level option for formats that support this kind of file or resource concatenation. FFmpeg documents examples using MPEG resources, but it should not be treated as a replacement for the demuxer when joining arbitrary MP4 or other containers. The official FFmpeg FAQ explains the distinction between the demuxer, filter and protocol.

If your goal is an endless playlist rather than one fixed sequence, also separate the media problem from the scheduling problem. A static list plays the files named in that list. It does not automatically discover new files added later or guarantee that a process will keep building a fresh queue.

Check stream and codec compatibility first

Stream copy means FFmpeg passes already encoded packets to the output without decoding, filtering or encoding them. It is fast and avoids another generation of compression, but it cannot make incompatible inputs compatible.

For concat demuxer use, the files need matching streams, including compatible codecs and time bases. In practical terms, compare more than the file extension. Check the video codec, width and height, frame rate, pixel format where relevant, audio codec, channel layout, sample rate and the number and order of streams.

You can inspect each file with ffprobe, which is distributed with FFmpeg:

ffprobe -v error -show_streams -show_format first.mp4
ffprobe -v error -show_streams -show_format second.mp4

Read the results side by side. A pair of files can both be called MP4 while containing different video codecs, different audio arrangements or different timing information. The container name alone is not a compatibility test.

You do not necessarily need every metadata field to look identical, but you should not assume that different stream layouts will join cleanly merely because both files play normally on their own. If one file has an extra audio stream, for example, decide whether that stream should be removed or whether all files should be normalised to include it.

For a YouTube channel, consistent output is also easier to monitor. The article on keeping video quality consistent across a YouTube loop stream covers why changes between files can be visible even when each individual file looks acceptable.

When the inspection shows a compatible set, try the demuxer and stream copy. When it shows meaningful differences, plan a filter-based encode. Do not use -c copy as a test for whether FFmpeg can somehow repair the differences; its purpose is precisely not to change the media.

Build a concat demuxer list

Create a plain text file called list.ffconcat in a convenient working directory:

ffconcat version 1.0
file 'first.mp4'
file 'second.mp4'
file 'third.mp4'

The header must be the exact first line, with no extra spaces or byte-order mark, so FFmpeg can recognise the format automatically. Each file line names one input, and the order of those lines is the playback order.

Relative paths are easier to audit and usually avoid unnecessary path-safety changes. If the files are in another directory, you can use paths appropriate to your operating system. Paths containing spaces or special characters need correct quoting or escaping. Test a small list before preparing a full overnight sequence.

The demuxer applies safety checks to paths. If your trusted local list contains paths outside its safe relative-path rules, you may need to add -safe 0 to the input command. That option deliberately relaxes the check, so use it only when you understand and trust every path in the list. It should not be added automatically to every command.

For example, if the list uses absolute local paths:

ffconcat version 1.0
file '/home/channel/videos/morning.mp4'
file '/home/channel/videos/afternoon.mp4'

You may run:

ffmpeg -f concat -safe 0 -i list.ffconcat -c copy output.mp4

On Windows, take care with backslashes, drive letters and the quoting rules of the shell you are using. A path that looks correct in a text editor can still be parsed differently by the command interpreter. Keep the first test small and verify the output before putting a longer sequence into a live process.

The list is a manifest, not a folder watcher. If you edit it while FFmpeg is already reading it, do not assume the running process will reload the new entries. For a channel that must add media while it is running, use a deliberate queue or process-management design rather than relying on an undocumented hot-reload behaviour.

Run a stream-copy example

Once the files have matching streams, the basic local join is:

ffmpeg -f concat -safe 0 -i list.ffconcat -c copy output.mp4

Use -safe 0 only when the paths require it. For ordinary relative filenames, this is preferable:

ffmpeg -f concat -i list.ffconcat -c copy output.mp4

The -f concat option tells FFmpeg to use the concat demuxer. The -i option supplies the list, and -c copy requests stream copy for the output. This command does not decode the video to correct a size mismatch, rebuild audio timing or apply a transition. If the source streams are not suitable, the command may fail or produce a file with an untidy transition.

First create a local output and watch the join points. Check the final seconds of the first file and the first seconds of the next one. Listen for missing audio, a frozen frame, a sudden change in dimensions or a pause that is not present in either source.

If the output is sound, you can adapt the same input structure for a live destination. Do not treat a successful local MP4 as proof that the receiving service accepts the same output settings. The output container, codecs, pixel format, keyframe behaviour and transport still need to match the destination’s current ingest requirements.

A useful next step is to compare this fixed-sequence approach with the workflow in the guide to looping multiple MP4 files on a 24/7 YouTube livestream. A loop can suit a settled playlist; a concat list gives you more explicit control over order and file selection.

Use the concat filter when inputs need normalisation

Choose the concat filter when the files cannot meet the demuxer’s stream-compatibility requirements without being changed. Typical reasons include different dimensions, frame rates, pixel formats, audio sample rates or channel layouts.

A filter-based workflow decodes each input, applies any required preparation, joins the prepared streams, and encodes the result. The inputs must still be described correctly in the filter graph. The filter does not remove the need to decide what the common output should be.

For two video files with one video and one audio stream each, a simplified example is:

ffmpeg -i first.mp4 -i second.mp4 \
  -filter_complex "[0:v]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2,format=yuv420p[v0];[1:v]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2,format=yuv420p[v1];[0:a]aresample=async=1[a0];[1:a]aresample=async=1[a1];[v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" \
  -c:v libx264 -c:a aac -shortest normalised.mp4

This is an example structure, not a universal command for every pair of files. It scales both videos into a common 1280 by 720 canvas, converts the video pixel format, prepares the audio streams, concatenates two video and audio pairs, then encodes the result. You may need to change the scale policy, audio handling, codecs or output options for your material.

The important part is the reasoning. Each input is made compatible before the concat filter joins it. If you have three files, the filter graph needs three prepared video streams and three prepared audio streams, with n=3. If a file has no audio, you need a separate decision: add silence, remove audio from every input, or handle that input with a graph designed for the actual stream layout.

Re-encoding takes longer and can reduce quality compared with stream copy, depending on the source and chosen settings. It also creates more work for the computer running FFmpeg. On the other hand, it gives you one predictable output format, which is often easier to send to a live service than a collection of mixed sources.

Before putting a filter graph into an overnight channel, render a short test that includes every type of transition in the planned playlist. Test a video-to-video change, a quiet audio section, a file with different dimensions and the longest expected source. This catches graph assumptions before they become a live interruption.

Send the resulting sequence to YouTube Live

The concat input and the live output are separate parts of the command. Keep the demuxer or filter selection on the input side, then configure the output for the destination you are using.

A generic shape looks like this:

ffmpeg -re -f concat -i list.ffconcat \
  -c:v YOUR_VIDEO_CODEC -c:a YOUR_AUDIO_CODEC \
  -f YOUR_OUTPUT_FORMAT "YOUR_LIVE_DESTINATION"

Replace the placeholders with settings required by the receiving service. Do not copy this as a complete YouTube command: the appropriate codecs, container, transport URL, stream key handling and rate-control settings depend on the current ingest instructions and on whether you used stream copy or re-encoding.

For YouTube, check the current YouTube Help guidance for live encoders and the settings shown in YouTube Studio for the specific broadcast. Keep the stream key private, and do not paste it into a shared script, screenshot or public support post.

The -re option is commonly used when reading local media for live-style pacing, so FFmpeg reads at approximately the media rate rather than consuming the files as quickly as the machine can process them. It does not fix incompatible streams, create an endless playlist or ensure that the output meets YouTube’s requirements.

For a local file sequence, you might first validate the output with a short run rather than connecting the full channel immediately. Once the media transitions are clean, add the destination settings and observe the broadcast in YouTube Studio. A local success confirms the join; it does not confirm the network path or the platform’s acceptance of the output.

If your computer must stay on for the entire broadcast, power settings, network stability and process supervision become part of the design. The guide to running a yoga music live stream from a cloud server discusses the operational difference between keeping your own computer running and placing the long-running job elsewhere. StreamNeo removes the need to leave your computer running for this particular YouTube workflow by taking an uploaded video, your stream key and the continuous broadcast process into one managed setup.

That does not remove the need to check your media rights, YouTube account status, stream settings or the actual broadcast. It only addresses the specific problem of keeping the file-based stream process running when you do not want to manage it locally.

Check timestamps and diagnose transitions

A concat demuxer sequence is timestamped using the duration information associated with each file. The first file begins at timestamp zero, and later files are offset using the preceding file’s duration. If a duration is missing or inaccurate, the next file can begin too early or too late.

Symptoms include a short gap, a repeated moment, an abrupt audio change or a transition that appears to drift after several files. Do not assume that a visible pause is caused by YouTube. Reproduce the sequence as a local output first and inspect the source durations.

Use ffprobe to examine the format and stream information:

ffprobe -v error -show_entries format=duration \
  -show_entries stream=index,codec_name,width,height,avg_frame_rate,time_base \
  -of default=noprint_wrappers=1 first.mp4

Compare the reported duration with the actual playable content. A truncated recording, unusual container metadata or a file that was not finalised cleanly can make the stored duration unhelpful. The demuxer list supports a duration directive when you need to override an inaccurate or missing duration deliberately:

ffconcat version 1.0
file 'first.mp4'
duration 42.5
file 'second.mp4'

Only use an override when you have checked what the correct value should be. An arbitrary duration can replace one timestamp problem with another. If the source itself has damaged timing, remuxing or re-encoding that source may be a better repair than adjusting the list.

Also check the list itself. A missing line, a duplicated line or an unexpected filename can look like a codec failure when it is simply an ordering error. Keep a copy of the exact list used for a broadcast so you can reproduce the same sequence during diagnosis.

If stream copy produces a clean local file but the live stream ends unexpectedly, investigate the output process and destination separately. The troubleshooting guide for a YouTube live stream that ended unexpectedly covers the broader checks around credentials, connection and process failure. If the local file already has a bad transition, return to compatibility, filtering and timestamp checks instead.

Make the workflow reliable overnight

Start with a short playlist and let it run through every transition. Confirm that the order is right, that audio remains present, and that the output does not stop at the end of the last file. A concat list is finite unless you repeat its contents or create a separate mechanism that supplies more input.

If you need the same list to repeat, one approach is to generate a longer list with repeated entries before starting FFmpeg. Another is to use a process or playlist design that deliberately starts the next cycle. The correct choice depends on how often the content changes and how much control you need over a live schedule.

Keep the input list, the exact FFmpeg command and a record of the source versions together. This makes it possible to distinguish a changed file from a changed command. Avoid editing source files in place while they are being read, especially if another application is still writing them.

Monitor the process and the broadcast independently. FFmpeg can remain running while the destination rejects output, and a destination can show a problem even though the local process has not exited. Check the local log, the network connection and the platform’s live status rather than relying on one indicator.

Before committing, compare the operating options on the pricing page. When the file and channel are ready, start free — 24-hour trial, no card.

FAQ

Can I use -c copy when the files have different resolutions?

Not reliably. Stream copy does not resize or otherwise normalise the inputs, so different dimensions are a reason to prepare the files first or use a concat filter with an output format chosen for all of them.

Is the concat protocol the same as the concat demuxer?

No. The demuxer reads a list of inputs and is intended for compatible streams, while the protocol joins resources at a lower file or resource level for formats that support it. The protocol is not a universal way to combine arbitrary MP4 files.

Will editing list.ffconcat add new videos to a running stream?

Do not assume it will. The list is a static input description for the process, so adding lines after FFmpeg has started is not a general hot-reload mechanism. Use a deliberate queue or scheduling design when content needs to arrive during the broadcast.

Why does the next video start with a gap or repeated frame?

Check the preceding file’s duration metadata and the stream timing first. The concat demuxer uses file durations when offsetting later inputs, so inaccurate duration information can create gaps or misplaced transitions.

YOU’VE REACHED THE END

Keep the ideas coming.

More guides, useful tools and a little help for your next broadcast.

Back to the journal ↗
YOUR NEXT READ

A little more to explore.

More Setup Guides guides ↗ · All topics ↗