Skip to content

fix(enc-ffmpeg): use encoder_time_base in H264PacketEncoder to fix 4-8x playback speed#1970

Merged
richiemcilroy merged 1 commit into
CapSoftware:mainfrom
ManthanNimodiya:fix/enc-ffmpeg-h264-pts-timbase
Jul 2, 2026
Merged

fix(enc-ffmpeg): use encoder_time_base in H264PacketEncoder to fix 4-8x playback speed#1970
richiemcilroy merged 1 commit into
CapSoftware:mainfrom
ManthanNimodiya:fix/enc-ffmpeg-h264-pts-timbase

Conversation

@ManthanNimodiya

@ManthanNimodiya ManthanNimodiya commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

H264PacketEncoder.update_pts was computing PTS using the FFmpeg encoder's time_base after avcodec_open2.

h264_videotoolbox can override this value after opening, but the cap-muxer subprocess is always initialised with the stored encoder_time_base (= input_config.time_base).
When these diverge, the muxer rescales PTS against the wrong base and the video plays back at the wrong speed, reported as 4-8x too fast in v0.5.3 on macOS.

Fix: use the stored encoder_time_base and frame_rate (the values already sent to cap-muxer via InitVideo) instead of reading them back from the post-open encoder object, which may have been modified by the codec.

Greptile Summary

This PR fixes a 4-8x playback speed regression on macOS by correcting how PTS values are computed in H264PacketEncoder::update_pts. The root cause is that h264_videotoolbox can change the codec's time_base after avcodec_open2, diverging from the encoder_time_base already sent to cap-muxer via InitVideo, causing the muxer to rescale PTS with the wrong denominator.

  • Replaces both self.encoder.time_base() and self.encoder.frame_rate() calls in update_pts with the stored self.encoder_time_base and self.frame_rate fields, which are the exact values the muxer subprocess was initialized with.
  • Hoists let tb = self.encoder_time_base before the if/else branches so both the normal-timestamp path and the fallback frame.pts() path use the same consistent base.

Confidence Score: 5/5

Minimal, targeted fix that eliminates a time-base mismatch between the encoder and muxer; all three changed call sites are consistently updated.

The change is a one-function, three-site substitution of two struct field reads for two post-open encoder accessor calls. Both fields were already populated at construction with the values sent to cap-muxer, and the public time_base() / frame_rate() accessors already returned them. The fix is internally consistent, well-commented, and accompanied by existing unit tests that cover the encode path.

No files require special attention.

Important Files Changed

Filename Overview
crates/enc-ffmpeg/src/video/h264_packet.rs update_pts now reads encoder_time_base and frame_rate from stored struct fields instead of the post-open encoder object, preventing PTS miscalculation when h264_videotoolbox overrides the codec time_base after avcodec_open2

Reviews (1): Last reviewed commit: "fix(enc-ffmpeg): use encoder_time_base i..." | Re-trigger Greptile

let tb = self.encoder_time_base;
if timestamp != Duration::MAX {
let tb = self.encoder.time_base();
let rate = tb.denominator() as f64 / tb.numerator() as f64;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

tb is now coming from config (vs the post-open codec), so it might be worth guarding against an invalid/zero Rational here — otherwise rate can become inf/NaN and the float->int cast can silently produce huge PTS.

Suggested change
let rate = tb.denominator() as f64 / tb.numerator() as f64;
debug_assert!(
tb.numerator() > 0 && tb.denominator() > 0,
"invalid encoder_time_base"
);
let rate = tb.denominator() as f64 / tb.numerator() as f64;

@richiemcilroy richiemcilroy merged commit 7cec17d into CapSoftware:main Jul 2, 2026
12 of 17 checks passed
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.

2 participants