Skip to content

feat(publish): enforce EncoderConfig.frameRate for video#1656

Merged
kixelated merged 1 commit into
mainfrom
claude/bold-johnson-b512d4
Jun 8, 2026
Merged

feat(publish): enforce EncoderConfig.frameRate for video#1656
kixelated merged 1 commit into
mainfrom
claude/bold-johnson-b512d4

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Summary

EncoderConfig.frameRate was accepted but never enforced for video. The encoder always used the captured track's frame rate for the bitrate calculation and the VideoEncoderConfig, and the encode loop had no frame dropping. This wires the config value through and actually paces the output to hit the target rate.

Changes

  • #runConfig now prefers config.frameRate over the captured track's rate (user.frameRate ?? settings.frameRate ?? 30). That single value already feeds the bitrate calculation (framerateFactor), the VideoEncoderConfig.framerate, and the catalog framerate/jitter.
  • Encode loop now drops frames to pace to the target: a frame is skipped if its timestamp falls within the minimum interval (1 / frameRate) since the last encoded frame. A half-interval of slack keeps the cadence stable against capture-timestamp jitter (e.g. 60→30fps cleanly keeps every other frame).
  • Doc comment on frameRate replaces the old // TODO actually enforce this.

Reviewer notes

  • Dropped frames are deliberately not close()d here. The frame is a shared Signal consumed by both the hd and sd encoders, and the owner in js/publish/src/video/index.ts closes each frame when the next one arrives. Closing inside one encoder would break the other and double-free.
  • frameRate is read non-reactively via this.config.peek() per frame, matching the existing keyframeInterval handling.

Test plan

  • Publish with config.frameRate set below the capture rate; confirm output framerate matches the target and catalog reports it.
  • Publish without frameRate; confirm behavior is unchanged (captured rate used, no dropping).

(Written by Claude)

frameRate was accepted but ignored: the encoder always used the captured
track's rate for the bitrate calc and VideoEncoderConfig, and the encode
loop had no frame dropping.

Now when config.frameRate is set:
- #runConfig prefers it over the captured rate, feeding both the bitrate
  calculation and the encoder/catalog framerate.
- The encode loop paces to the target by dropping frames whose timestamp
  falls within the minimum interval since the last encoded frame. A half
  interval of slack keeps the cadence stable against capture jitter.

Dropped frames are not closed here: the frame is a shared Signal consumed
by both the hd and sd encoders, and the owner closes each frame when the
next arrives.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kixelated kixelated merged commit 90200a5 into main Jun 8, 2026
1 check passed
@kixelated kixelated deleted the claude/bold-johnson-b512d4 branch June 8, 2026 20:37
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.

1 participant