To loop a sequence of local video clips into YouTube Live, put their paths in an FFmpeg concat-demuxer playlist, then use FFmpeg to read that playlist repeatedly and encode a live output. The clips need compatible streams and timing; the playlist does not fix mismatched files or create seamless transitions.
The reliable workflow is to check the exact playlist syntax, inspect the source sequence, choose an output encode, and test the actual stream with YouTube’s ingest details before relying on it overnight. Treat the command below as a starting shape to adapt, not as a tested preset.
Prepare the ffconcat playlist file
Create a plain-text file named playlist.ffconcat. Keep it in the directory from which you will run FFmpeg, or use paths that you have checked carefully. A simple playlist with three clips looks like this:
ffconcat version 1.0
file 'clip1.mp4'
file 'clip2.mp4'
file 'clip3.mp4'
Each file directive names one input, and the order of those lines is the playback order. The concat demuxer presents the listed files as a single virtual input, reading their packets one after another. It does not combine them into a new video file, render transitions, or make an incompatible clip compatible with its neighbours.
Use filenames that are easy to type and verify. Relative names such as clip1.mp4 are resolved from the working directory where FFmpeg runs, not necessarily from the location of the playlist. If you launch the command from a service, scheduled task, or different terminal directory, check that its working directory is what you expect. Alternatively, put a relative path in each directive, such as media/clip1.mp4.
The syntax inside this file is concat-demuxer syntax, not a shell command. Quoting and escaping spaces or special characters therefore follow FFmpeg’s playlist rules rather than the rules for the command line you use to launch FFmpeg. The safest first test is with simple filenames without spaces, apostrophes, or unusual characters. For more elaborate paths, consult the FFmpeg concat demuxer documentation and test that FFmpeg can read every entry before setting up a long-running broadcast.
A useful preparation step is to make a short playlist containing the first two or three clips and check it before adding the full rotation. That isolates path and compatibility problems. Keep a copy of the final playlist somewhere you can restore; editing it while FFmpeg is already running does not mean the active input will necessarily adopt your changes.
Put the exact signature first
The first line must be exactly ffconcat version 1.0. Do not put a blank line, leading spaces, a comment, or a byte-order mark before it. The exact signature at the start of the file lets FFmpeg recognise the format automatically. A text editor can silently add a byte-order mark or save in an unexpected encoding, so use a plain-text editor and inspect the first line if FFmpeg reports that it cannot identify the input format.
After that line, add one file directive per clip. Keep the list in the order you want the audience to see and hear it. For a devotional channel, that might mean an opening slate, a group of bhajans, and then a closing slate before the sequence repeats. For a study channel, it might be several lesson segments in chapter order. The demuxer follows the written order; it does not sort files by name or infer a programme sequence.
FFmpeg’s concat demuxer applies a safe-path check by default. Simple relative paths are usually the least troublesome choice. If you intentionally use absolute paths or paths that FFmpeg considers unsafe, -safe 0 can relax that check, but it should only be used with a playlist you control. It is an input option and belongs before the -i that names the playlist, as in -safe 0 -i playlist.ffconcat. Do not use it to process a playlist supplied by someone else without inspecting the paths first.
If the playlist contains a path with spaces, do not assume putting double quotes around the whole directive will work like a shell. Follow the concat file’s quoting and escaping rules, then run a short read test. This small distinction prevents a common confusion: the quotes you use around "$INGEST_URL/$STREAM_KEY" in a shell command protect a shell argument, while quotes in the playlist are interpreted by FFmpeg’s own parser.
Check whether the source clips are compatible
The concat demuxer is best suited to files whose corresponding streams match. In practice, check that each clip has the same stream layout, codecs, and time bases. For example, a playlist where every file has one video stream and one audio stream in a consistent format is a better candidate than one mixing silent video, variable layouts, or different encoding parameters. Similar-looking pictures do not establish technical compatibility.
Inspect each source before assembling the list. FFmpeg’s ffprobe can report the streams, codecs, dimensions, frame rates, time bases, and durations, for example:
ffprobe -hide_banner -show_streams -show_format clip1.mp4
Repeat that check for each file rather than examining only the first. Note whether one clip has no audio, a different frame size, or a different frame rate. A channel owner who has exported clips over months may have more variation than expected, even if the files all end in .mp4.
If the streams do not match, normalise or re-encode the clips to a common format before concatenating, or use a filter-based workflow that can handle the required conversion. The FFmpeg project’s FAQ on concatenation distinguishes the concat demuxer, which can avoid re-encoding compatible inputs, from the concat filter, which is appropriate when the material must be re-encoded. These methods make different trade-offs: the demuxer is simpler when inputs already match, while filtering offers a route to standardise them but requires an encode and a more involved command.
Do not expect the playlist to provide fades, title cards, volume levelling, or other per-clip treatment. Prepare those edits in the source material or build them into a filter workflow. A direct sequence can be suitable for a bhajan rotation where clips are already prepared to end and begin cleanly; a sequence of lessons that needs a short title between topics needs that title built into the programme or handled by another editing step.
Check boundaries and duration metadata
A playlist can parse correctly and still produce an untidy join. The demuxer uses the previous file’s duration to schedule the next one. If duration metadata is inaccurate, a file is truncated, or audio and video tracks end at different times, the boundary can contain a gap, overlap, or other artefact. The duration directive can override a file duration when you know the correct value, but it is not a guesswork fix.
Listen and watch across every boundary in the actual ordered sequence. Pay particular attention to the end of each clip, the start of the next one, and the transition from the last listed clip back to the first. A file that plays properly by itself may reveal an audio tail, a black frame, or a timing issue when it follows another file. This is why testing the sequence matters more than assuming that compatible extensions or similar resolutions guarantee a clean loop.
If one clip has a longer audio track than video, or vice versa, decide how to handle that before broadcasting. Trim or re-encode the source, choose a deliberate filter workflow, or use the documented duration override only when you have a verified duration. Avoid hiding an unexplained timing problem with repeated command changes; identify which file boundary causes it first.
For a more detailed preflight on an individual video, use this guide to checking whether a video file is ready for a 24/7 YouTube stream. A file-level check is useful, but it does not replace a test of the complete playlist, because the joins and repeat point are part of what viewers will receive.
Configure looping and FFmpeg output
For a file-based live feed, -re paces the input at its native rate instead of reading it as quickly as storage permits. -stream_loop -1 asks FFmpeg to repeat the input indefinitely. Together with the concat demuxer, those options provide the basic shape for a repeated sequence sent through an output encoder.
ffmpeg -re -stream_loop -1 -f concat -safe 0 -i playlist.ffconcat \
-c:v libx264 -preset veryfast -pix_fmt yuv420p \
-r 30 -g 60 -b:v 4500k -maxrate 4500k -bufsize 9000k \
-c:a aac -b:a 128k -ar 44100 \
-f flv "$INGEST_URL/$STREAM_KEY"
This is an illustrative command, not a universal recommendation and not a report of a live test. The sample uses H.264 video, AAC audio and an FLV output container for an RTMP-style ingest. Its sample frame rate and rate-control values must be checked against your source, intended output, YouTube’s current encoder guidance, and the upload connection you can sustain. The source files are inputs to FFmpeg; they are not themselves the encoded live output. FFmpeg processes the input and produces the outgoing stream according to the output options.
The -g 60 value in the example corresponds to a two-second GOP at 30 frames per second. If you choose a different frame rate, adjust the GOP length to keep the keyframe interval appropriate. YouTube’s current guidance should take precedence over copying a command from an article, since its supported settings and bitrate recommendations can change. Choose a resolution and output rate that suit the material and a stable connection, rather than selecting a higher rate merely because the source file permits it.
The example also assumes that audio is available. If the source clips have no audio stream, those audio options do not create silence automatically. Add a deliberate silent-audio source or choose another audio plan that produces the output you intend, and test that the outgoing stream contains it. If the playlist mixes clips with and without audio, that is a compatibility warning to resolve before using the demuxer workflow.
For an always-on rotation, decide what should happen when FFmpeg stops or the machine restarts. A locally run process depends on the computer, power, network and process supervision remaining available. StreamNeo is useful when the specific pain is keeping your own computer on and restarting a dropped broadcast: it accepts the video and YouTube stream key so the loop can keep running without that machine being left on. It is YouTube-only, so it is not a replacement for this FFmpeg workflow when you need to shape a multi-file sequence or control encoding yourself.
Supply YouTube’s ingest URL and stream key
In YouTube Live Control Room, use the ingest details YouTube provides for the broadcast. The ingest URL identifies where the encoder sends the stream; the stream key identifies the stream associated with your channel setup. Keep the key private. Anyone with access to it may be able to send video to that ingest, so do not publish it in a script, screenshot, shared playlist, or public repository.
In the example, INGEST_URL and STREAM_KEY are placeholders, not literal values. Replace them with the current URL and key shown in your YouTube account. Keeping them as shell variables can reduce accidental copying into logs or shared command history, but the exact handling depends on how you launch FFmpeg. Do not paste a real key into a public troubleshooting forum; rotate it through YouTube if it is exposed.
Check that the selected ingest protocol and output muxer match. YouTube documents RTMP and RTMPS ingest, and recommends RTMPS for an encrypted connection. An FLV output is shown for the RTMP-style command shape above; use current YouTube and FFmpeg documentation to check the right combination if you change the protocol or output format.
YouTube’s Live Streaming API stream resource describes ingestion information and status fields, including health information. In ordinary use, the practical check is in Live Control Room: confirm YouTube receives the encoder, review the status and stream-health messages, and resolve warnings before you rely on a long run. The word “live” in the FFmpeg command does not mean YouTube has accepted or is displaying the feed.
Verify codec and bitrate requirements
YouTube’s live encoder settings page lists its current choices for video codecs, audio codecs, frame rates, keyframe interval and bitrate guidance. Check that page when you configure the stream rather than treating example values in a copied command as permanent limits. YouTube’s published bitrate recommendations vary by codec, resolution and frame rate.
The example uses H.264 and AAC, with stereo-oriented sample audio settings. YouTube’s advanced guidance lists 44.1 kHz and 128 kbps for stereo audio. Use those as settings to verify against the current official page and your material, not as a claim that every source should be encoded identically. If you select another supported video codec, confirm that the FFmpeg build you are using can encode it and that the entire output chain uses matching settings.
YouTube recommends a two-second keyframe interval and says not to exceed four seconds. With the sample’s 30 fps output, a GOP length of 60 frames gives a two-second interval. If you change -r, calculate the GOP for the chosen frame rate rather than leaving -g 60 unchanged by habit. Keyframe settings are an output-encoder concern; they do not alter the source clips or make their boundaries seamless.
The outgoing bitrate also has to be sustainable on the connection used by the encoder. Leave practical headroom for normal network variation and other household or office traffic. A bitrate warning is not always evidence that the source file is wrong; it may point to an unstable upload or output settings that are too demanding. For a local connection in India, these checks for YouTube bitrate warnings on Indian internet connections help separate encoder settings from connection problems.
A VPS changes where the process runs, not the underlying requirement for a compatible playlist and dependable upload path. If you are weighing that route, consider the VPS location factors for an FFmpeg YouTube stream alongside the audience and the machine’s network capability. Do not assume that physical proximity to viewers alone determines ingest quality.
Test playback and diagnose failures
Test the exact playlist, command, audio and output settings you intend to use. A short test should include representative motion and audio, not just a static frame or the first seconds of the first clip. Let it pass at least one join and the last-to-first repeat point, then watch the YouTube preview and inspect its health messages. YouTube recommends testing with audio and motion representative of the actual stream and monitoring stream health during the broadcast.
When FFmpeg fails before connecting, read the first relevant error and check in order: the playlist signature, file paths and working directory, safe-path handling, and whether every listed file can be opened. If it opens the list but reports stream or timestamp errors at a boundary, compare the streams and durations for the files on either side. Do not jump straight to -safe 0 for a codec or timing error; it only relaxes path checks.
If FFmpeg reports that no audio stream exists, verify every source and decide on a silent-audio or other audio plan. If the local output appears to run but YouTube does not receive it, recheck the current ingest URL, stream key, protocol and output format. If YouTube receives the stream but flags health, use the message to distinguish codec, bitrate, keyframe or connection issues. Keep the test private or unlisted as appropriate to your channel workflow while you check it.
Record the known-good playlist, FFmpeg command and output settings without recording the secret stream key in a shared document. That gives you a repeatable baseline if a later edit breaks the loop. For detailed command-line operation on Ubuntu, see the guide to creating a YouTube 24/7 stream with FFmpeg on Ubuntu in India; this concat workflow still requires its own compatibility and boundary checks.
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 the concat demuxer make unrelated clips compatible?
No. It reads listed files one after another and expects corresponding streams, codecs and time bases to match. If the clips differ, prepare a common format or use a filter-based workflow that can re-encode them.
Why must ffconcat version 1.0 be the first line?
That exact signature allows FFmpeg to recognise the playlist format automatically. A blank line, extra leading characters or a byte-order mark before it can prevent recognition, so save the file as plain text and check its opening bytes if detection fails.
Will -stream_loop -1 guarantee a seamless repeat?
No. It repeats the input indefinitely, but it does not add transitions or repair duration errors, mismatched streams, or rough clip endings. Test every boundary, including the join from the final file back to the first.
Is the playlist the video that YouTube receives?
No. The playlist describes the input sequence. FFmpeg reads that sequence, applies the configured output encoding and sends the resulting live stream to the ingest URL and stream key supplied by YouTube.