fix: 修复 RTSP 功能对 VLC 视频播放器的兼容性 #237

This commit is contained in:
mofeng-git
2026-04-11 21:55:34 +08:00
parent 099f0b1ca2
commit 4952cbaf19

View File

@@ -498,6 +498,9 @@ async fn stream_video_interleaved(
let mut h265_payloader = H265Payloader::new();
let mut ctrl_read_buf = [0u8; RTSP_BUF_SIZE];
let mut ctrl_buffer = Vec::with_capacity(RTSP_BUF_SIZE);
// RTP timestamps must increase; pts_ms is often 0 for many frames (capture→encode jitter),
// which yields a flat RTP timestamp and breaks VLC/ffplay.
let mut last_rtp_timestamp: u32 = 0;
loop {
tokio::select! {
@@ -529,7 +532,11 @@ async fn stream_video_interleaved(
update_parameter_sets(&mut params, &frame);
}
let rtp_timestamp = pts_to_rtp_timestamp(frame.pts_ms);
let rtp_timestamp = monotonic_rtp_timestamp(
frame.pts_ms,
&mut last_rtp_timestamp,
frame.duration,
);
let payloads: Vec<Bytes> = match rtsp_codec {
RtspCodec::H264 => h264_payloader
@@ -1128,6 +1135,29 @@ fn pts_to_rtp_timestamp(pts_ms: i64) -> u32 {
((pts_ms as u64 * RTP_CLOCK_RATE as u64) / 1000) as u32
}
/// 90 kHz ticks per frame from nominal duration (at least 1).
fn rtp_timestamp_increment(frame_duration: Duration) -> u32 {
let inc = (frame_duration.as_secs_f64() * f64::from(RTP_CLOCK_RATE)).round() as u32;
inc.max(1)
}
/// Prefer PTS-based RTP time when it advances; otherwise step by `frame_duration` in 90 kHz units.
fn monotonic_rtp_timestamp(
pts_ms: i64,
last: &mut u32,
frame_duration: Duration,
) -> u32 {
let from_pts = pts_to_rtp_timestamp(pts_ms);
let inc = rtp_timestamp_increment(frame_duration);
let ts = if from_pts > *last {
from_pts
} else {
last.wrapping_add(inc)
};
*last = ts;
ts
}
fn generate_session_id() -> String {
let mut rng = rand::rng();
let value: u64 = rng.random();
@@ -1199,6 +1229,28 @@ mod tests {
assert_eq!(response.status(), rtsp::StatusCode::MethodNotAllowed);
}
#[test]
fn monotonic_rtp_timestamp_steps_when_pts_stays_zero() {
let d = Duration::from_millis(33);
let mut last = 0u32;
let a = monotonic_rtp_timestamp(0, &mut last, d);
let b = monotonic_rtp_timestamp(0, &mut last, d);
let c = monotonic_rtp_timestamp(0, &mut last, d);
assert!(a > 0);
assert!(b > a);
assert!(c > b);
}
#[test]
fn monotonic_rtp_timestamp_uses_pts_when_it_advances() {
let d = Duration::from_millis(33);
let mut last = 0u32;
let a = monotonic_rtp_timestamp(1000, &mut last, d);
assert_eq!(a, 90_000);
let b = monotonic_rtp_timestamp(2000, &mut last, d);
assert_eq!(b, 180_000);
}
#[test]
fn build_sdp_h264_is_parseable_with_expected_video_attributes() {
let config = RtspConfig::default();