diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index ebe2a4fc7..87655222f 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,3 +1,7 @@ +0.96.7 (unreleased) +------------------- +- Fix: Prevent crash in Rust timing module when logging out-of-range PTS/FTS timestamps from malformed streams. + 0.96.6 (2026-02-19) ------------------- - New: 32-bit (x86) Windows build and installer (#2116) diff --git a/src/rust/lib_ccxr/src/time/c_functions.rs b/src/rust/lib_ccxr/src/time/c_functions.rs index 1f3180eee..fe4c319af 100644 --- a/src/rust/lib_ccxr/src/time/c_functions.rs +++ b/src/rust/lib_ccxr/src/time/c_functions.rs @@ -29,7 +29,9 @@ pub fn get_fts_max(ctx: &mut TimingContext) -> Timestamp { /// Rust equivalent for `print_mstime_static` function in C. Uses Rust-native types as input and output. pub fn print_mstime_static(mstime: Timestamp, sep: char) -> String { - mstime.to_hms_millis_time(sep).unwrap() + mstime + .to_hms_millis_time(sep) + .unwrap_or_else(|_| "INVALID".to_string()) } /// Rust equivalent for `print_debug_timing` function in C. Uses Rust-native types as input and output. diff --git a/src/rust/lib_ccxr/src/time/timing.rs b/src/rust/lib_ccxr/src/time/timing.rs index c10e5da54..73bbfb106 100644 --- a/src/rust/lib_ccxr/src/time/timing.rs +++ b/src/rust/lib_ccxr/src/time/timing.rs @@ -151,8 +151,29 @@ impl TimingContext { if self.pts_set == PtsSet::No { self.pts_set = PtsSet::Received } - debug!(msg_type = DebugMessageFlag::VIDEO_STREAM; "PTS: {} ({:8})", self.current_pts.as_timestamp(timing_info.mpeg_clock_freq).to_hms_millis_time(':').unwrap(), self.current_pts.as_i64()); - debug!(msg_type = DebugMessageFlag::VIDEO_STREAM; " FTS: {} \n", self.fts_now.to_hms_millis_time(':').unwrap()); + let pts_string = self + .current_pts + .as_timestamp(timing_info.mpeg_clock_freq) + .to_hms_millis_time(':') + .unwrap_or_else(|_| "INVALID".to_string()); + + let fts_string = self + .fts_now + .to_hms_millis_time(':') + .unwrap_or_else(|_| "INVALID".to_string()); + + debug!( + msg_type = DebugMessageFlag::VIDEO_STREAM; + "PTS: {} ({:8})", + pts_string, + self.current_pts.as_i64() + ); + + debug!( + msg_type = DebugMessageFlag::VIDEO_STREAM; + " FTS: {} \n", + fts_string + ); // Check if PTS reset if self.current_pts < prev_pts { @@ -368,7 +389,7 @@ impl TimingContext { debug!( msg_type = DebugMessageFlag::TIME; "\nFirst sync time PTS: {} {:+}ms (time before this PTS)\n", - self.min_pts.as_timestamp(timing_info.mpeg_clock_freq).to_hms_millis_time(':').unwrap(), + self.min_pts.as_timestamp(timing_info.mpeg_clock_freq).to_hms_millis_time(':').unwrap_or_else(|_| "INVALID".to_string()), self.fts_offset.millis() ); debug!( @@ -411,7 +432,7 @@ impl TimingContext { debug!( msg_type = DebugMessageFlag::TIME; "\nNew min PTS time: {} {:+}ms (time before this PTS)\n", - self.min_pts.as_timestamp(timing_info.mpeg_clock_freq).to_hms_millis_time(':').unwrap(), + self.min_pts.as_timestamp(timing_info.mpeg_clock_freq).to_hms_millis_time(':').unwrap_or_else(|_| "INVALID".to_string()), self.fts_offset.millis() ); } @@ -506,11 +527,13 @@ impl TimingContext { self.sync_pts .as_timestamp(timing_info.mpeg_clock_freq) .to_hms_millis_time(':') - .unwrap() + .unwrap_or_else(|_| "INVALID".to_string()) ); info!( " GOP start FTS: {}\n", - gop_time.to_hms_millis_time(':').unwrap() + gop_time + .to_hms_millis_time(':') + .unwrap_or_else(|_| "INVALID".to_string()) ); // Length first GOP to last GOP @@ -521,14 +544,16 @@ impl TimingContext { info!( "Last FTS: {}", - self.get_fts_max().to_hms_millis_time(':').unwrap() + self.get_fts_max() + .to_hms_millis_time(':') + .unwrap_or_else(|_| "INVALID".to_string()) ); info!( " GOP start FTS: {}\n", timing_info .fts_at_gop_start .to_hms_millis_time(':') - .unwrap() + .unwrap_or_else(|_| "INVALID".to_string()) ); let one_frame = FrameCount::new(1).as_timestamp(timing_info.current_fps); @@ -538,10 +563,10 @@ impl TimingContext { "Max FTS diff. to PTS: {:6}ms GOP: {:6}ms\n\n", (self.get_fts_max() + one_frame - ptslenms) .to_hms_millis_time(':') - .unwrap(), + .unwrap_or_else(|_| "INVALID".to_string()), (self.get_fts_max() + one_frame - goplenms) .to_hms_millis_time(':') - .unwrap() + .unwrap_or_else(|_| "INVALID".to_string()) ); }