Nodes/ComfyUI-OldTimeRadio/ Video Render Batch (A-S7.5 in-process render)
ComfyUI Node

Video Render Batch (A-S7.5 in-process render)

The renderer that turns a video plan into actual clips

By jbrick2070·Created 5 months ago·Updated about 20 hours ago· 7
Video Render Batch (A-S7.5 in-process render)
    • render_report_json
    • clip_manifest_json
    modesoak
    beats40
    oom_index20
    frame_count25
    engineviz_camera
    portrait_path
    audio_path
    patched_ledger_json{}
    master_audio_path
    image_done

    OTR_VideoRenderBatch is where the OldTimeRadio pipeline stops planning and starts burning GPU time. Everything upstream - the script, the voices, the frozen audio master, the per-role video policy from OTR_VideoDirector, the shot plan from OTR_ShotLock, the episode stills - has already happened. This node walks the engine registry and renders one real per-beat clip per shot, then hands the finished clips downstream to OTR_SilentComposite for assembly. It's the workhorse, and it's why this pack needs a GPU at all if you dial past the procedural floor.

    The one widget that matters is mode. episode is the production path - render a real episode from patched_ledger_json, the ShotLock-planned, image-genned ledger. soak and single are diagnostic harness modes for the author's own QA rig; most users will never touch them, and the widgets that look like they matter there (beats, oom_index, frame_count, engine) are only read in those modes. In episode mode they're inert - the beat count and frame budget come from the planned ledger, not your widgets. So when you're looking at this node in a real workflow, set mode to episode and leave the rest alone.

    Wiring, for when you're building the graph by hand rather than loading the canonical workflow:

    • patched_ledger_json - the ShotLock-planned ledger. Non-negotiable in episode mode.
    • master_audio_path - path to the frozen master mix from OTR_EpisodeAssembler.output_path. Beats that lack their own per-line audio get it sliced from this file, read-only, by ffmpeg. The master is never mutated. Leave it unset and the node degrades loudly on missing audio.
    • image_done - an ordering gate from OTR_ImageGenDispatcher.image_done. Consuming that opaque token forces the image phase (every episode still on disk) to finish before video rendering starts. It's never parsed - just a handshake.

    It returns render_report_json (a structured report of what each engine delivered) and clip_manifest_json (the beat-ordered manifest that feeds OTR_SilentComposite). It's an output node, so it can sit at the end of a render-gate workflow with nothing wired downstream and still run.

    The mechanism is the interesting part. This node must run inside ComfyUI's executor thread (a normal /prompt queue) rather than a background route - only there does ComfyUI's model_management evict the umt5/whisper encoders between encode and sample, which is what keeps the heavy in-process forward under the VRAM ceiling. It holds a single resident engine at a time, and any per-beat detach/reclaim happens inside the selected engine wrapper. The frozen audio section stays read-only the whole time. That "one engine resident, explicit reclaim" discipline is the same philosophy as the rest of the pack: no surprises, and when an engine OOMs or a model is missing, it stops with a named error rather than quietly swapping in something else.

    Two troubleshooting notes worth keeping. First, install via ComfyUI Manager ("ComfyUI-OldTimeRadio") or clone from GitHub into custom_nodes/, check out v2.0-alpha, restart - then place the Stable Audio / voice / image weights yourself, because nothing auto-downloads and a missing weight fails this node loudly. Second, if you're experimenting: mode=soak with oom_index set will inject a simulated OOM at a chosen beat index to test the fallback trail - it's a genuinely nice diagnostic, but it's for understanding failure behavior, not for making episodes. And know the pack's honest known limitation going in: occasionally an episode hands a line to the wrong character, and nothing fixes that. The render still completes; it just isn't perfect.

    CategoryOldTimeRadio/v2/video

    Inputs (10)

    NameTypeDefaultDescription
    modeCOMBOsoakRun mode. 'episode' is the production path (renders one REAL per-beat clip per shot from patched_ledger_json). 'soak' and 'single' are diagnostic harness modes -- some widgets below are read ONLY in a specific mode (see engine / oom_index).
    beatsINT401–400Diagnostic harness only (mode=soak): synthetic beat count. Ignored in mode=episode (beats come from the planned ledger).
    oom_indexINT200–399Diagnostic harness only -- read ONLY in mode=soak (the beat index at which to inject a simulated OOM for fallback-trail testing). Inert in mode=single and mode=episode.
    frame_countINT251–240Diagnostic harness only: per-clip frame count, consumed by mode=single AND mode=soak. Ignored in mode=episode (the per-shot frame budget is planned upstream).
    engineoptSTRINGviz_cameraDiagnostic harness only -- read ONLY in mode=single (forces the single engine to render). Inert in mode=soak and mode=episode (episode routes each beat by its planned per-role engine).
    portrait_pathoptSTRINGDiagnostic harness only (mode=single and mode=soak): conditioning still for the harness render. Inert in mode=episode, where each beat's still comes from the planned ledger.
    audio_pathoptSTRINGDiagnostic harness only (mode=single and mode=soak): driving audio for the harness render. Inert in mode=episode, where per-beat audio comes from the episode's own clips.
    patched_ledger_jsonoptSTRING{}mode=episode: the OTR_ShotLock-planned (and image-genned) ledger JSON. run_real_episode renders one REAL per-beat clip per shot; the emitted clip manifest feeds OTR_SilentComposite.
    master_audio_pathoptSTRINGmode=episode: path to the FROZEN master mix (MP4 or WAV). Beats whose ledger line has no per-line *_wav_path get audio_ref filled by slicing [start_s, start_s+dur_s] from this file (read-only ffmpeg; master is NEVER mutated). Wire from OTR_EpisodeAssembler.output_path (the frozen master WAV). Leave unset to degrade LOUD on missing per-line wavs.
    image_doneoptSTRINGImage-done gate (mirrors audio_done; ST-0.2 still-spine). Wire from OTR_ImageGenDispatcher.image_done so the video render cannot start before every episode still exists on disk (W4). Opaque STRING; the token is never parsed.

    Outputs (2)

    NameTypeDescription
    render_report_jsonSTRING
    clip_manifest_jsonSTRING