Fix timestamp overflow causing stream corruption after ~71 minutes#398
Fix timestamp overflow causing stream corruption after ~71 minutes#398joshkautz wants to merge 1 commit into
Conversation
The video and audio timestamp counters use u32, which overflows after approximately 71 minutes of continuous streaming at 30fps (4,294,967,295 / (1,000,000 / 30) ≈ 4295 seconds ≈ 71.6 minutes). After overflow, timestamps wrap to zero causing GStreamer to interpret the discontinuity as a pipeline error, corrupting the stream. Change vid_ts and aud_ts from u32 to u64, which can represent over 584,000 years of continuous streaming. This makes long-running 24/7 streams reliable. Fixes the timestamp component of stream degradation reported in QuantumEntangledAndy#378.
|
Note: I made this change for my own use case (a 24/7 license plate recognition system that streams continuously). If the direction of this change doesn't align with where you want to take the project, feel free to close it — no hard feelings. Just figured it might be useful to others hitting similar long-running stream issues. |
Upstream PR QuantumEntangledAndy#398. u32 microsecond counters overflow at ~71 min at 30fps, causing GStreamer to interpret the wrap as a discontinuity and corrupt the stream. u64 can represent 584,000+ years. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add a section crediting @wafgo, @Maaggs, @fromagge, @lorek123, and @joshkautz for their unmerged upstream PRs (QuantumEntangledAndy#373, QuantumEntangledAndy#389, QuantumEntangledAndy#394, QuantumEntangledAndy#395, QuantumEntangledAndy#396, QuantumEntangledAndy#398, QuantumEntangledAndy#399, QuantumEntangledAndy#400) that were ported into this fork. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
Hit this today on two RLC-820A cameras going through neolink into Frigate. Stalls every 72m24s on both. The two cameras drifted 7s per cycle relative to each other, ending up 48s apart after 8 cycles. Two independent counters in neolink, not an external trigger. 72.4 vs the 71.6 in the PR took me a minute to reconcile. u32::MAX µs is 71m35s regardless of fps. My cameras are set to 25 fps but actually run at about 24.7, and 107374 frames at 24.7 fps is 72m24s. On Intel QSV, ffmpeg stalls for 25s at each wrap. Strace shows the writer thread blocked on a condvar for 24.76s. On VAAPI the decoder crashes every 2 min with "Failed to sync surface" and "hwdownload: -5". Rebuilt neolink with this patch, ran 9 hours, none of the 7 expected wraps fired. Happy to see it merged. |
Problem
The video and audio timestamp counters in
send_to_sourcesuseu32, which overflows after approximately 71 minutes of continuous streaming at 30fps:After overflow, timestamps wrap to zero. GStreamer interprets this as a discontinuity and corrupts or drops the stream. This makes Neolink unreliable for any use case requiring continuous streaming beyond ~1 hour (NVR recording, surveillance, home automation).
Fix
Change
vid_tsandaud_tsfromu32tou64. Au64microsecond counter can represent over 584,000 years of continuous streaming, effectively eliminating timestamp overflow as a failure mode.This is a minimal, targeted change — only the timestamp variables and their immediate usage are affected. No behavior change for streams shorter than 71 minutes.
Changes
src/rtsp/factory.rs: Changevid_ts/aud_tsdeclarations from0u32tou64src/rtsp/factory.rs: Updatesend_to_sourcessignature from&mut u32to&mut u64src/rtsp/factory.rs: UpdateMICROSECONDSconstant fromu32tou64as u64casts onDuration::from_microscalls