π₯ Burn Subtitle
Permanent, styled subtitles baked into the pixels β no player toggle involved
- frames
- audio
- final_video_path
MF_BurnSubtitle hard-burns an SRT subtitle file into a video - the words become part of the image, which is exactly what you want for a YouTube upload or a social clip where you can't trust the viewer's player to render captions. It's a thin FFmpeg wrapper under the hood, but the node's real value is that it gives you full ASS-level subtitle styling without you ever writing an ASS file: font, color, outline, shadow, alignment, margins - all as friendly widgets.
This is the one-shot burner. If you're also adding a watermark or BGM, MF_ComposeBurnSubtitle folds the same job into the Compose single-encode pipeline instead. For "I have a video and an SRT, make it one file," this is the simpler node.
How it works
Feed it a video and an SRT, and it runs FFmpeg's subtitles filter with a generated ASS style (your hex colors get converted to ASS's BGR-with-alpha internally, so don't panic when the numbers look "wrong" in a debug print). The frontend picks up .ttf / .otf / .ttc files from the plugin's font/ directory for the font dropdown, and fontTools reads the actual family name out of each file - so drop msjh.ttc in there and it shows up as its proper name. Output follows the pack's standard pattern: output/<filename_prefix>_NNNNN.mp4 with an auto-counter, so repeated runs never clobber each other.
The inputs that matter
video_pathandsrt_path- the obvious two. SRT should be UTF-8.font_size,font_color_hex,outline_width- the three knobs you'll actually touch.#RRGGBBhex for colors.outline_width=2with a black outline is the read-on-any-background baseline.alignment- nine named positions in numpad layout.bottom_center (2)is the sane default.border_style-1is outline+shadow,3is an opaque box behind the text (back_color_hexcontrols the box). The box style is how you survive badly compressed footage.codec/crf/preset- same encoder family as the rest of the pack. Default is the smart pick:h264_nvencif ffmpeg sees your NVIDIA card, libx264 otherwise.crfisn't unit-for-unit comparable across codec families - treat it as a starting point, not a law.
The interesting optional inputs are the dual-input ones. Wire frames (IMAGE) + tensor_fps + audio from MF_LoadVideoFrames, VHS, or AnimateDiff and the video_path widget hides - the node stages your tensor to a temp file and burns onto that. Or wire srt_text (a STRING) from MF_WhisperTranscribe / MF_TranslateSubtitle and skip the SRT file entirely. keep_source_audio (default on) amixes an external audio pin with the source's own track instead of replacing it.
Output is final_video_path - a STRING, wire it anywhere the pack's file consumers can use it.
Install
Same as the pack - this isn't a separate package:
cd ComfyUI/custom_nodes
git clone https://github.com/leon80148/comfyui_MediaForge.git
# restart ComfyUI
ComfyUI Manager works too: search "MediaForge". The pack's requirements.txt pulls fontTools and the ffmpeg fallback binaries automatically; system ffmpeg is preferred but not required.
Common issues
Font dropdown empty? You haven't put any fonts in <plugin>/font/. Grab msjh.ttc (the readme's default) or any TTF. Filenames containing [ ] ' , ; or : in the path can break the FFmpeg filter graph - the pack escapes these automatically, but if you hand-craft paths with weird characters and hit a filter syntax error, that's what's going on. And if you get a bare RuntimeError: ffmpeg ... failed, scroll up in the console: the last 30 lines of FFmpeg's stderr are printed before the error, and it's usually a bad path, not a codec problem.
Inputs (27)
| Name | Type | Default | Description |
|---|---|---|---|
| video_path | STRING | input/sample.mp4 | β |
| srt_path | STRING | input/sample.srt | β |
| filename_prefix | STRING | MediaForge/subtitled | β |
| codec | COMBO | h264 NVIDIA GPU (h264_nvenc) | 7 options: h264 (libx264), hevc (libx265), av1 (libsvtav1), prores (prores_ks), h264 NVIDIA GPU (h264_nvenc), hevc NVIDIA GPU (hevc_nvenc), +1 |
| crf | INT | 180β51 | β |
| preset | COMBO | medium | 9 options: ultrafast, superfast, veryfast, faster, fast, medium, +3 |
| font | COMBO | (ζ .ttf / .otf / .ttc δΈι² plugin/font/ εΎιζ°ζ΄η) | 1 options: (ζ .ttf / .otf / .ttc δΈι² plugin/font/ εΎιζ°ζ΄η) |
| font_size | INT | 248β150 | β |
| font_color_hex | STRING | #FFFFFF | β |
| bold | BOOLEAN | true | β |
| italic | BOOLEAN | false | β |
| letter_spacing | FLOAT | 0.00β20 | β |
| outline_color_hex | STRING | #000000 | β |
| outline_width | INT | 20β10 | β |
| shadow_depth | INT | 10β10 | β |
| border_style | INT | 11β3 | β |
| back_color_hex | STRING | #000000 | β |
| alignment | COMBO | bottom_center (2) | 9 options: bottom_left (1), bottom_center (2), bottom_right (3), middle_left (4), middle_center (5), middle_right (6), +3 |
| margin_v | INT | 200β500 | β |
| margin_l | INT | 500β1000 | β |
| margin_r | INT | 500β1000 | β |
| framesopt | IMAGE | β | |
| tensor_fpsopt | FLOAT | 30.01β240 | β |
| audioopt | AUDIO | β | |
| keep_source_audioopt | BOOLEAN | true | β |
| target_fpsopt | FLOAT | 0.00β240 | β |
| srt_textopt | STRING | β |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| final_video_path | STRING | β |