Burned-in subtitles are text rendered into the video picture by FFmpeg; they are not a YouTube live caption track. To stream a playlist this way, prepare compatible video and subtitle files, confirm your FFmpeg build includes libass, apply the subtitles filter before encoding, then send the resulting stream to YouTube Live.
Treat the commands below as examples, not a universal recipe. FFmpeg options vary with your operating system, build, media streams and chosen output settings, so test a representative section before relying on it for a scheduled broadcast.
Burned-in subtitles and YouTube live captions are different
FFmpeg’s subtitles video filter draws text onto each frame. Once encoded, that text is part of the image: viewers see it whenever that part of the video plays, and cannot turn it off or select it as a separate caption track. This can suit a lyric video, a language-specific devotional playlist, or a local news loop where the text should always be visible.
That is different from captions delivered to YouTube through its supported live-caption pathways. Those pathways can use captions embedded as EIA 608/CEA 708 or a supported software workflow that sends captions to YouTube. They are set up separately; rendering an SRT file with FFmpeg does not create a YouTube caption feed. YouTube documents the distinction in its live caption guidance.
| Approach | What viewers receive | Viewer control | What you must prepare |
|---|---|---|---|
| Burned-in subtitles | Text pixels in the video image | The text cannot be toggled off or selected as a caption track | A subtitle file and a video filter that renders it |
| YouTube live captions | A separate caption pathway, when configured and delivered correctly | Caption behaviour depends on YouTube’s supported setup | A compatible caption feed or embedded caption configuration |
Choose burned-in text when the wording should be visible to everyone and the video is the intended presentation. If viewers need selectable captions, or if a caption track is important to your accessibility plan, investigate YouTube’s caption setup rather than relying on text in the image. Neither approach automatically makes your content accurate: check the words, timing, language and current YouTube requirements yourself.
A useful distinction for a 24/7 station is that subtitles need to match the programme file being played. A fixed overlay can become misleading when the playlist advances to a different song or segment. If the playlist changes often, plan how each item’s timed text will be selected alongside its video, rather than assuming one subtitle file can follow every item.
Check whether your FFmpeg build supports libass
The filter depends on libass, and not every FFmpeg build includes it. The official FFmpeg filter documentation describes the subtitles filter as drawing subtitles over input video using the libass library. It also documents a build configured with --enable-libass, with libavcodec and libavformat support needed to convert subtitle input to ASS internally.
Check the FFmpeg executable that will actually run your stream. A computer can have more than one FFmpeg installation, so checking a different copy from the one used by a script or scheduled task can lead to a false sense of readiness. In a terminal or command prompt, run:
ffmpeg -filters
Look for a subtitles video filter in the output. Then inspect its local help:
ffmpeg -h filter=subtitles
The available options can differ by version and build. If the filter is absent, installing another subtitle font will not fix it; use a build that includes libass or choose a different workflow. The FFmpeg documentation index points out that the online documentation tracks the newest revision, so the local help is especially useful when your installed version is older.
You can also inspect the build configuration with ffmpeg -buildconf and look for --enable-libass. This is a useful check, but the practical test is whether the same executable exposes and can run the filter. Do not assume that a package named FFmpeg has the same set of features across operating systems or distributors.
If you are deciding between a local encoding setup and a cloud-run broadcast, compare the work involved rather than treating either as universally better. A local machine gives you direct access to files and tools, but it must remain powered, connected and available for the stream. For readers whose recurring problem is keeping their own computer on overnight, StreamNeo removes that particular burden by turning an uploaded video into a YouTube stream that can run with the computer switched off; subtitle preparation still needs to be done correctly before upload.
Prepare the playlist and subtitle files
Start by making a list of the exact media items and their corresponding subtitle files. Keep names simple and consistent, especially if the files will be read by a script. For example, morning-prayer.mp4 and morning-prayer.srt are easier to pair than names that rely on an undocumented ordering. Check that each subtitle file uses the expected language and encoding, and that its timing corresponds to the final edit of its video.
For a playlist assembled with FFmpeg’s concat demuxer, make a text file such as playlist.txt containing entries in playback order:
file 'part-01.mp4'
file 'part-02.mp4'
file 'part-03.mp4'
The concat demuxer presents the listed files sequentially, but its documentation warns that timestamp adjustment can produce gaps when streams do not have exactly the same duration. It also expects compatible streams. Consult the FFmpeg concat demuxer documentation and inspect your own files instead of assuming that two files with the same extension have identical stream layouts.
Use ffprobe to examine each item’s duration, video dimensions, frame rate, audio stream and subtitle streams. One possible inspection command is:
ffprobe -v error -show_streams -show_format part-01.mp4
This output is detailed, so focus first on whether every file has the expected video and audio, whether the dimensions and frame rates are consistent, and whether any subtitle track is already embedded. If the files differ, test the exact concatenation and output duration before setting up a live broadcast. A short gap, repeated frame or audio discontinuity at a join can be easy to miss when checking only the first item.
An external SRT file is often simpler to manage than selecting a subtitle stream already inside each media file. If your text is not UTF-8, the filter has a charenc option; check the local filter help and use the correct character encoding rather than trying random conversions. FFmpeg also has a stream_index option for selecting a subtitle stream from a media input. That is a different case from supplying a separate .srt file, so make the source explicit in your command.
If you already run a playlist through OBS, first decide whether FFmpeg will replace that playback path or only prepare the video files. The practical concerns around keeping a playlist moving are also covered in this guide to keeping OBS streaming when a video playlist ends. Whichever player you use, test what happens when one item ends, the next begins and the playlist reaches its final entry.
Apply the subtitles filter before encoding
A simple FFmpeg pattern applies subtitles to a video input and encodes the filtered frames. For one file with an external SRT, a basic example is:
ffmpeg -i input.mp4 -vf "subtitles=input.srt" -c:v libx264 -c:a aac output.mp4
This is a local file example, not a complete YouTube command and not a guarantee that the named codecs are available in your build. It shows the important order: FFmpeg reads the video, applies the video filter, then encodes the resulting frames. The subtitle text is therefore included in the picture, rather than carried as a separate caption track.
For a playlist, the same idea can be represented with the concat demuxer as input:
ffmpeg -f concat -safe 0 -i playlist.txt -vf "subtitles=all.srt" \
-c:v libx264 -c:a aac output.mp4
Here, all.srt is only appropriate if it contains timings aligned to the concatenated timeline. A subtitle file timed from zero for each individual clip will not automatically reset when the next clip starts. One long SRT must use timestamps that match the playlist’s continuous timeline, including the duration and any gaps at joins. Alternatively, process each video with its own matching subtitle file before combining the outputs, then verify the joins. Choose a strategy that fits your playlist rather than expecting FFmpeg to infer which text belongs to each clip.
File paths and quoting are shell-dependent. Spaces, punctuation, drive letters and non-ASCII characters can need different quoting or escaping on Windows, macOS and Linux. If FFmpeg reports that it cannot open a subtitle file, simplify the path for a test and check the filter’s local help for how that build parses filter options. Keep the stream key out of scripts that might be shared, logged or published.
The filter also supports style and font options. force_style can override selected ASS style properties, while fontsdir can point to a directory containing font files for rendering. If characters appear as empty boxes or an unexpected typeface, verify that the intended font is installed or available to the filter and that it includes the script’s characters. Indian-language text may need a font with the relevant glyphs and correctly encoded source text; confirm by rendering a local sample, not by guessing from the command line.
If the video’s aspect ratio or frame size has changed from the conditions under which the subtitle style was authored, check the filter’s original_size option. The FFmpeg documentation notes that it can matter for correct font scaling when the aspect ratio has changed. Make style adjustments on a representative clip and inspect the result at the final output resolution. Text that looks well-sized in a small preview can cover important parts of a phone-screen composition when it is broadcast at a different size.
Test rendering across every playlist file
Do not stop after seeing subtitles on the first clip. Render a short local sample from each source file, or make a temporary playlist that includes representative beginnings, joins and endings. Check that the right words appear over the right images, that the text is inside the safe viewing area, and that punctuation and line breaks remain legible. Review the audio as well: adding a video filter does not correct mismatched sound levels or timing at a playlist boundary.
For a long programme, prepare subtitles per item and note their time origin. If you combine files before filtering, calculate each item’s position in the combined timeline and shift its subtitle cues accordingly. This is particularly important where file duration differs from the duration suggested by a playlist editor, or where the concat demuxer’s timestamp handling adds a gap. FFmpeg’s concat documentation explains the timestamp caveat; your own playback test reveals whether that caveat affects this set of files.
Check the first and last subtitle cues in every item. A cue that starts before a file’s first visible frame may be cut off, and a late cue can extend into the next item if the end time is wrong. Watch the transition at normal speed, not only by scrubbing. A few seconds of apparently correct text at the start do not prove that a full song, news segment or study session remains synchronised.
If you need to repeat the playlist continuously, verify how the playlist-level repeat mechanism behaves with your installed FFmpeg version and input format. Do not mistake the loop filter’s documented one-frame example for a ready-made way to loop a whole playlist. Check the end-of-file behaviour, whether timestamps continue as expected, and whether your chosen method reopens inputs cleanly. Make a short test that reaches the end of the list before planning an overnight run.
For a continuous channel, playlist changes also need deliberate handling. A stream that remains connected while its media source changes is not the same as a stream that stops and starts for every item. If you routinely replace content during a broadcast, see the notes on switching playlists during an ongoing YouTube Live loop. For subtitle accuracy, the operational checklist should include updating the video and its matching timed text together.
Send the encoded stream to YouTube Live
When local rendering is correct, connect FFmpeg to the stream entry point shown in YouTube Live Control Room. YouTube generates a server URL and a stream key for the stream; copy the current values from the relevant stream settings rather than borrowing an old key from another broadcast. Keep the key private. Anyone with access to it may be able to send video to that stream.
A representative RTMPS command shape for an H.264/AAC output is:
ffmpeg -re -f concat -safe 0 -i playlist.txt \
-vf "subtitles=all.srt" \
-c:v libx264 -preset veryfast -b:v 8M -maxrate 8M -bufsize 16M \
-r 30 -g 60 -pix_fmt yuv420p -c:a aac -b:a 128k \
-f flv "rtmps://YOUR_SERVER_URL/YOUR_STREAM_KEY"
The URL is a placeholder. Do not paste a real key into a public post or a shared command. The example uses a 30 fps output and a two-second GOP as an illustration; bitrate, frame size, encoder availability, filter options and keyframe behaviour need to match the stream you intend to run and YouTube’s current requirements. It does not guarantee the input playlist, fonts or local FFmpeg build will work unchanged.
YouTube’s encoder settings guidance recommends RTMPS where available, CBR, and a two-second keyframe interval, with keyframes not exceeding four seconds. It lists H.264, H.265/HEVC and AV1 video support, as well as AAC or MP3 audio, and supports frame rates up to 60 fps. Check the current page before choosing settings because the supported options and recommendations may change.
For a concrete H.264 comparison, YouTube lists recommended ingestion bitrates of 8 Mbps for 720p at 30 or 60 fps, 14 Mbps for 1080p at 30 fps and 17 Mbps for 1080p at 60 fps on the page accessed in 2026. These are recommendations for the listed modes, not a promise of quality or a substitute for a stable upload connection. A higher output rate uses more upload capacity; choose resolution and frame rate your connection can sustain, and consult YouTube’s current table for the exact configuration.
Start with an unlisted or private test where appropriate, and include representative motion and sound rather than a static frame. Wait for the preview in Live Control Room, check the stream health indicators and listen for audio. A scheduled event may still require you to select “Go live” in the control room after the encoder connects. When the test ends, stop the encoder and end the stream in the control room as needed. For a longer run, keep a plan for what to do if the input reaches the end of its playlist or the connection drops.
Troubleshoot missing, garbled or misaligned text
If no subtitles appear, first confirm that the selected FFmpeg executable exposes the subtitles filter and that the subtitle path is correct. Run a short local encode and read the error output carefully. A missing libass filter, an unreadable file path and a malformed subtitle file are different problems; changing bitrate will not solve any of them.
If the text is absent only on particular items, check whether the playlist timeline and subtitle timeline match. An SRT file that begins at zero for one clip cannot be applied unchanged across a longer concatenated programme unless its timestamps have been adjusted. Confirm the exact join duration and inspect cues near the transition. Where media streams are not compatible, normalise or process the items separately before building the final playlist.
If letters are garbled or missing, check the subtitle character encoding and the font’s glyph coverage. Use charenc when the input is not UTF-8, as supported by the filter, and verify the font with the actual language and characters you will broadcast. If the file renders correctly on one computer but not the streaming machine, the two machines may have different fonts or FFmpeg builds.
If text is too small, too large or misplaced, inspect the final video dimensions and any prior scaling or aspect-ratio changes. Try a style override with force_style, or review whether original_size is relevant to the source-to-output change. Render and view a sample at the output size before going live; a preview window can scale the image and make placement look different from the eventual player.
If subtitles look correct locally but YouTube has no captions menu, that is expected for burned-in text. You have sent pixels in the video, not a caption feed. If you need a separate caption track, follow YouTube’s current live-caption setup, configure the supported delivery path, and test it independently from the rendered subtitle overlay.
Finally, if the stream health is poor, separate the cause from subtitle rendering. Check the encoder’s CPU load, upload stability, frame rate, bitrate and YouTube’s stream health messages. The subtitle filter adds video processing work, but a caption or path error should not be diagnosed as a network fault. You can also compare how live streaming differs from broadcasting when deciding whether your workflow should be a continuous live connection or a sequence of prepared broadcasts.
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
Do burned-in subtitles create YouTube live captions?
No. FFmpeg renders them into the video frames, so they are visible text in the picture rather than a YouTube caption track. For selectable live captions, set up and test a supported YouTube caption pathway separately.
Why does FFmpeg say the subtitles filter is unavailable?
The FFmpeg build you are using may not include libass support, or you may be invoking a different FFmpeg executable from the one you checked. Inspect ffmpeg -filters and the local filter help; if the filter is missing, use a build that includes it.
Can one SRT file cover a whole playlist?
Yes, if its cue times are aligned to the complete concatenated timeline. A file timed from zero for each individual video will not automatically restart at every playlist item, so test each join and adjust timings or process items separately.
Will the example command work unchanged on my computer?
Not necessarily. Paths, shell quoting, input streams, codecs, frame size, frame rate and FFmpeg build options vary. Treat it as a pattern, check your local documentation and settings, and make a short test stream before relying on it for a live event.