fix: v0.8.1 静止桌面黑屏 - 积压跳帧限定突发到达, 空闲重发帧不判陈旧不计E2E
This commit is contained in:
parent
8dd18a06a1
commit
ad022ffcf4
@ -256,6 +256,7 @@ fn session(
|
|||||||
let mut rgb_buf: Vec<u8> = Vec::new();
|
let mut rgb_buf: Vec<u8> = Vec::new();
|
||||||
let mut last_kfreq = Instant::now();
|
let mut last_kfreq = Instant::now();
|
||||||
let mut skip_stale = 0u64;
|
let mut skip_stale = 0u64;
|
||||||
|
let mut last_arr: Option<Instant> = None;
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut size_logged = false;
|
let mut size_logged = false;
|
||||||
loop {
|
loop {
|
||||||
@ -263,6 +264,12 @@ fn session(
|
|||||||
Ok((hdr, payload)) => {
|
Ok((hdr, payload)) => {
|
||||||
stats.bytes.fetch_add(payload.len() as u64, Ordering::Relaxed);
|
stats.bytes.fetch_add(payload.len() as u64, Ordering::Relaxed);
|
||||||
stats.frames.fetch_add(1, Ordering::Relaxed);
|
stats.frames.fetch_add(1, Ordering::Relaxed);
|
||||||
|
// 与上一帧的到达间隔:≤100ms 才算"突发到达"。
|
||||||
|
// 桌面静止时 agent 以 2Hz 空闲重发,帧龄天然 ≥500ms,
|
||||||
|
// 不能按陈旧帧丢弃——否则静止桌面所有帧被跳过 →
|
||||||
|
// 永久黑屏 + KeyFrameReq/IDR 死循环(v0.8 实测教训)
|
||||||
|
let burst = matches!(last_arr, Some(t) if t.elapsed() <= Duration::from_millis(100));
|
||||||
|
last_arr = Some(Instant::now());
|
||||||
// 端到端延迟 = 接收时刻 - 时钟偏移 - 采集时刻(EMA 平滑)
|
// 端到端延迟 = 接收时刻 - 时钟偏移 - 采集时刻(EMA 平滑)
|
||||||
let mut est = None;
|
let mut est = None;
|
||||||
let mut stale = false;
|
let mut stale = false;
|
||||||
@ -271,27 +278,30 @@ fn session(
|
|||||||
now_ms() as i64 - stats.offset.load(Ordering::Relaxed)
|
now_ms() as i64 - stats.offset.load(Ordering::Relaxed)
|
||||||
- hdr.ts_ms as i64;
|
- hdr.ts_ms as i64;
|
||||||
if (0..5000).contains(&e) {
|
if (0..5000).contains(&e) {
|
||||||
// 积压保护:QUIC 视频流可靠有序,积压必须逐帧读出,
|
// 积压判定必须同时满足:突发到达(背靠背)+ 帧龄>250ms。
|
||||||
// 但陈旧帧(>250ms)可以不解码——跳过解码让积压以
|
// QUIC 可靠有序,积压须逐帧读出但可不解码——跳过解码
|
||||||
// 网络速度排空,否则消化速率≈到达速率永远追不回来
|
// 让队列以网络速度排空
|
||||||
stale = e > 250;
|
stale = burst && e > 250;
|
||||||
let old = stats.e2e.load(Ordering::Relaxed) as i64;
|
// 空闲重发帧的帧龄不代表显示延迟,不计入 EMA
|
||||||
let sm = if stats.e2e_valid.load(Ordering::Relaxed) {
|
if burst || e < 250 {
|
||||||
(old * 4 + e) / 5
|
let old = stats.e2e.load(Ordering::Relaxed) as i64;
|
||||||
} else {
|
let sm = if stats.e2e_valid.load(Ordering::Relaxed) {
|
||||||
e
|
(old * 4 + e) / 5
|
||||||
};
|
} else {
|
||||||
stats.e2e.store(sm as u64, Ordering::Relaxed);
|
e
|
||||||
stats.e2e_valid.store(true, Ordering::Relaxed);
|
};
|
||||||
est = Some(sm);
|
stats.e2e.store(sm as u64, Ordering::Relaxed);
|
||||||
|
stats.e2e_valid.store(true, Ordering::Relaxed);
|
||||||
|
est = Some(sm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stats.on_frame_arrival(est);
|
stats.on_frame_arrival(est);
|
||||||
if stale {
|
if stale {
|
||||||
skip_stale += 1;
|
skip_stale += 1;
|
||||||
if skip_stale % 120 == 1 {
|
if skip_stale % 60 == 1 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[viewer] backlog: stale frame skipped (e2e>250ms, total {skip_stale})"
|
"[viewer] backlog: stale burst frame skipped (total {skip_stale})"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// 限频请求关键帧:积压排空后从 IDR 重新衔接画面
|
// 限频请求关键帧:积压排空后从 IDR 重新衔接画面
|
||||||
@ -392,7 +402,7 @@ fn session(
|
|||||||
push(&msg_tx, ControlMsg::KeyFrameReq);
|
push(&msg_tx, ControlMsg::KeyFrameReq);
|
||||||
|
|
||||||
let mut window = Window::new(
|
let mut window = Window::new(
|
||||||
"mvp-remote v0.8-CatchUp (Esc 退出)",
|
"mvp-remote v0.8.1-CatchUp (Esc 退出)",
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
WindowOptions {
|
WindowOptions {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user