Subtitle Burn-In
Hardcode your SRTs without leaving ComfyUI
- video
- video
- output_path
- summary
Subtitles are great until the platform strips them. If you've ever uploaded a clean video and watched the captions vanish, you know why "burning in" - drawing the text onto the pixels themselves - exists. MKRSubtitleBurnIn does exactly that, inside the graph: give it a video and an SRT, and it re-encodes every frame with the subtitles painted on, at your font size, position, and colors.
The mechanism is refreshingly boring. It decodes the video to frames, parses the SRT into timed cues, then for each frame works out which cues are active at that timestamp and draws them with PIL - multiline, centered, with a stroke for readability. Frames with no active cue pass through untouched. Then it re-encodes to your chosen format. It's the same thing you'd do with an ffmpeg filter, but exposed as a node with previewable inputs.
The inputs
- video (any type) - an MKR_VIDEO payload or a path it can decode.
- subtitles_path OR subtitles_srt - the SRT from a file, or pasted directly into the text box. You can use either; if both are set, the path wins.
- font_size, position (bottom/center/top), y_margin - text size and placement. Default 42px at the bottom, 64px margin.
- text_color, stroke_color, stroke_width - white text with a 3px black stroke is the default and it's a good one; the stroke is what keeps subs readable on bright frames.
- fallback_fps - used if the video's own fps can't be read.
- output_format -
auto,gif,webp,mp4,mov,webm. mp4/mov/webm need ffmpeg on the system; if it's missing the node falls back to gif.
What comes out
video (MKR_VIDEO), output_path (where it landed), and summary (with cue_count and any warnings, e.g. "No subtitle cues found").
Installing it
Part of criskb/MKRShift_Nodes from Cris K B. ComfyUI Manager search "MKRShift_Nodes", or:
cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes
Restart. The README is explicit: install ffmpeg if you plan to use the video/audio export nodes - this is one of them. No pip requirements otherwise.
The gotchas
SRT parsing is forgiving but not infinite - malformed cue times get skipped, and if nothing parses you'll get a clean run with cue_count: 0 and no subtitles, so check the summary. Timing is driven by the video's fps or fallback_fps, so a wrong fallback drifts sub sync on videos whose fps you couldn't read. And it re-encodes, so source quality and output format both matter: pick a sensible bitrate format (mp4/mov) for delivery, gif/webp only for previews.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| video | * | — | |
| subtitles_path | STRING | — | |
| subtitles_srt | STRING | — | |
| font_size | INT | 428–256 | — |
| position | COMBO | bottom | 3 options: bottom, center, top |
| y_margin | INT | 640–1024 | — |
| text_color | STRING | #FFFFFF | — |
| stroke_color | STRING | #000000 | — |
| stroke_width | INT | 30–20 | — |
| fallback_fps | FLOAT | 24.01–240 | — |
| output_format | COMBO | auto | 6 options: auto, gif, webp, mp4, mov, webm |
| filename_prefix | STRING | MKR_sub_burnin | — |
| subfolder | STRING | — | |
| overwrite | BOOLEAN | false | — |
| filename_labelopt | STRING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| video | MKR_VIDEO | — |
| output_path | STRING | — |
| summary | STRING | — |