From 04c02d9ced267a93ca7327fd213f2b33f3df6a6c Mon Sep 17 00:00:00 2001 From: dev-team Date: Fri, 23 Oct 2026 13:12:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=90=AF=E5=8A=A8=E9=BB=91=E5=B1=8F=20-?= =?UTF-8?q?=20=E9=9D=99=E6=AD=A2=E6=A1=8C=E9=9D=A2=E5=93=8D=E5=BA=94KeyFra?= =?UTF-8?q?meReq=20+=20=E9=A6=96=E5=B8=A7=E5=BC=BA=E5=88=B6IDR=20+=20?= =?UTF-8?q?=E5=85=A5=E4=BC=9A=E4=B8=BB=E5=8A=A8=E8=AF=B7=E6=B1=82=E5=85=B3?= =?UTF-8?q?=E9=94=AE=E5=B8=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agent/src/capture.rs | 11 +++++++---- viewer/src/main.rs | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/agent/src/capture.rs b/agent/src/capture.rs index e6daf81..9489495 100644 --- a/agent/src/capture.rs +++ b/agent/src/capture.rs @@ -236,7 +236,8 @@ impl NvencEncoder { /// 编码当前 GPU 纹理内容,返回 Annex B H.264 码流。 fn encode(&mut self, force_idr: bool, ts_ms: u64) -> Result> { - let ty = if force_idr { + // 首帧强制 IDR:解码端从任意时刻接入,没有 IDR 无法解出后续 P 帧 + let ty = if force_idr || self.frame_count == 0 { NVencPicType::IDR } else { NVencPicType::P @@ -441,12 +442,14 @@ pub fn run(tx: Sender>>, keyreq: Arc, congestion: Arc } Ok(false) => { // 桌面静止:低频重发(丢包后恢复 + 会话保活)。 - // NVENC 重编当前 GPU 帧(输出极小 P 帧);软编重发最后一帧副本。 + // 关键:KeyFrameReq 在桌面静止时也必须响应 —— 此前只在新帧路径 + // 消费该标志,桌面完全静止时解码端请求 IDR 永远得不到响应 → 黑屏。 + let force_key = keyreq.swap(false, Ordering::Relaxed); if last_sent.elapsed() > Duration::from_millis(500) { match &mut encoder { EncoderKind::Nvenc(enc) => { - // 重编当前 GPU 帧(内容未变,输出极小 P 帧) - let r = enc.encode(false, start.elapsed().as_millis() as u64); + // 重编当前 GPU 帧(内容未变,输出极小;force_key 时为 IDR) + let r = enc.encode(force_key, start.elapsed().as_millis() as u64); match r { Ok(payload) => emit!(payload), Err(e) => { diff --git a/viewer/src/main.rs b/viewer/src/main.rs index 36ba386..48873a0 100644 --- a/viewer/src/main.rs +++ b/viewer/src/main.rs @@ -360,6 +360,8 @@ fn session( let push = |tx: &tokio::sync::mpsc::UnboundedSender>, m: ControlMsg| { let _ = tx.send(common::encode_control(&m)); }; + // 入会立即请求 IDR:避免从 GOP 中间接入收到裸 P 帧解码失败导致启动黑屏 + push(&msg_tx, ControlMsg::KeyFrameReq); let mut window = Window::new( "mvp-remote v0.7-LowLatency (Esc 退出)",