Skip to content
streamneo.
Setup Guides15 min read

How to Stream Pre-Recorded Videos to YouTube 24/7 with FFmpeg on Linux

Set up a continuous prerecorded YouTube stream with FFmpeg on Linux using concat playlists, looping, real-time pacing and RTMPS.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

A Linux machine running FFmpeg can send a prerecorded video, or a prepared sequence of videos, to YouTube Live continuously. The important parts are the concat playlist, compatible source files, -stream_loop for repetition, and -re so FFmpeg reads the files at real-time speed rather than as quickly as the computer can process them.

This is an encoder workflow, not a guarantee of uninterrupted broadcasting. You still need a YouTube stream configured in Live Control Room, a stable host and upload connection, compatible media, process supervision, and a test that runs long enough to expose problems.

Prepare YouTube Live and the Linux host

In YouTube Studio, open Go Live and create or schedule an encoder stream. In Live Control Room, copy the stream URL and stream key shown under the stream settings. YouTube describes stream keys as similar to a password and address for the stream, so do not place the key in a public tutorial, screenshot, repository, shell history or shared log.

You can read YouTube's current encoder workflow in the official live-streaming help guide. The exact labels in Studio may change, but the basic arrangement remains the same: YouTube supplies the ingest destination and FFmpeg sends the encoded feed to it.

Prefer the RTMPS address displayed by Live Control Room when the installed FFmpeg build supports it. RTMPS is RTMP over TLS/SSL, which encrypts the connection between the encoder and YouTube. The endpoint is not something to guess from a blog post. Copy the current address from the stream settings and keep the key separate from the public parts of your command.

On Linux, first check what your FFmpeg installation can actually do:

ffmpeg -version
ffmpeg -encoders | grep -E '264|aac'
ffmpeg -protocols | grep -E 'rtmp|rtmps'

Package builds differ. One distribution may include libx264, while another may provide a different H.264 encoder or omit an encoder that a sample command expects. The same applies to protocol support. A command written for another machine is a template until its options and encoders work on yours.

The machine must remain on, prevent sleep, have enough CPU for the selected encoding settings, and retain enough disk space for logs and media. The upload connection must sustain the video and audio bitrate, with headroom for normal variation. If the computer is in a home or office, consider what happens when the network router restarts or the machine installs updates overnight.

Create a stable media directory

Keep the files used by the stream in a dedicated directory rather than building a playlist from downloads, desktop files and temporary exports. A simple layout makes paths predictable and makes it easier to check what the encoder is reading:

mkdir -p "$HOME/youtube-channel/media"
mkdir -p "$HOME/youtube-channel/logs"
cd "$HOME/youtube-channel/media"

Copy or move the videos into media, then give them simple names. Spaces are supported when paths are quoted, but names containing spaces, quotation marks, brackets or shell metacharacters create avoidable mistakes in hand-written playlist files. Names such as morning.mp4, midday.mp4 and evening.mp4 are easier to inspect than names generated by a phone or editing application.

Do not let the playlist directory change unexpectedly while FFmpeg is running. If you need to replace a file, prepare the replacement separately and test it first. A file that is renamed halfway through a broadcast can produce an input error even though the stream command itself has not changed.

The playlist is not a broadcast schedule in the YouTube sense. It tells FFmpeg which local files to read and in what order. If you need different content at different times of day, a queue or a schedule may be more suitable than one endlessly repeated list. A daily schedule for a 24/7 YouTube music stream covers that planning problem separately.

For an always-on channel, decide what should happen when a clip ends, when the list ends, and when one source is missing. A playlist that looks correct in a text editor can still fail because of a bad path, an unsupported stream or a timing mismatch. Treat the directory and its contents as part of the broadcast configuration.

Write the ffconcat playlist directives

FFmpeg's concat demuxer reads a text file containing a sequence of media files. Start the file with the directive that identifies this format:

ffconcat version 1.0
file 'morning.mp4'
file 'midday.mp4'
file 'evening.mp4'

Save it as playlist.ffconcat in the same directory as the media files. The file lines define the order. Relative paths are useful here because moving the complete channel directory does not require rewriting every entry.

You can also use explicit relative paths:

ffconcat version 1.0
file './morning.mp4'
file './midday.mp4'
file './evening.mp4'

The first line matters. It tells FFmpeg to interpret the file as an ffconcat script rather than as an ordinary media file. Do not add Markdown fences, comments copied from a web page, or explanatory text to the actual playlist.

For filenames that contain characters with special meaning, follow the escaping rules for the concat demuxer and quote the path correctly. The safest operational choice is still to use simple filenames. If a filename contains an apostrophe, for example, copying it directly into a single-quoted entry may not produce the path you intended.

A playlist can include the same file more than once:

ffconcat version 1.0
file 'opening.mp4'
file 'main-programme.mp4'
file 'opening.mp4'

That is useful when you want a short ident or announcement between longer items. It does not make the files compatible. Each transition still depends on the files having a layout and timing that the concat demuxer can handle.

The playlist also does not provide an endless loop by itself. It describes one pass through the listed files. Repetition is added in the FFmpeg input options, which is why the playlist, looping and real-time pacing should be treated as separate pieces of the command.

Check filenames and source compatibility

Before streaming, confirm that every entry exists and that the files can be read. From the media directory, you can inspect the list with ordinary Linux tools:

while IFS= read -r file; do
  [ -z "$file" ] || [ "$file" = "ffconcat version 1.0" ] || printf '%s\n' "$file"
done < playlist.ffconcat

That simple check does not fully parse ffconcat quoting, so also test the complete input with FFmpeg. A useful first inspection command is:

ffprobe -hide_banner -i playlist.ffconcat

If your build needs the format specified explicitly, try:

ffmpeg -hide_banner -f concat -safe 0 -i playlist.ffconcat -f null -

The null output discards the encoded result while FFmpeg reads the sequence. Watch for missing files, invalid data, decoder errors, unexpected stream types and timestamp warnings. Fix those before adding YouTube credentials.

The concat demuxer is most reliable when the files share the same stream arrangement and timing properties. In practical terms, make the clips consistent in resolution, frame rate, video codec, pixel format, audio layout, sample rate and general time base. The source material does not need to have the same subject, but it should be prepared as if it belongs to one continuous programme.

For example, joining one 1920×1080 file at 30 fps with another at a different resolution or frame rate may expose problems at the transition. A clip with no audio can also create a different stream layout from one with stereo AAC audio. The playlist line is not a conversion step.

If the clips are mixed, normalise them before making the final playlist. Choose the output format you intend to send to YouTube, convert each item to that format, inspect the results, and then concatenate the normalised files. This adds an export step, but it moves difficult compatibility decisions out of the overnight broadcast.

You can use the FFmpeg documentation for the concat demuxer to check the syntax supported by your installed version. Do not assume that a playlist alone guarantees a working stream. It only supplies an ordered input; decoding, timestamps, encoding, network output and YouTube's ingest checks still have to succeed.

Pass the list to FFmpeg

Once the playlist reads correctly, pass it to FFmpeg with the concat demuxer. The following command shows the main structure without connecting to YouTube:

ffmpeg -re -f concat -safe 0 -i "/home/you/youtube-channel/media/playlist.ffconcat" \\
  -map 0:v:0 -map 0:a:0? \\
  -c:v libx264 -preset veryfast -pix_fmt yuv420p \\
  -r 30 -g 60 -b:v 6000k -maxrate 6000k -bufsize 12000k \\
  -c:a aac -b:a 128k -ar 44100 \\
  -f null -

The -f null - output is only a test destination. It lets you confirm that FFmpeg can read the playlist, decode the media, encode the selected output and run at approximately real-time speed without exposing the stream key.

Here, -f concat selects the concat demuxer and -safe 0 permits the absolute path used in the example. The -map options select the first video stream and the first audio stream when one exists. The question mark on the audio map makes that mapping optional, so a file without an audio stream does not immediately fail for that reason. A channel still needs to decide how it wants to handle silent material.

The output settings are examples for a 30 fps H.264/AAC stream. They are not universal values. libx264 must exist in the local build, and the bitrate must match the intended resolution, frame rate, encoder and available upload capacity.

When the local test passes, replace the null output with the RTMPS URL from YouTube. Keep the key out of copied public commands. One practical pattern is to put the complete destination in a protected configuration file and restrict its permissions, or to construct the final command from a protected environment value. Check how your shell, service manager and logging setup handle command lines before choosing that method.

YouTube's encoder settings and bitrate guidance currently lists H.264 examples including 1080p at 30 fps with a 5 Mbps minimum and 14 Mbps recommended bitrate. The same table gives different guidance for other resolutions, frame rates and codecs. The 6 Mbps value in the sample command is deliberately only an example above that listed minimum, not a claim that it is YouTube's recommendation for every channel.

YouTube also documents constant bitrate encoding, AAC or MP3 audio, frame rates up to 60 fps and a keyframe interval of two seconds, advising not to exceed four seconds. Match the settings to the current official table and to the actual source. After starting FFmpeg, check the preview and stream health in Live Control Room before making the broadcast public.

Add looping and real-time pacing

For a single file, FFmpeg can repeat the input with -stream_loop -1. For a concat playlist, the same input option can repeat the complete list, provided the concat input is accepted by the installed build and the source sequence is valid. The essential shape is:

ffmpeg -re -stream_loop -1 \\
  -f concat -safe 0 -i "/home/you/youtube-channel/media/playlist.ffconcat" \\
  -map 0:v:0 -map 0:a:0? \\
  -c:v libx264 -preset veryfast -pix_fmt yuv420p \\
  -r 30 -g 60 -b:v 6000k -maxrate 6000k -bufsize 12000k \\
  -c:a aac -b:a 128k -ar 44100 \\
  -f flv "rtmps://INGEST_HOST/APP/STREAM_KEY"

The position of the input options matters. -stream_loop -1 applies to the input that follows, and -re tells FFmpeg to read at the native real-time rate. Put them before the corresponding -i. Without real-time pacing, a file input can be consumed faster than its presentation time, which is not the behaviour wanted for a live encoder feed.

Looping and pacing solve different problems. -stream_loop -1 answers, “What should happen when this input reaches its end?” -re answers, “How quickly should FFmpeg read it?” Neither option repairs a corrupt file, converts incompatible clips, restores a dead Linux host or reconnects an invalid YouTube key.

YouTube expects a continuous encoder feed, but the broadcast may still experience interruptions at clip transitions or when the process exits. Start with a private or unlisted test stream. Watch at least one transition, allow the list to reach its end if practical, and confirm that the next loop begins with valid audio, video and timestamps.

The host also needs supervision. A terminal session is not a reliable operations plan if closing the terminal stops FFmpeg. You can use a service manager, a process supervisor or another tested method that starts the command at boot, keeps logs within a known size, and records exit failures. Test the restart path rather than assuming it works.

FFmpeg documents FIFO output options that can retry an RTMP output after a temporary failure, including recovery-related settings. Those options are a recovery mechanism for a particular class of output problem. They do not fix a powered-off host, a failed decoder, an invalid key, a disabled broadcast or an interruption on YouTube's side. Add them only after checking the syntax in your installed version and testing the resulting behaviour.

If the operational burden is the problem rather than the media preparation, StreamNeo removes the need to leave your Linux computer encoding overnight: upload the finished video, provide the YouTube stream key, and let the cloud workflow run and restart the broadcast automatically when it drops. It remains a YouTube-only workflow, so YouTube's own stream settings and content policies still apply.

Treat HLS as a separate output workflow

HLS is not another name for the RTMPS command above. The RTMP or RTMPS workflow sends a continuous encoded feed to YouTube's ingest endpoint. HLS creates a playlist file and a sequence of media segments for a player or delivery system. It has separate output settings, file paths, segment duration decisions and cleanup requirements.

A basic HLS example might look like this:

ffmpeg -re -stream_loop -1 -i input.mp4 \\
  -c:v libx264 -preset veryfast -pix_fmt yuv420p \\
  -c:a aac -b:a 128k \\
  -f hls -hls_time 4 -hls_list_size 6 \\
  -hls_flags delete_segments \\
  /var/www/html/live/index.m3u8

That command writes an HLS playlist and segment files. It does not send the result to YouTube's RTMPS ingest URL, and an HLS playlist is not a substitute for the -f flv output used in the RTMP-style command. The segment directory must be writable, the playlist and segments must be served correctly, and the player or delivery platform must be configured to retrieve them.

HLS may be the right output when you control a web player or a distribution endpoint that accepts HLS. It may be the wrong choice when your immediate goal is a YouTube Live broadcast. Keeping these workflows separate prevents a common failure: producing a valid local .m3u8 file while never sending a feed to the YouTube stream.

HLS also introduces lifecycle questions that do not appear in exactly the same form with a direct RTMPS output. Decide how many segments remain in the live playlist, whether older segments are deleted, where temporary files are stored, and what viewers should see after the encoder stops. Test the playlist over HTTP from another device rather than checking only that files appeared on disk.

For this article's YouTube workflow, use the stream URL and key from Live Control Room and an output format accepted by that ingest service. Use HLS only when the receiving system specifically requires an HLS playlist and segments.

Test the overnight operation

A successful command launch is only the first check. Confirm that YouTube receives the feed, the preview shows the intended picture, audio meters move when audio is present, and the stream health panel does not report an input or bitrate problem. YouTube recommends testing before starting a live stream and monitoring audio and video.

Check the parts that are easy to miss:

  • Does the first playlist entry decode correctly from a clean start?
  • Does the transition between two clips keep audio and video present?
  • Does the final entry return to the first entry when looping?
  • Does the upload remain stable while the encoder is running?
  • Does FFmpeg write useful logs without filling the disk?
  • What happens when the network is briefly interrupted?
  • What happens when the process exits and is restarted?
  • Is the stream key absent from public logs and copied commands?

A 24/7 stream also has YouTube-side limits and publishing implications. YouTube says streams under 12 hours are automatically archived, but you should not assume that an arbitrarily long broadcast becomes one complete archive. Its documentation also notes that DVR may be limited or unavailable for very long streams longer than 12 hours. Check the current official pages before designing your archive or viewer experience around those features.

Do not describe a prerecorded loop as automatically eligible for monetisation or compliant with every YouTube policy. Review the current YouTube monetisation and content policies for the actual material and channel. If your channel uses devotional music, news footage, public-domain material, commissioned content or licensed tracks, keep records of the rights and permissions that apply to each item.

For channels carrying music or ambience, normalise the source files before building the playlist and test the joins with headphones. For devotional channels, pay attention to rights in recordings as well as the underlying composition. For a local news loop, confirm that dated information does not remain on air after it becomes misleading. A 24/7 aarti and mantra setup guide discusses rights and publishing considerations in that specific setting.

If FFmpeg repeatedly stops after a few hours, inspect the process log, host resources, input errors and network events rather than immediately changing unrelated bitrate values. The common causes of OBS stopping after a few hours are not identical to FFmpeg failures, but the same operational lesson applies: identify whether the problem is the source, encoder, host, connection or YouTube ingest.

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 FFmpeg loop one video on YouTube Live?

Yes. Use -stream_loop -1 as an input option and -re to read a file at real-time speed, then encode the result to an RTMP or RTMPS output accepted by YouTube. Test the complete command because looping does not repair an invalid source or guarantee uninterrupted delivery.

Does the concat file create a 24/7 stream by itself?

No. The ffconcat file supplies an ordered list of local inputs. You still need compatible media, FFmpeg decoding and encoding, real-time pacing, an output endpoint, a protected stream key, a stable host and a working upload connection.

Is HLS the same as streaming to YouTube with RTMPS?

No. RTMPS sends an encoded feed to YouTube's ingest endpoint. HLS writes a playlist and media segments for a player or service that accepts HLS, so it has separate file-serving and segment-management requirements.

What should I do if a playlist transition fails?

Inspect the files at the transition and compare their resolution, frame rate, codecs, pixel format, audio layout and timing properties. Normalise mixed clips to a consistent format, test the playlist locally with FFmpeg, and only then reconnect it to the YouTube workflow.

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 ↗