From ffb36b7e0d1a87d02186e83382c1902809df02e2 Mon Sep 17 00:00:00 2001 From: dailz Date: Fri, 22 May 2026 13:05:53 +0800 Subject: [PATCH] fix(portal): convert PipeWire nanosecond PTS to encoder frame-number units PipeWire spa_meta_header.pts is CLOCK_MONOTONIC in nanoseconds, but the encoder expects frame-number units (time_base = 1/fps). The raw nanosecond value was assigned directly to AVFrame.pts, causing the encoder/muxer to interpret timestamps as billions of frames, producing corrupted duration metadata and broken rate control. Fix: record the first frame's PTS as a nanosecond base, compute elapsed nanoseconds for each subsequent frame, then convert to frame numbers via elapsed_ns * fps / 1_000_000_000. Using elapsed time avoids i64 overflow on absolute timestamps (~10^18 ns). Matches the WLR path pattern (state.rs:525-527) which converts microseconds to frame numbers for the same encoder. --- src/state_portal.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/state_portal.rs b/src/state_portal.rs index f11fc4e..21e28af 100644 --- a/src/state_portal.rs +++ b/src/state_portal.rs @@ -25,6 +25,7 @@ pub struct StatePortal { errored: bool, first_frame: bool, drm_device: PathBuf, + first_pts_ns: Option, } impl StatePortal { @@ -43,6 +44,7 @@ impl StatePortal { errored: false, first_frame: true, drm_device, + first_pts_ns: None, }) } @@ -174,9 +176,16 @@ impl StatePortal { bail!("av_hwframe_transfer_data failed: error {ret}"); } - // 7. Set PTS + // 7. Set PTS — convert PipeWire nanoseconds to encoder frame-number units + // PipeWire PTS is CLOCK_MONOTONIC in nanoseconds. + // Encoder time_base = 1/fps, so PTS must be in frame numbers. + // Use elapsed time since first frame to avoid i64 overflow on absolute timestamps. + let fps_i64 = self.args.fps as i64; + let base_ns = *self.first_pts_ns.get_or_insert(frame.pts.max(0)); + let elapsed_ns = (frame.pts.max(0) - base_ns).max(0); + let pts = elapsed_ns * fps_i64 / 1_000_000_000; unsafe { - (*hw_frame.as_mut_ptr()).pts = frame.pts; + (*hw_frame.as_mut_ptr()).pts = pts; } // 8. Encode