Skip to content

remotion_caption_burn: Remotion path fails 'No frame found at position 5546'; TalkingHead has hardcoded 9000-frame duration #433

Description

@srikanthapril19-code

Summary

remotion_caption_burn fails on its Remotion path (the animated per-word caption renderer) with a compositor error, falling back to plain FFmpeg captions only if the caller passes force_ffmpeg: True. On a normal call it errors out:

Compositor error: No frame found at position 5546 for source <...>/clip_with_audio.mp4

The failure is deterministic and input-independent: I hit the identical position 5546 on two different source files — an 8.3 s clip muxed with -c:v copy, and a clean re-encode of the same clip (H.264, keyframe every frame, 205 frames). Because both are ~8.3 s but produce the same errant position, 5546 cannot be derived from the input duration — it points at the composition/tooling, not the video.

Operating system

Windows 11, Python 3.12, Remotion 4.0.484, Node 24

Pipeline

Caption burn-in (remotion_caption_burn), Remotion path (no force_ffmpeg)

Runtime / renderer

remotion

Steps to reproduce

  1. Take any short clip (~8 s) with an audio track.

  2. Transcribe it with transcriber to get word-level segments.

  3. Burn captions without force_ffmpeg:

    registry.get("remotion_caption_burn").execute({
        "input_path": "clip_with_audio.mp4",
        "output_path": "out.mp4",
        "segments": segments,
        "words_per_page": 3,
        "font_size": 64,
    })

Expected behavior

An MP4 with animated per-word captions burned in.

Actual behavior

The npx remotion render TalkingHead subprocess aborts with Compositor error: No frame found at position 5546. No output file is produced. force_ffmpeg: True works but renders static centred captions, losing the animated per-word highlight that is the point of the Remotion path.

Relevant logs or error output

Could not extract frame from compositor Error: Compositor error:
  No frame found at position 5546 for source <tmp>/remotion-assets-dir/<hash>.mp4
  (original source = http://localhost:3000/public/talking-head/clip_with_audio.mp4)
tools.base_tool.ToolCommandError: Command '[... 'remotion','render','TalkingHead',
  '--props=public/demo-props/caption-burn-clip_with_audio.json',
  '--width=1920','--height=1080','--fps=30','--frames=0-249', ...]' returned non-zero exit status 1

Investigation / prime suspect

TalkingHead is registered very differently from its siblings in remotion-composer/src/Root.tsx:

// Root.tsx (~L179)
<Composition
  id="TalkingHead"
  component={TalkingHead}
  durationInFrames={30 * 300}   // hardcoded 9000 frames (5 min), no calculateMetadata
  fps={30}
  width={1080}                  // declared PORTRAIT...
  height={1920}
  ...
/>

Two things stand out versus Explainer / TitledVideo, which both derive duration from content via a calculateMetadata (e.g. durationInFrames: Math.ceil((lastEnd + 1) * 30)):

  1. durationInFrames is a fixed 30 * 300 (9000 frames) rather than computed from the clip. The Python side does clamp the render with --frames=0-{ceil(duration*30)-1} (tools/video/remotion_caption_burn.py ~L291/L335), and that math is correct for an 8 s clip (0-249) — but <OffthreadVideo src={videoSrc}> in TalkingHead.tsx (~L320) has no explicit bounds, so the composition's own 9000-frame length may still drive a source seek beyond the clip.

  2. Declared dimensions are portrait (1080×1920) but the tool overrides to landscape via --width/--height. Likely unrelated to the seek error, but it means the registered composition never matches the actual render and is worth aligning in the same pass.

Honesty caveat: I could not fully derive why the position is exactly 5546 — I confirmed it is not input-duration-derived (identical across two different-encoding files of the same length) and that the Python frame clamp itself is correct, but I did not trace 5546 to a specific line. The hardcoded 9000-frame duration with no calculateMetadata is the strongest candidate, not a proven root cause.

Suggested fix

Give TalkingHead a calculateMetadata that sets durationInFrames from the actual video (as Explainer/TitledVideo already do), and align its default width/height with how the tool renders it — or have the tool pass dimensions/duration the composition trusts. Happy to test a patch against this exact repro (Remotion 4.0.484).

Reminder for triage, matching a pattern in #431/#432: remotion_caption_burn reports available whenever Remotion is installed, so this only surfaces at call time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions