# -*- coding: utf-8 -*- """加"心跳帧":画面没变也要定期发一帧。 问题(我自己引入的): 为了省流量,我给抓屏加了"画面没变就不编码、不发送"的去重。 但这样在**静止桌面**上会一帧都不发 —— 客户端不知道流还活着,测试里"收到至少 3 帧镜像"也会失败。 顺带还有别的影响:某些播放器/解码路径长时间没数据会超时。 修法: 画面没变时**不要一直不发**,而是每隔一段时间(默认 1.5 秒) 强制编码发一帧当心跳。既省了绝大部分流量(静止时 12fps -> 0.67fps), 又保证客户端始终知道流是活的。 """ from __future__ import annotations import sys from pathlib import Path SCREEN = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\windows" r"\lanremote\screen.py") # ---------- 1. grab_jpeg 支持 force ---------- SIG_OLD = ''' def grab_jpeg(self) -> tuple[bytes, int, int]:''' SIG_NEW = ''' def grab_jpeg(self, force: bool = False) -> tuple[bytes, int, int]:''' DEDUP_OLD = ''' digest = None if self.dedup:''' DEDUP_NEW = ''' digest = None if self.dedup and not force:''' # ---------- 2. 循环里加心跳 ---------- LOOP_OLD = ''' if not jpeg: # 画面没变(capturer 做了去重):不发送,间隔拉长一点再抓。 idle = min(4.0, idle * 1.6) self._stop.wait(interval * idle) continue''' LOOP_NEW = ''' if not jpeg: # 画面没变(capturer 做了去重)。 # 但不能一直不发 —— 客户端会以为流断了。 # 所以每隔 HEARTBEAT 秒强制发一帧当心跳。 now = time.time() if now - self._last_sent >= self.HEARTBEAT: try: jpeg, width, height = self.capturer.grab_jpeg( force=True) except ScreenError as exc: self.last_error = str(exc) time.sleep(0.5) continue if jpeg: self.frames_sent += 1 self._last_sent = now idle = 1.0 try: if self.on_frame(jpeg, width, height) is False: break except Exception as exc: # noqa: BLE001 self.last_error = str(exc) break elapsed = time.time() - started wait = interval - elapsed if wait > 0: self._stop.wait(wait) continue idle = min(4.0, idle * 1.6) self._stop.wait(interval * idle) continue self._last_sent = time.time()''' # ---------- 3. 字段 ---------- INIT_OLD = ''' self.frames_sent = 0 self.last_error = "" self._started_at = 0.0''' INIT_NEW = ''' self.frames_sent = 0 self.last_error = "" self._started_at = 0.0 # 上次真正发出帧的时间(心跳判断用) self._last_sent = 0.0''' CLASS_OLD = '''class FrameStreamer: """按固定帧率在后台线程推帧,供服务端广播。"""''' CLASS_NEW = '''class FrameStreamer: """按固定帧率在后台线程推帧,供服务端广播。 画面静止时不会傻发同样的画面(用 32x18 缩略图指纹判断), 但每隔 HEARTBEAT 秒会强制发一帧,让客户端知道流还活着。 """ # 画面没变时,最多隔这么久也要发一帧(心跳) HEARTBEAT = 1.5''' def main() -> int: text = SCREEN.read_text(encoding="utf-8") if "_last_sent" in text: print(" 已经改过") return 0 ok = True for old, new, label in ((CLASS_OLD, CLASS_NEW, "加 HEARTBEAT 常量"), (INIT_OLD, INIT_NEW, "加 _last_sent 字段"), (SIG_OLD, SIG_NEW, "grab_jpeg 支持 force"), (DEDUP_OLD, DEDUP_NEW, "force 时跳过去重"), (LOOP_OLD, LOOP_NEW, "循环里加心跳")): if old not in text: print(f" [失败] {label} —— 锚点没找到") ok = False continue text = text.replace(old, new, 1) print(f" {label}") SCREEN.write_text(text, encoding="utf-8", newline="\n") import ast try: ast.parse(text) print(" screen.py 语法 OK") except SyntaxError as exc: print(f" screen.py 语法错误: 行 {exc.lineno}: {exc.msg}") ok = False return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())