Skip to content
streamneo.
Tools12 min read

How to Keep FFmpeg Playing a Radio Playlist After One File Ends

Use FFmpeg’s concat demuxer and -stream_loop -1 to repeat a radio playlist, with guidance on paths, compatible files and streaming output.

sn.
StreamNeoPublished 5 October 2026
Worth sharing?

If FFmpeg stops when the last track in your radio playlist ends, use a concat playlist as its input and set -stream_loop -1 to repeat that input indefinitely. The loop option belongs before the -i that reads the playlist; it is not an output option and does not reconnect a failed network stream.

The example below is an adaptable starting point, not a tested server-specific recipe. You will need to set its output format and destination for your own streaming service, and make sure the files in the playlist are compatible with the concat demuxer.

Why playback stops after one file

A local audio file has a finite end. If FFmpeg reads a single track and sends it to a live destination, it reaches end-of-file (EOF) when that track finishes. The live output then has no more audio to send. A destination may close the connection or report that the stream has ended, but neither behaviour means FFmpeg has automatically chosen the next file.

A playlist and a loop solve two related but separate parts of the problem. The concat demuxer reads a text file that names the tracks and presents them in order. -stream_loop -1 tells FFmpeg to repeat that demuxer input without a set number of repeats. Together, they let a finite set of local files provide a continuing sequence.

This is a configuration change, not a requirement to buy a physical product. If your goal is a continuously running YouTube channel rather than a radio-server mount, the destination and operating arrangement differ. For context on that distinction, see how an always-on YouTube channel can run during load shedding in India.

Do not confuse a playlist ending with a connection problem. A remote input that drops needs a network-recovery approach; a local playlist that reaches its final entry needs looping. FFmpeg documents protocol reconnect controls separately from its input loop option in the protocol documentation. Reconnect settings cannot make a local list start again after its last file.

Build a concat playlist file

Create a plain text file, for example playlist.txt, in the order you want the tracks to play. A basic script looks like this:

ffconcat version 1.0
file 'track-01.mp3'
file 'track-02.mp3'
file 'track-03.mp3'

The first line identifies the concat script format. Each following file directive names one input file. FFmpeg reads those files in sequence, so the second entry follows the first, and the third follows the second. Reorder the lines to change the broadcast order; the demuxer does not shuffle them for you.

Keep the playlist and tracks together while you are getting the setup working. Relative paths such as track-01.mp3 are then easier to check than absolute paths, which vary between computers. If your playlist is stored elsewhere, use a path that resolves from the process's working directory, or use absolute paths deliberately and account for safe mode as described below.

The concat demuxer documentation explains the script format and how the demuxer joins files. It adjusts timestamps so a subsequent file follows the preceding one. That does not make arbitrary media files interchangeable: the inputs still need compatible streams and parameters for this method to be appropriate.

A playlist is not a media file. Renaming a text list to .mp3 will not turn it into audio, and writing the filenames one per line without the file directive does not create the concat script shown here. If FFmpeg says it cannot parse the playlist, inspect the first line, directive spelling, quotation marks and file paths before changing the output options.

Add infinite input looping

For a local playlist, the adaptable audio-only starting point is:

ffmpeg -re -stream_loop -1 -f concat -safe 0 -i playlist.txt \
  -vn -c:a libmp3lame -b:a 128k -f mp3 OUTPUT

playlist.txt is the script created above. -f concat selects the concat demuxer for that input, and -i identifies the playlist. -stream_loop -1 makes FFmpeg repeat that input indefinitely. The FFmpeg command-line reference defines -stream_loop as an input option and -1 as infinite looping; consult the current FFmpeg command-line documentation if you use a different build or need to check option details.

The rest of the command is only a starting point. -re reads the input at its native rate, which is useful when local files are being sent to a real-time output. -vn says not to include video. -c:a libmp3lame selects MP3 audio encoding, -b:a 128k sets an example audio bitrate, and -f mp3 selects the output format. OUTPUT is a placeholder, not a literal server address.

The bitrate shown is an example, not a quality recommendation or a requirement from a radio provider. Confirm what your destination accepts and choose audio settings that fit your source and use. Likewise, MP3 output will not suit every endpoint. The fact that the input loop is configured correctly does not establish that the output protocol, credentials, container or codec will be accepted.

-safe 0 is included because absolute paths and some other path forms are rejected by the concat demuxer’s default safe mode. It allows those paths, so use it only when the playlist is one you control and trust. If every path is simple, relative and safe, you can omit -safe 0 and leave the default safe mode enabled.

Put the loop option before its input

The placement is important. The loop setting applies to an input, so it must appear before the -i for the playlist it should repeat:

-stream_loop -1 -f concat -safe 0 -i playlist.txt

In the full command, these input options come after ffmpeg and before the playlist’s -i. They describe how FFmpeg reads that input. The options after -i playlist.txt describe what FFmpeg does with the decoded media or how it writes the output. If you place -stream_loop -1 after the playlist input, it is no longer attached to that input in the intended way.

This distinction matters when a command has more than one input. Put each input option before the corresponding -i, rather than assuming an option placed anywhere in the command applies to the whole job. For this single-playlist example, the order makes the relationship clear: loop the concat input, then configure the output.

Do not change -1 to another value while expecting the same behaviour. The value -1 means repeat indefinitely. A different loop value changes the repeat behaviour, so use the documented value when the requirement is to keep replaying the playlist without a fixed repeat count.

The -re option also concerns input reading, but it serves a different purpose. It paces local file reading at the native frame rate for cases where output packet timing matters, such as live streaming. It neither selects the playlist nor retries a connection. The FFmpeg documentation on reading and writing at real-time rates describes this pacing behaviour.

Adapt the output for your streaming server

The input playlist and the destination are separate pieces of the command. OUTPUT must be replaced with the endpoint syntax and any authentication details required by your radio server. The suitable protocol, mount or endpoint, credentials, output container and audio codec depend on that service and on the FFmpeg build you are using. Check the provider’s current documentation rather than copying a destination string from an unrelated example.

This is why the command above is not a universal copy-and-paste recipe. It demonstrates the playlist input and its infinite loop, while leaving the deployment-specific output unresolved. FFmpeg’s streaming examples illustrate output as a separate configuration concern; an example for one endpoint does not prove another service accepts the same form.

If the command reads the playlist but the server rejects the connection, inspect the output side first: confirm the endpoint spelling, required authentication method, format and codec. If FFmpeg reaches the server but no audio is heard, check the accepted audio stream and the service’s own status information. Avoid treating a remote rejection as evidence that the concat playlist failed.

The same separation is useful if you are sending audio into a video-oriented live workflow. YouTube stream-key configuration, for instance, is its own destination setup, as explained in this guide to setting up a YouTube stream key in vMix. A radio server mount and a YouTube ingest endpoint should not be assumed to use interchangeable output options.

If the operational problem is keeping an uploaded programme running when your own computer is off, rather than composing a local radio playlist in FFmpeg, StreamNeo removes the need to leave that computer running by turning an uploaded video into a 24/7 YouTube live stream. It is YouTube-only, so it does not replace a radio server or solve its endpoint-specific output configuration.

Check paths, order and compatibility

Before leaving a stream unattended, check that every file entry resolves to a readable track and that the lines are in the intended order. A missing file can stop processing before the loop has a chance to make another pass. A spelling difference in a filename or a working-directory change can produce the same practical result even if the playlist looked correct when edited.

Next, check that the tracks are suitable for the concat demuxer. FFmpeg’s documentation is explicit: “All files must have the same streams (same codecs, same time base, etc.).” For an audio playlist, differences in stream layout, codec or timing properties may make an apparently simple sequence unsuitable or lead to transition problems.

If the files do not have compatible stream properties, first normalise or transcode them to a consistent format, then use the concat demuxer. That adds a preparation step and can involve re-encoding, but it is more appropriate than expecting the demuxer to reconcile unlike inputs. FFmpeg’s FAQ describes the concat filter as the approach for concatenation when re-encoding is needed; the demuxer is suited to compatible files where avoiding a re-encode is useful. The FFmpeg FAQ on concatenation covers the distinction.

Duration information is another point to inspect when a transition has a gap or artefact. The concat demuxer uses each file’s duration to set timestamps for the next file. If a file’s stored duration is wrong or unknown, the next timestamps can be off. The concat script has a duration directive that can override a stored duration, but use it only when you have a reliable duration to enter and have confirmed that duration handling is the issue.

For path errors, use a simple relative-path layout first if it suits your workflow. If you need absolute paths or a path that safe mode rejects, -safe 0 permits it; keep the playlist controlled and trustworthy when doing so. Do not disable safe mode reflexively as a remedy for codec, duration or output-connection errors: it changes which paths can be read, not how tracks are joined or sent to a server.

Diagnose the kind of failure

When something fails, identify where the failure occurs before changing several options at once. If FFmpeg reports an inability to open a file, check the path, filename, permissions and process working directory. If it reports an unsafe filename, decide whether a safe relative path is practical; otherwise, use -safe 0 only with a playlist you trust.

If FFmpeg opens the files but reports a stream or timestamp issue at a transition, examine the media properties and duration information. The concat demuxer expects compatible inputs; a list containing files with different codecs or stream layouts may need normalisation. Changing the loop count will not fix a mismatch between tracks.

If the playlist plays through but the destination disconnects, separate that network event from local EOF. The loop option repeats local input; protocol reconnect options concern supported network inputs and have their own conditions. They are not substitutes for each other. Similarly, -re affects reading pace, not a broken path, incompatible file or rejected server endpoint.

Make one change at a time and keep a copy of the last command that reached the expected stage. For example, first confirm the playlist can be read locally, then verify that the tracks transition correctly, then configure the service output. This makes it easier to tell whether the remaining fault is in the files, the script, the output settings or the network connection, instead of attributing every stop to the playlist loop.

If your overall aim is a continuous video loop on YouTube rather than an audio radio playlist, the underlying workflow differs. This article on looping one pre-recorded video continuously in OBS covers that separate setup; it should not be treated as a replacement for the concat-demuxer input shown here.

Make the unattended run understandable

A command that works during a short test still needs sensible operating checks before you rely on it overnight. Keep the playlist in a stable location, note the exact command and record which output destination it targets. If you revise the order or replace a file, verify the playlist again rather than assuming the new version matches the old one.

Check the full cycle, including the transition from the final entry back to the first. Infinite looping only repeats the input list; it does not make the transition inaudible, repair damaged media or guarantee that a server maintains a connection. Listen for an unexpected silence or abrupt change at the boundary and review FFmpeg’s messages for warnings about files and durations.

A long-running stream also depends on the process continuing to run and on the destination staying reachable. Those concerns are outside the local playlist loop itself. Plan how you will notice a stopped process or a rejected connection, and decide what recovery action is appropriate for your host and service. Do not infer a reliability guarantee from the fact that the command has -stream_loop -1 in it.

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

Does -stream_loop -1 mean the playlist repeats forever?

Yes. In FFmpeg’s command-line reference, -1 means infinite looping for the input. Place it before the matching -i, here the one that reads playlist.txt.

Can I use this with tracks that have different codecs?

The concat demuxer expects files to have the same streams and compatible properties, including codecs and time bases. If your tracks differ, normalise or transcode them to a consistent format, or use a workflow such as the concat filter when re-encoding is needed.

Does the command work with every radio server?

No. The command is an adaptable starting point, not a tested server-specific recipe. Replace OUTPUT and confirm the endpoint, authentication, accepted format and codec against the documentation for your own service.

Will the playlist loop reconnect FFmpeg if the server drops?

No. The loop repeats local input; it does not reconnect a network output. Reconnect controls apply to supported network protocols and address a different failure, so diagnose local EOF and connection loss separately.

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 Tools guides ↗ · All topics ↗