Skip to content

fix(CinematicRenderer): prevent slowed clips ending early with black frames (#855) - #858

Open
pei711 wants to merge 2 commits into
OpenMontageInc:mainfrom
pei711:fix/cinematic-renderer-playback-rate-trim-855
Open

pei711 wants to merge 2 commits into
OpenMontageInc:mainfrom
pei711:fix/cinematic-renderer-playback-rate-trim-855

Conversation

@pei711

@pei711 pei711 commented Oct 27, 2026

Copy link
Copy Markdown

Summary

Fixes an issue in CinematicRenderer.tsx where video clips rendered with playbackRate < 1 (slowed down) stop playback prematurely and display a black background for the remainder of the scene (#855).

Related issue

Closes #855

Changes

  • In remotion-composer/src/CinematicRenderer.tsx, omit trimAfter on <OffthreadVideo> when scene.playbackRate is customized (!= 1). Remotion's <OffthreadVideo> bounds its internal sequence by trimAfter in unscaled frames, which cuts off slowed clips early. The enclosing <Sequence> in CinematicRenderer already precisely bounds the scene duration to Math.round(scene.durationSeconds * FPS).
  • Added contract test test_cinematic_custom_playback_rate_omits_trim_after to tests/contracts/test_remotion_video_transition_contract.py.

Testing

  • Ran npx tsc --noEmit in remotion-composer to ensure clean TypeScript compilation.
  • Ran py_compile on core Python modules.
  • Ran pytest tests/contracts/test_remotion_video_transition_contract.py tests/tools/test_cinematic_remotion_adapter.py (12 passed).
  • Ran full contracts test suite pytest tests/contracts/ (1271 passed, 7 skipped).

Checklist

  • The change is focused on a single logical concern.
  • I ran the relevant tests locally (make test-contracts / make test) where applicable.
  • I updated docs/README if behavior or usage changed.
  • No unrelated files (build artifacts, local config) are included in the diff.

@pei711
pei711 requested a review from calesthio as a code owner October 27, 2026 00:58
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-27T00:59:49.751384Z
We couldn’t complete this review. Comment @codex review to try again.
4862c0e PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@calesthio calesthio left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for investigating the slowed-clip black tail. I verified the underlying issue in the pinned Remotion 4.0.484 source: its internal trim Sequence uses unscaled source frames, so this is a real problem. The proposed workaround still needs to preserve the caller's explicit source-out boundary.

[P2] Do not discard trimAfterSeconds for every non-1 playback rate. The enclosing Sequence only knows durationSeconds; it does not enforce the source trim. For a direct cinematic scene with trimBeforeSeconds=0, trimAfterSeconds=2, playbackRate=0.5 and durationSeconds=6, this change allows source frames after second 2 to render during the final two timeline seconds. With playbackRate=2 it similarly removes an explicit source bound even though the reported defect concerns slowed playback. Please reconcile the source interval and playback rate (or reject inconsistent scene duration) so the fix cannot show footage outside the selected cut. Add a behavior test with distinguishable source regions; the new source-string assertion only checks that the trim is omitted and cannot catch this regression.

Validation: 12 focused transition/adapter tests passed in an isolated worktree integrated with main 63d1087a; no full Remotion/browser render was run. Source semantics checked against https://raw.githubusercontent.com/remotion-dev/remotion/v4.0.484/packages/core/src/video/OffthreadVideo.tsx and https://www.remotion.dev/docs/timing .

…r's source-out

Remotion's OffthreadVideo enforces trimAfter through an internal
Sequence bounded by (trimAfter - trimBefore) timeline frames without
scaling for playbackRate. Dropping trimAfter for non-1 rates (the
previous workaround) let footage past the caller's explicit
trimAfterSeconds render; passing it through unscaled cut slowed
clips early. resolveTrimAfterFrames now scales the source interval
into timeline frames (trimBefore + interval / playbackRate), so the
bound expires exactly when playback reaches trimAfterSeconds at any
rate. Replaces the source-string omission contract test with one
covering the scaling behaviour for distinguishable source regions.
@pei711

pei711 commented Nov 11, 2026

Copy link
Copy Markdown
Author

Thanks for verifying the underlying Remotion behaviour and for the concrete counterexample. You were right: dropping trimAfter for every non-1 rate discarded the caller's explicit source-out.

Fixed in 7e61b47 by reconciling the source interval with the playback rate instead of dropping the trim:

  • New resolveTrimAfterFrames helper: trimAfter = trimBefore + (trimAfterSeconds - trimBeforeSeconds) * fps / playbackRate. Since Remotion's internal trim Sequence is bounded by (trimAfter - trimBefore) timeline frames, scaling the interval makes that bound expire exactly when playback reaches trimAfterSeconds.
  • Your example (trimBeforeSeconds=0, trimAfterSeconds=2, rate 0.5, 30fps): the resolved bound is 120 frames, so playback reaches source second 2 exactly at timeline frame 120 — footage past second 2 can no longer render in the final two seconds. At rate 2 the bound is 30 frames, again landing exactly on source second 2. At rate 1 the value is unchanged from the original pass-through.
  • The old source-string test (which only asserted the trim was omitted) is replaced by test_cinematic_trim_after_scales_source_interval_by_playback_rate, which pins the scaling behaviour using distinguishable source regions (0-1s / 1-2s / 2-3s) at both rates and asserts the trim is never dropped. It passes locally against the updated source, along with the existing fade-bound contract test.

@calesthio could you take another look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CinematicRenderer: clips with speed < 1 end early and leave the rest of the scene black

2 participants