A 24/7 stream that does not reconnect between videos: one ffmpeg fed through a pipe

Video

A live channel that plays finished videos around the clock has two easy designs, and both drop something. Restarting ffmpeg for each video drops the RTMP connection at every switch. A concat playlist is read once at start, so a new video waits for the next restart.

The design

Each video is converted once into MPEG-TS at the stream's size and frame rate; a vertical video sits on a blurred copy of itself instead of black bars. One ffmpeg process reads MPEG-TS from its standard input and encodes at a constant bitrate with a keyframe every two seconds, as live ingest expects. A small feeder writes the prepared files into that pipe one after another, at real-time pace, choosing the next file at each switch: videos never played first, then the least recently played. ffmpeg's MPEG-TS reader sees that each file's timestamps start over and shifts them, so its output runs on without a break.

Detail one: pace from the first byte

Our first version started its clock when ffmpeg started. Preparing the first file took nine seconds, so the feeder thought it was nine seconds behind and sent them all at once. Starting the clock at the first byte written fixed it: a 53-second run produced 53 seconds of stream.

Detail two: the audio at the seam

At a switch, the next file's audio began 17 milliseconds before the previous file's audio ended. The encoder warned that its input went "backward in time" and the muxer patched a timestamp. Resampling with aresample=async=1:min_hard_comp=0.01:first_pts=0 trims or pads such overlaps before the encoder sees them. In a run of just over a minute with five switches, every audio and video timestamp in the received stream rose, and the stream decoded without a single error.

Detail three: some warnings are normal

Each file restarts its MPEG-TS counters and its clock, so ffmpeg reports "Packet corrupt" and "timestamp discontinuity" at every switch. Those lines are expected, and we keep them out of the log so that real errors stand out.

The watchdog

If ffmpeg exits or its progress stops for a minute, the stream restarts with growing pauses and sends a message after repeated failures. In our test we killed the encoder by hand; the stream was back seven seconds later, and a video added mid-run joined the rotation without a reconnect. A restart is a short reconnect, so set the YouTube broadcast to start automatically and not to stop automatically. The stream key is masked in every log line, ffmpeg's own included. Studio ships this live channel as a systemd service.

Updated: