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