功能:完善2K串流、显示恢复与输入优化
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Patches are applied to LF sources on the Linux terminal.
|
||||
terminal/moonlight/patches/*.patch text eol=lf
|
||||
35
MEMORY.md
@ -2,7 +2,42 @@
|
||||
|
||||
完整对话总结在:`D:\DAIMA\vdi-cloud\PROJECT_CONTEXT.md`
|
||||
|
||||
## 2026-11-03 显示器关开修复(优先于下文旧状态)
|
||||
- 关屏再开后画面变矮:盒子回退1920x1440@75(4:3),Moonlight 16:9视频上下黑边;
|
||||
MATE monitors.xml仍存旧4:3布局,原启动脚本只设置一次2K。
|
||||
- 已部署vdi-display-guard用户服务(active/enabled)和幂等启动恢复,保留297MHz定制2K时序;
|
||||
2秒检查、异常稳定2秒后恢复;断开不强设、失败退避、命令超时、单实例锁,正常不反复切换。
|
||||
修正当前GWR/0x2708显示器旧保存布局。仅部署tools/deploy_display_guard.sh,不重启串流。
|
||||
- 9个场景测试通过,CTest 3/3;两次主动回退均约14秒恢复,Moonlight PID66385和boot ID不变。
|
||||
用户真实关屏再开确认自动全屏;10:03:19断开、10:03:31正确2K模式,10:04现场2560x1440。
|
||||
- 备份~/vdi-terminal/backups/display-guard-20261103-095920/;详情/回退见
|
||||
docs/display-resume-fix-20261103.md。此修复仅限当前Xorg单HDMI 2K POC,未做隔夜老化。
|
||||
|
||||
## 2026-11-03 鼠标/点击跳转优化(优先于下文旧状态)
|
||||
- Moonlight私有客户端新增两个补丁:鼠标合并不跨点击/键盘/窗口边界,绝对鼠标按钮封住前一位置批次;
|
||||
低延迟非pacing队列可丢弃等待帧保留最新帧,wrapper默认VDI_LATEST_FRAME=1。保持单白色Windows光标。
|
||||
- 现场32次交替点击:旧客户端30/32正确(第1、13错位),补丁32/32正确;native输入测试1000轮和ASAN通过。
|
||||
配对串流补丁队列2.14ms/呈现6.12ms,原3.39ms/6.84ms;帧率约28.4/28.1,受网络/软件编码波动,不能称零延迟。
|
||||
- Windows保留DragFullWindows=1、MouseTrails=0;已在test交互会话将MinAnimate从1改0、菜单400改100ms,读回通过,
|
||||
原值备份在test的LocalAppData/VDI;临时执行/测试任务已清理。
|
||||
- 用户确认蓝框在盒子登录/选择页:QFrame:hover错误匹配QLabel。移除蓝色悬停框和登录焦点蓝框,限定卡片对象样式,
|
||||
局部编译CTest3/3,部署新版kiosk;悬停截图亮蓝像素8302→0。UI/wrapper备份input-rendering-20261103-114542。
|
||||
详情见docs/input-rendering-optimization-20261103.md和terminal/moonlight/README.md。
|
||||
|
||||
## 2026-11-02 最新实测(优先于下文旧状态)
|
||||
- 2026-11-02晚:已在用户目录完成MPP+FFmpeg-Rockchip+Moonlight6.2.0私有构建,
|
||||
实际2K串流选中h264_rkmpp/drm_prime与EGL/GLES呈现,非仅FFmpeg样本测试。
|
||||
2K20 smooth会话平均呈现18.97FPS、解码10.53ms、呈现2.54ms;2K30 low-latency
|
||||
呈现23.46FPS、解码9.11ms、队列2.39ms、呈现5.41ms。服务端仍Code43/libx264。
|
||||
2K30 smooth队列31.95ms,VSync开/帧步调关也有28.93ms,故该盒子选低延迟档。
|
||||
原始日志和限制见 `docs/rendering-execution-20261102.md`。
|
||||
通过 `~/.config/vdi-terminal/render.conf` 显式选择私有wrapper+hardware,系统客户端不覆盖;
|
||||
Windows桌面票据改30FPS,原20FPS文件备份为desktops.before-rkmpp-20261102.json。
|
||||
构建脚本 `tools/build-rkmpp-client.sh` 修Qt5 optional、EGL探测缓存与旧对象不重编;
|
||||
kiosk就绪判断兼容RKMPP独立测试解码器日志,CTest 2/2通过。
|
||||
鼠标MouseTrails=0、DragFullWindows=1;现场仍有VDIApplyTransparentCursor刷新参数任务,
|
||||
先前“任务已删除”的记录不准确,本轮未改变光标配置;截图单白光标正常。
|
||||
不能把23FPS、硬解接通解释为GPU已恢复、2K60或端到端零延迟。
|
||||
- 已部署真实2K:盒子HDMI 2560x1440约60Hz、Windows VDD 2560x1440@30、Moonlight 2560x1440@20/30Mbps。
|
||||
- RK3528旧PHY拒绝EDID的241.70MHz,实测用297MHz固定时钟和扩展消隐成功:
|
||||
`297.00 2560 2608 2640 2720 1440 1443 1448 1820 +HSync -VSync`;盒子重启已验证,link Good。
|
||||
|
||||
@ -258,11 +258,8 @@ Qt QImage/QLabel 显示
|
||||
|
||||
重要:当前 POC 已成功显示 Windows 10 的真实远程桌面画面,颜色正确,进程保持运行。这是目前最重要的实测成果。
|
||||
|
||||
详细说明在:
|
||||
|
||||
```text
|
||||
D:\DAIMA\vdi-cloud\docs\freerdp3-embedding-notes.md
|
||||
```
|
||||
这部分属于早期 FreeRDP POC 历史记录;对应的临时笔记文件已从仓库移除。
|
||||
当前终端会话实现和维护说明以 `terminal/kiosk-shell/` 及其 README 为准。
|
||||
|
||||
### 6.5 显示问题
|
||||
|
||||
@ -276,12 +273,15 @@ D:\DAIMA\vdi-cloud\docs\freerdp3-embedding-notes.md
|
||||
|
||||
注意:此前对“X11 无 glamor 硬件合成”的判断不准确,Xorg 日志实际显示 `glamor X acceleration enabled on Mali450`;后续不要继续引用这个错误结论。正确表述是:当前路径仍未达到目标流畅度,具体瓶颈需要后续基准测试确认。
|
||||
|
||||
### 6.6 Moonlight 云桌面开机直达(2026-10-28)
|
||||
### 6.6 Moonlight 云桌面开机直达(2026-10-28,历史记录)
|
||||
|
||||
本节保留当时的联调过程和取舍。2026-11-03 的实际部署状态、显示恢复、输入补丁及
|
||||
渲染参数以后续 `MEMORY.md` 和对应日期的 `docs/` 记录为准。
|
||||
|
||||
RDP/Moonlight 实测对比见 `docs/rdp-vs-moonlight-comparison-20261028.md`,
|
||||
落地记录见 `docs/moonlight-kiosk-20261028.md`。
|
||||
|
||||
盒子当前开机默认走 Moonlight 直连云桌面,链路:
|
||||
当时盒子开机默认走 Moonlight 直连云桌面,链路如下:
|
||||
|
||||
```text
|
||||
~/.config/autostart/vdi-moonlight.desktop
|
||||
|
||||
@ -44,7 +44,7 @@ vdi-cloud/
|
||||
├─ platform/ # Go 云端服务
|
||||
├─ console/ # Vue 3 + TypeScript Web 管理控制台
|
||||
├─ deploy/ # Docker Compose、Helm、离线部署包
|
||||
├─ docs/ # OpenAPI、MQTT、数据库等正式协议文档
|
||||
├─ docs/ # 方案文档、实施记录、测试证据和运维资料
|
||||
└─ tools/ # 烧录、构建、压测和 CI 工具
|
||||
```
|
||||
|
||||
|
||||
@ -1 +0,0 @@
|
||||
# Keep the monorepo directory structure in Git.
|
||||
70
docs/display-resume-fix-20261103.md
Normal file
@ -0,0 +1,70 @@
|
||||
# 2026-11-03 显示器关屏再开后云桌面变矮:修复与验收
|
||||
|
||||
已在 `armbian@192.168.1.188` 部署。用户现场关闭显示器、等待后重新打开,确认“已自动恢复全屏”。修复过程没有重启盒子,也没有重启或重连 Moonlight。
|
||||
|
||||
## 原因与证据
|
||||
|
||||
- 异常时盒子 HDMI 输出为 **1920×1440@75Hz(4:3)**,Windows/Moonlight 视频为 **2560×1440(16:9)**。
|
||||
- Moonlight 全屏窗口跟随盒子变为 1920×1440,视频保持宽高比,因此视频内容为 1920×1080,上下各有约 180 像素黑边,表现为“宽度一样,高度矮了一点”。异常截图见 `evidence/display-resume-20261103/before.png`。
|
||||
- MATE 的 `~/.config/monitors.xml` 还保存着 HDMI-1 的 1920×1440@75Hz 配置;原启动脚本只在启动时设置一次 2K,没有处理后续热插拔和模式回退。
|
||||
- 显示器 EDID 的 241.70MHz 时序仍不适用于此 RK3528 vendor PHY;沿用此前已验证的 297MHz 定制 2K 时序,不切回该原厂时序。
|
||||
|
||||
## 修改
|
||||
|
||||
1. 新增 `terminal/kiosk-shell/scripts/vdi-display-guard`:每 2 秒检查 XRandR 状态,模式异常持续至少 2 秒后恢复 `2560x1440_60_fixed297`。模式已存在时不重复创建,热插拔后丢失关联时重新关联。
|
||||
2. 健康状态只查询,不反复设置分辨率;显示器断开或 X11 尚不可用时等待,不强设;设置失败按 2/4/8/16/32/60 秒退避,并在设置后重新读取验证。XRandR 每条命令有 10 秒超时。
|
||||
3. 新增用户级 `vdi-display-guard.service`,已启用 `default.target` 自启、异常退出重启;使用文件锁防止启动恢复与常驻守护竞争。服务独立受 systemd 管理,不挂无主后台循环。
|
||||
4. `vdi-kiosk-start` 使用相同恢复程序做启动检查,再确保服务运行;保留此前渲染配置解析及单一 kiosk 启动链。
|
||||
5. 将本机已知显示器(HDMI-1,GWR/0x2708)的旧保存布局改为 2560×1440@60,其余布局不改。部署前保存原文件。
|
||||
6. 新增只部署显示修复的 `tools/deploy_display_guard.sh`;完整 `deploy_kiosk.sh` 也接入该步骤,避免下次部署覆盖修复。此次只执行前者,未执行会停止串流的完整部署。
|
||||
|
||||
时序仍为:
|
||||
|
||||
```text
|
||||
297.00 2560 2608 2640 2720 1440 1443 1448 1820 +HSync -VSync
|
||||
```
|
||||
|
||||
本次仅调整盒子本地显示,不修改 Windows、Sunshine、GPU、远程光标或已有硬解参数。
|
||||
|
||||
## 验收
|
||||
|
||||
| 项目 | 结果 |
|
||||
| --- | --- |
|
||||
| 自动化显示恢复场景 | 9/9 通过:正常不写、断开/重连、首次创建、重新关联、晚到覆盖、失败退避、设置结果校验、X11 暂不可用等 |
|
||||
| 盒子 CTest | 3/3 通过:display-guard、moonlight-session、desktop-list-page |
|
||||
| 连续两次主动回退 1920×1440@75 | 均自动恢复 2560×1440,全屏窗口恢复 2560×1440,单次从发起切换到观测恢复约 14 秒(含两次驱动切换耗时) |
|
||||
| 真实显示器电源循环 | 用户确认自动恢复全屏;日志在 10:03:19 检测断开,10:03:31 检测到正确 2K 模式,无需额外模式设置 |
|
||||
| 会话连续性 | Moonlight PID 始终为 66385,窗口始终为 44040203;模拟测试前后 boot ID 不变;服务未发生异常重启 |
|
||||
| 最终现场 | 2026-11-03 10:04,HDMI 2560×1440 约 60Hz,Moonlight 窗口 2560×1440,守护 active/enabled |
|
||||
|
||||
原始测试输出:`evidence/display-resume-20261103/recovery-test.txt`。最终模式、进程及包含真实关屏过程的日志:`evidence/display-resume-20261103/final-state.txt`。真实开屏后的截图:`evidence/display-resume-20261103/after-power-cycle.png`。
|
||||
|
||||
这是当前这一台盒子与显示器的现场验收,未执行隔夜或多型号显示器测试。守护固定针对当前单 HDMI、2K、Xorg POC;以后换不同显示器或迁移到 Weston/Wayland 时需改为对应的输出配置机制。当前修复不代表服务端 Code43、帧率或鼠标动态残影问题已解决。
|
||||
|
||||
## 运维
|
||||
|
||||
Windows 开发机在 Git Bash 中只部署此修复:
|
||||
|
||||
```bash
|
||||
bash tools/deploy_display_guard.sh
|
||||
```
|
||||
|
||||
盒子上查看状态与日志(当前环境 `journalctl --user` 看不到用户服务日志,因此使用系统日志的用户单元过滤):
|
||||
|
||||
```bash
|
||||
systemctl --user status vdi-display-guard.service
|
||||
sudo -n journalctl _SYSTEMD_USER_UNIT=vdi-display-guard.service -n 50 --no-pager
|
||||
DISPLAY=:0 XAUTHORITY=/home/armbian/.Xauthority xrandr --query
|
||||
```
|
||||
|
||||
本次部署备份目录为 `/home/armbian/vdi-terminal/backups/display-guard-20261103-095920/`,包含原 `vdi-kiosk-start` 和原 `monitors.xml`。必要时可回退到原行为;这也会恢复旧的 4:3 保存布局和“仅启动时修复”的限制:
|
||||
|
||||
```bash
|
||||
systemctl --user disable --now vdi-display-guard.service
|
||||
cp -p ~/vdi-terminal/backups/display-guard-20261103-095920/vdi-kiosk-start ~/vdi-terminal/bin/vdi-kiosk-start
|
||||
cp -p ~/vdi-terminal/backups/display-guard-20261103-095920/monitors.xml ~/.config/monitors.xml
|
||||
rm -- ~/.config/systemd/user/vdi-display-guard.service
|
||||
systemctl --user daemon-reload
|
||||
```
|
||||
|
||||
日常操作:盒子保持开机,显示器可正常关开。若 HDMI 模式确实回退,给驱动和恢复程序约 15 秒完成切换,无需为此重启盒子。
|
||||
BIN
docs/evidence/display-resume-20261103/after-power-cycle.png
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
BIN
docs/evidence/display-resume-20261103/before.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
43
docs/evidence/display-resume-20261103/final-state.txt
Normal file
@ -0,0 +1,43 @@
|
||||
2026-11-03T10:04:16+08:00
|
||||
Screen 0: minimum 320 x 200, current 2560 x 1440, maximum 16384 x 16384
|
||||
HDMI-1 connected primary 2560x1440+0+0 (normal left inverted right x axis y axis) 597mm x 336mm
|
||||
1920x1440 75.00
|
||||
2048x1152 60.00
|
||||
1920x1080 100.00 60.00 60.00 50.00 59.94
|
||||
1920x1080i 60.00 50.00 59.94
|
||||
1600x1200 60.00
|
||||
1680x1050 59.88
|
||||
1600x900 60.00
|
||||
1280x1024 60.02
|
||||
1440x900 59.90
|
||||
1280x960 85.00 60.00
|
||||
1280x800 59.91
|
||||
1152x864 75.00
|
||||
1280x720 100.00 60.00 50.00 59.94
|
||||
1024x768 60.00
|
||||
800x600 60.32
|
||||
720x576 50.00
|
||||
720x480 59.94
|
||||
2560x1440_60_fixed297 60.00*
|
||||
WINDOW=44040203
|
||||
X=0
|
||||
Y=0
|
||||
WIDTH=2560
|
||||
HEIGHT=1440
|
||||
SCREEN=0
|
||||
66385 /home/armbian/vdi-build/rkmpp-experiment/build/moonlight/app/moonlight stream 192.168.1.70 Desktop --resolution 2560x1440 --fps 30 --bitrate 30000 --display-mode fullscreen --video-codec H.264 --video-decoder hardware --absolute-mouse --keep-awake --no-vsync --no-frame-pacing --audio-on-host
|
||||
MainPID=76385
|
||||
NRestarts=0
|
||||
CPUUsageNSec=2960579000
|
||||
ActiveState=active
|
||||
UnitFileState=enabled
|
||||
11月 03 09:59:22 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 09:59:22 mode drift: 1920x1440 1920x1440+0+0
|
||||
11月 03 09:59:30 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 09:59:30 restored: 2560x1440_60_fixed297 (stream process untouched)
|
||||
11月 03 09:59:33 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 09:59:33 healthy: 2560x1440_60_fixed297
|
||||
11月 03 10:00:26 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:26 mode drift: 1920x1440 1920x1440+0+0
|
||||
11月 03 10:00:34 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:34 restored: 2560x1440_60_fixed297 (stream process untouched)
|
||||
11月 03 10:00:41 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:41 mode drift: 1920x1440 1920x1440+0+0
|
||||
11月 03 10:00:49 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:49 restored: 2560x1440_60_fixed297 (stream process untouched)
|
||||
11月 03 10:00:51 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:51 healthy: 2560x1440_60_fixed297
|
||||
11月 03 10:03:19 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:03:19 HDMI-1 disconnected; no mode changes
|
||||
11月 03 10:03:31 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:03:31 healthy: 2560x1440_60_fixed297
|
||||
@ -0,0 +1,10 @@
|
||||
--query seconds= 0.109
|
||||
--current seconds= 0.015
|
||||
11月 03 09:59:22 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 09:59:22 mode drift: 1920x1440 1920x1440+0+0
|
||||
11月 03 09:59:30 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 09:59:30 restored: 2560x1440_60_fixed297 (stream process untouched)
|
||||
11月 03 09:59:33 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 09:59:33 healthy: 2560x1440_60_fixed297
|
||||
11月 03 10:00:26 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:26 mode drift: 1920x1440 1920x1440+0+0
|
||||
11月 03 10:00:34 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:34 restored: 2560x1440_60_fixed297 (stream process untouched)
|
||||
11月 03 10:00:41 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:41 mode drift: 1920x1440 1920x1440+0+0
|
||||
11月 03 10:00:49 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:49 restored: 2560x1440_60_fixed297 (stream process untouched)
|
||||
11月 03 10:00:51 rk3528pro-ddr4 vdi-display-guard[76385]: 2026-11-03 10:00:51 healthy: 2560x1440_60_fixed297
|
||||
25
docs/evidence/display-resume-20261103/recovery-test.txt
Normal file
@ -0,0 +1,25 @@
|
||||
before_stream_pid=66385 boot_id=89a44e11-5cfd-46bb-ae72-3232edc4ea62
|
||||
enabled
|
||||
active
|
||||
2026-11-03 10:00:20 display guard already running
|
||||
cycle=1 drift_at=2026-11-03T10:00:20+08:00
|
||||
cycle=1 recovered_at=2026-11-03T10:00:34+08:00
|
||||
WINDOW=44040203
|
||||
X=0
|
||||
Y=0
|
||||
WIDTH=2560
|
||||
HEIGHT=1440
|
||||
SCREEN=0
|
||||
cycle=2 drift_at=2026-11-03T10:00:35+08:00
|
||||
cycle=2 recovered_at=2026-11-03T10:00:49+08:00
|
||||
WINDOW=44040203
|
||||
X=0
|
||||
Y=0
|
||||
WIDTH=2560
|
||||
HEIGHT=1440
|
||||
SCREEN=0
|
||||
PASS: both recoveries kept stream PID and boot ID
|
||||
MainPID=76385
|
||||
NRestarts=0
|
||||
CPUUsageNSec=1092599000
|
||||
-- No entries --
|
||||
BIN
docs/evidence/display-resume-20261103/restored.png
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
71
docs/evidence/input-latency-20261103/baseline-clicks.txt
Normal file
@ -0,0 +1,71 @@
|
||||
width=2560 height=1440 paints=19411 elapsed_ms=536551 clicks=32
|
||||
|
||||
ms,x,y,target
|
||||
|
||||
536057,1920,600,R
|
||||
|
||||
536060,1920,600,R
|
||||
|
||||
536063,639,600,L
|
||||
|
||||
536070,1920,600,R
|
||||
|
||||
536071,639,600,L
|
||||
|
||||
536072,1920,600,R
|
||||
|
||||
536077,639,600,L
|
||||
|
||||
536078,1920,600,R
|
||||
|
||||
536086,639,600,L
|
||||
|
||||
536148,1920,600,R
|
||||
|
||||
536151,639,600,L
|
||||
|
||||
536152,1920,600,R
|
||||
|
||||
536153,1920,600,R
|
||||
|
||||
536154,1920,600,R
|
||||
|
||||
536155,639,600,L
|
||||
|
||||
536156,1920,600,R
|
||||
|
||||
536157,639,600,L
|
||||
|
||||
536158,1920,600,R
|
||||
|
||||
536159,639,600,L
|
||||
|
||||
536160,1920,600,R
|
||||
|
||||
536161,639,600,L
|
||||
|
||||
536162,1920,600,R
|
||||
|
||||
536163,639,600,L
|
||||
|
||||
536164,1920,600,R
|
||||
|
||||
536165,639,600,L
|
||||
|
||||
536166,1920,600,R
|
||||
|
||||
536167,639,600,L
|
||||
|
||||
536168,1920,600,R
|
||||
|
||||
536169,639,600,L
|
||||
|
||||
536170,1920,600,R
|
||||
|
||||
536171,639,600,L
|
||||
|
||||
536172,1920,600,R
|
||||
|
||||
{"LastTaskResult":267009}
|
||||
|
||||
|
||||
37
docs/evidence/input-latency-20261103/baseline-stats.txt
Normal file
@ -0,0 +1,37 @@
|
||||
ELAPSED COMMAND
|
||||
93 /home/armbian/vdi-build/rkmpp-experiment/build/moonlight/app/moonlight stream 192.168.1.70 Desktop --resolution 2560x1440 --fps 30 --bitrate 30000 --display-mode fullscreen --video-codec H.264 --video-decoder hardware --absolute-mouse --keep-awake --no-vsync --no-frame-pacing --audio-on-host --performance-overlay
|
||||
------------------
|
||||
Incoming frame rate from network: 27.45 FPS
|
||||
Decoding frame rate: 27.45 FPS
|
||||
Rendering frame rate: 27.14 FPS
|
||||
Host processing latency min/max/average: 27.3/87.5/48.5 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.52%
|
||||
Average network latency: 6 ms (variance: 5 ms)
|
||||
Average decoding time: 9.84 ms
|
||||
Average frame queue delay: 4.50 ms
|
||||
Average rendering time (including monitor V-sync latency): 6.89 ms
|
||||
00:01:34 - SDL Info (0): Stopping input stream...
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Stopping audio stream...
|
||||
00:01:34 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:01:34 - SDL Info (0): ENet wait interrupted
|
||||
00:01:34 - SDL Info (0): Control stream connection failed: 4
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Stopping video stream...
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Stopping control stream...
|
||||
00:01:34 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Cleaning up input stream...
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Cleaning up video stream...
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Cleaning up control stream...
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Cleaning up audio stream...
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - SDL Info (0): Cleaning up platform...
|
||||
00:01:34 - SDL Info (0): done
|
||||
00:01:34 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:01:34 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
BIN
docs/evidence/input-latency-20261103/baseline.png
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
docs/evidence/input-latency-20261103/blue-hover-after.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
docs/evidence/input-latency-20261103/blue-hover-before.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
17
docs/evidence/input-latency-20261103/click-comparison.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"baseline": {
|
||||
"received": 32,
|
||||
"expected": 32,
|
||||
"wrong_positions": [
|
||||
1,
|
||||
13
|
||||
],
|
||||
"correct": 30
|
||||
},
|
||||
"patched": {
|
||||
"received": 32,
|
||||
"expected": 32,
|
||||
"wrong_positions": [],
|
||||
"correct": 32
|
||||
}
|
||||
}
|
||||
BIN
docs/evidence/input-latency-20261103/current-screen.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
15
docs/evidence/input-latency-20261103/deployed-final.txt
Normal file
@ -0,0 +1,15 @@
|
||||
101612 /home/armbian/vdi-build/rkmpp-experiment/build/moonlight/app/moonlight stream 192.168.1.70 Desktop --resolution 2560x1440 --fps 30 --bitrate 30000 --display-mode fullscreen --video-codec H.264 --video-decoder hardware --absolute-mouse --keep-awake --no-vsync --no-frame-pacing --audio-on-host
|
||||
Renderer 'SDL' with 'DRM' backend chosen
|
||||
00:00:09 - SDL Info (0): VDI latest-frame queue: enabled
|
||||
00:00:09 - SDL Info (0): Renderer 'EGL/GLES' with 'DRM' backend chosen
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=ticket result=ready phase_ms=20 total_ms=20 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=process_start result=started phase_ms=0 total_ms=21 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=process_start result=ready phase_ms=103 total_ms=125 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=stream_ready result=ready phase_ms=10440 total_ms=10566 error=
|
||||
active
|
||||
WINDOW=44040203
|
||||
X=0
|
||||
Y=0
|
||||
WIDTH=2560
|
||||
HEIGHT=1440
|
||||
SCREEN=0
|
||||
@ -0,0 +1,3 @@
|
||||
Screen 0: minimum 320 x 200, current 2560 x 1440, maximum 16384 x 16384
|
||||
2560x1440_60_fixed297 60.00*
|
||||
active
|
||||
30
docs/evidence/input-latency-20261103/paired-retest.txt
Normal file
@ -0,0 +1,30 @@
|
||||
baseline2 ready_at=2026-11-03T10:52:11+08:00 pid=95753
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 28.93 FPS
|
||||
Decoding frame rate: 28.93 FPS
|
||||
Rendering frame rate: 28.48 FPS
|
||||
Host processing latency min/max/average: 27.9/78.7/42.6 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.54%
|
||||
Average network latency: 9 ms (variance: 4 ms)
|
||||
Average decoding time: 10.49 ms
|
||||
Average frame queue delay: 3.39 ms
|
||||
Average rendering time (including monitor V-sync latency): 6.84 ms
|
||||
00:00:54 - SDL Info (0): Stopping input stream...
|
||||
baseline2 complete_at=2026-11-03T10:52:58+08:00
|
||||
patched2 ready_at=2026-11-03T10:53:07+08:00 pid=95869
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 28.40 FPS
|
||||
Decoding frame rate: 28.40 FPS
|
||||
Rendering frame rate: 28.09 FPS
|
||||
Host processing latency min/max/average: 31.2/96.2/42.3 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 1.10%
|
||||
Average network latency: 4 ms (variance: 4 ms)
|
||||
Average decoding time: 7.96 ms
|
||||
Average frame queue delay: 2.14 ms
|
||||
Average rendering time (including monitor V-sync latency): 6.12 ms
|
||||
00:00:54 - SDL Info (0): Stopping input stream...
|
||||
patched2 complete_at=2026-11-03T10:53:53+08:00
|
||||
71
docs/evidence/input-latency-20261103/patched-clicks.txt
Normal file
@ -0,0 +1,71 @@
|
||||
width=2560 height=1440 paints=1532 elapsed_ms=45518 clicks=32
|
||||
|
||||
ms,x,y,target
|
||||
|
||||
44625,639,600,L
|
||||
|
||||
44625,1920,600,R
|
||||
|
||||
44627,639,600,L
|
||||
|
||||
44628,1920,600,R
|
||||
|
||||
44629,639,600,L
|
||||
|
||||
44630,1920,600,R
|
||||
|
||||
44651,639,600,L
|
||||
|
||||
44692,1920,600,R
|
||||
|
||||
44693,639,600,L
|
||||
|
||||
44694,1920,600,R
|
||||
|
||||
44695,639,600,L
|
||||
|
||||
44696,1920,600,R
|
||||
|
||||
44697,639,600,L
|
||||
|
||||
44697,1920,600,R
|
||||
|
||||
44698,639,600,L
|
||||
|
||||
44699,1920,600,R
|
||||
|
||||
44703,639,600,L
|
||||
|
||||
44713,1920,600,R
|
||||
|
||||
44716,639,600,L
|
||||
|
||||
44717,1920,600,R
|
||||
|
||||
44718,639,600,L
|
||||
|
||||
44718,1920,600,R
|
||||
|
||||
44719,639,600,L
|
||||
|
||||
44720,1920,600,R
|
||||
|
||||
44721,639,600,L
|
||||
|
||||
44722,1920,600,R
|
||||
|
||||
44722,639,600,L
|
||||
|
||||
44723,1920,600,R
|
||||
|
||||
44746,639,600,L
|
||||
|
||||
44747,1920,600,R
|
||||
|
||||
44748,639,600,L
|
||||
|
||||
44749,1920,600,R
|
||||
|
||||
{"LastTaskResult":267009}
|
||||
|
||||
|
||||
37
docs/evidence/input-latency-20261103/patched-stats.txt
Normal file
@ -0,0 +1,37 @@
|
||||
ELAPSED COMMAND
|
||||
147 /home/armbian/vdi-build/rkmpp-experiment/build/moonlight/app/moonlight stream 192.168.1.70 Desktop --resolution 2560x1440 --fps 30 --bitrate 30000 --display-mode fullscreen --video-codec H.264 --video-decoder hardware --absolute-mouse --keep-awake --no-vsync --no-frame-pacing --audio-on-host --performance-overlay
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.81%
|
||||
Average network latency: 15 ms (variance: 14 ms)
|
||||
Average decoding time: 8.30 ms
|
||||
Average frame queue delay: 2.72 ms
|
||||
Average rendering time (including monitor V-sync latency): 6.62 ms
|
||||
00:02:05 - SDL Info (0): Stopping input stream...
|
||||
00:02:05 - Qt Critical: 会话已终止
|
||||
|
||||
错误代码: -1
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - Qt Warning: stream 1 finished with error: "Connection closed"
|
||||
00:02:05 - SDL Info (0): Stopping audio stream...
|
||||
00:02:05 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - SDL Info (0): Stopping video stream...
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - SDL Info (0): Stopping control stream...
|
||||
00:02:05 - SDL Info (0): ENet peer is already disconnected
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - SDL Info (0): Cleaning up input stream...
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - SDL Info (0): Cleaning up video stream...
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - SDL Info (0): Cleaning up control stream...
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - SDL Info (0): Cleaning up audio stream...
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - SDL Info (0): Cleaning up platform...
|
||||
00:02:05 - SDL Info (0): done
|
||||
00:02:05 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:02:05 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:02:05 - Qt Warning: Failed to download latest compatibility data: QNetworkReply::RemoteHostClosedError
|
||||
00:02:13 - Qt Info: "DESKTOP-Q072ICM" is now offline
|
||||
00:02:22 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
@ -0,0 +1,7 @@
|
||||
width=2560 height=1440 paints=19799 elapsed_ms=599310 clicks=0
|
||||
|
||||
ms,x,y,target
|
||||
|
||||
{"LastTaskResult":267014}
|
||||
|
||||
|
||||
28
docs/evidence/input-latency-20261103/wifi-disconnect.txt
Normal file
@ -0,0 +1,28 @@
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.6211] device (wlan0): supplicant interface state: completed -> disconnected
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.6213] device (p2p-dev-wlan0): supplicant management interface state: completed -> disconnected
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.7019] device (wlan0): supplicant interface state: disconnected -> scanning
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.7030] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.7412] device (wlan0): supplicant interface state: scanning -> associating
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.7415] device (p2p-dev-wlan0): supplicant management interface state: scanning -> associating
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.9321] device (wlan0): supplicant interface state: associating -> disconnected
|
||||
11月 03 10:48:18 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674098.9324] device (p2p-dev-wlan0): supplicant management interface state: associating -> disconnected
|
||||
11月 03 10:48:19 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674099.4318] device (wlan0): supplicant interface state: disconnected -> scanning
|
||||
11月 03 10:48:19 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674099.4320] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning
|
||||
11月 03 10:48:20 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674100.8003] device (wlan0): supplicant interface state: scanning -> associating
|
||||
11月 03 10:48:20 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674100.8005] device (p2p-dev-wlan0): supplicant management interface state: scanning -> associating
|
||||
11月 03 10:48:20 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674100.9901] device (wlan0): supplicant interface state: associating -> disconnected
|
||||
11月 03 10:48:20 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674100.9903] device (p2p-dev-wlan0): supplicant management interface state: associating -> disconnected
|
||||
11月 03 10:48:21 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674101.9908] device (wlan0): supplicant interface state: disconnected -> scanning
|
||||
11月 03 10:48:21 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674101.9910] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning
|
||||
11月 03 10:48:22 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674102.0281] device (wlan0): supplicant interface state: scanning -> associating
|
||||
11月 03 10:48:22 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674102.0283] device (p2p-dev-wlan0): supplicant management interface state: scanning -> associating
|
||||
11月 03 10:48:22 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674102.2189] device (wlan0): supplicant interface state: associating -> disconnected
|
||||
11月 03 10:48:22 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674102.2192] device (p2p-dev-wlan0): supplicant management interface state: associating -> disconnected
|
||||
11月 03 10:48:27 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674107.2236] device (wlan0): supplicant interface state: disconnected -> scanning
|
||||
11月 03 10:48:27 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674107.2239] device (p2p-dev-wlan0): supplicant management interface state: disconnected -> scanning
|
||||
11月 03 10:48:31 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674111.5980] device (wlan0): supplicant interface state: scanning -> associating
|
||||
11月 03 10:48:31 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674111.5983] device (p2p-dev-wlan0): supplicant management interface state: scanning -> associating
|
||||
11月 03 10:48:31 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674111.8979] device (wlan0): supplicant interface state: associating -> associated
|
||||
11月 03 10:48:31 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674111.8981] device (p2p-dev-wlan0): supplicant management interface state: associating -> associated
|
||||
11月 03 10:48:31 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674111.9156] device (wlan0): supplicant interface state: associated -> completed
|
||||
11月 03 10:48:31 rk3528pro-ddr4 NetworkManager[883]: <info> [1793674111.9161] device (p2p-dev-wlan0): supplicant management interface state: associated -> completed
|
||||
@ -0,0 +1,30 @@
|
||||
{"LastTaskResult":0}
|
||||
|
||||
{
|
||||
|
||||
"backup": "C:\\Users\\test\\AppData\\Local\\VDI\\desktop-responsiveness-before-20261103.json",
|
||||
|
||||
"before": {
|
||||
|
||||
"animation": 1,
|
||||
|
||||
"menuDelay": 400
|
||||
|
||||
},
|
||||
|
||||
"restored": false,
|
||||
|
||||
"after": {
|
||||
|
||||
"animation": 0,
|
||||
|
||||
"menuDelay": 100
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
41
docs/evidence/moonlight-20261102/decode-drm-prime.txt
Normal file
@ -0,0 +1,41 @@
|
||||
[h264 @ 0xaaab09e425e0] Reinit context to 2560x1440, pix_fmt: yuv420p
|
||||
Input #0, h264, from '/home/armbian/vdi-build/rkmpp-experiment/test/1440p.h264':
|
||||
Duration: N/A, bitrate: N/A
|
||||
Stream #0:0: Video: h264 (Constrained Baseline), 1 reference frame, yuv420p(progressive, left), 2560x1440, 25 fps, 60 tbr, 1200k tbn
|
||||
[out#0/null @ 0xaaab09e42f00] No explicit maps, mapping streams automatically...
|
||||
[vost#0:0/wrapped_avframe @ 0xaaab09e77260] Created video stream from input stream 0:0
|
||||
[h264_mp4toannexb @ 0xaaab09e6e100] The input looks like it is Annex B already
|
||||
mpp[30233]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
[h264_rkmpp @ 0xaaab09f55980] Picked up an existing RKMPP hardware device
|
||||
Stream mapping:
|
||||
Stream #0:0 -> #0:0 (h264 (h264_rkmpp) -> wrapped_avframe (native))
|
||||
Press [q] to stop, [?] for help
|
||||
[h264_rkmpp @ 0xaaab09f55980] Noticed an info change
|
||||
[h264_rkmpp @ 0xaaab09f55980] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
[h264_rkmpp @ 0xaaab09f55980] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
[graph 0 input from stream 0:0 @ 0xaaab09f264a0] w:2560 h:1440 pixfmt:drm_prime tb:1/1200000 fr:30/1 sar:0/1
|
||||
Output #0, null, to 'pipe:':
|
||||
Metadata:
|
||||
encoder : Lavf60.16.101
|
||||
Stream #0:0: Video: wrapped_avframe, 1 reference frame, drm_prime(tv, progressive, left), 2560x1440 (0x0), q=2-31, 200 kb/s, 30 fps, 30 tbn
|
||||
Metadata:
|
||||
encoder : Lavc60.31.102 wrapped_avframe
|
||||
frame= 0 fps=0.0 q=-0.0 size= 0kB time=00:00:00.03 bitrate= 0.0kbits/s speed=29.3x
[in#0/h264 @ 0xaaab09e3b470] EOF while reading input
|
||||
[in#0/h264 @ 0xaaab09e3b470] Terminating demuxer thread
|
||||
[vist#0:0/h264 @ 0xaaab09e42c30] Decoder thread received EOF packet
|
||||
[vist#0:0/h264 @ 0xaaab09e42c30] Decoder returned EOF, finishing
|
||||
[vist#0:0/h264 @ 0xaaab09e42c30] Terminating decoder thread
|
||||
No more output streams to write to, finishing.
|
||||
[out#0/null @ 0xaaab09e42f00] All streams finished
|
||||
[out#0/null @ 0xaaab09e42f00] Terminating muxer thread
|
||||
[out#0/null @ 0xaaab09e42f00] Output file #0 (pipe:):
|
||||
[out#0/null @ 0xaaab09e42f00] Output stream #0:0 (video): 60 frames encoded; 60 packets muxed (28800 bytes);
|
||||
[out#0/null @ 0xaaab09e42f00] Total: 60 packets (28800 bytes) muxed
|
||||
[out#0/null @ 0xaaab09e42f00] video:28kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
|
||||
frame= 60 fps=0.0 q=-0.0 Lsize=N/A time=00:00:02.00 bitrate=N/A speed=6.91x
|
||||
bench: utime=0.058s stime=0.062s rtime=0.290s
|
||||
bench: maxrss=24448kB
|
||||
[in#0/h264 @ 0xaaab09e3b470] Input file #0 (/home/armbian/vdi-build/rkmpp-experiment/test/1440p.h264):
|
||||
[in#0/h264 @ 0xaaab09e3b470] Input stream #0:0 (video): 60 packets read (57854 bytes); 60 frames decoded; 0 decode errors;
|
||||
[in#0/h264 @ 0xaaab09e3b470] Total: 60 packets (57854 bytes) demuxed
|
||||
[AVIOContext @ 0xaaab09e3bb10] Statistics: 57854 bytes read, 0 seeks
|
||||
42
docs/evidence/moonlight-20261102/dependency-sha256.txt
Normal file
@ -0,0 +1,42 @@
|
||||
9eba20198e9416da0be63cf8da2c34d943e6702b825528d1678eccfc7ab5b3ce /home/armbian/vdi-build/rkmpp-experiment/debs/libbrotli-dev_1.1.0-2ubuntu0.1_arm64.deb
|
||||
892633787d2810eb326e3b3dc5ef43cc61fa5b58efdd8474cef71a7c706d8220 /home/armbian/vdi-build/rkmpp-experiment/debs/libdrm-dev_2.4.125-1ubuntu0.1~24.04.2_arm64.deb
|
||||
99e364f5b5d5847feeb57bf4bd866331da93f16ba767c25286dd7f65e4b828ec /home/armbian/vdi-build/rkmpp-experiment/debs/libegl-dev_1.7.0-1build1_arm64.deb
|
||||
887755d6aa91c12ee0eb3404b61f6dc138c4c59234aa2add0264baf270337708 /home/armbian/vdi-build/rkmpp-experiment/debs/libffi-dev_3.4.6-1build1_arm64.deb
|
||||
bf051daf32337f64c23010f59bfca6e54810918531ba7757aa6797fa413ba1cb /home/armbian/vdi-build/rkmpp-experiment/debs/libfreetype-dev_2.13.2+dfsg-1ubuntu0.2_arm64.deb
|
||||
f0faf030f4dc8b78420dbdefd3aa764b855aa6ff7fbe1b0851ba851c43c2fa08 /home/armbian/vdi-build/rkmpp-experiment/debs/libgbm-dev_25.2.8-0ubuntu0.24.04.4_arm64.deb
|
||||
a7c9cd011c8e05fb573445560cab86d61583cda0f79c248fd73680e2d0618b54 /home/armbian/vdi-build/rkmpp-experiment/debs/libgles1_1.7.0-1build1_arm64.deb
|
||||
df742afc0b66f24d80920b419723e072ab59d70726519d5994f50cf09e1f3961 /home/armbian/vdi-build/rkmpp-experiment/debs/libgles-dev_1.7.0-1build1_arm64.deb
|
||||
7cf6c28c1895d6843e901f68dd2d90be5a9280bfef70e1e8dfaa2096e14c13ad /home/armbian/vdi-build/rkmpp-experiment/debs/libglib2.0-dev_2.80.0-6ubuntu3.10_arm64.deb
|
||||
f6af2526f1a4b2264bbc7db25161f1d4f14ade79f731cd21a4c388d7e03debce /home/armbian/vdi-build/rkmpp-experiment/debs/libgraphite2-dev_1.3.14-2ubuntu0.24.04.1_arm64.deb
|
||||
2897a334893c407502f3787fb1ca10ddfd2e35c05a19637396afcfd55873db8d /home/armbian/vdi-build/rkmpp-experiment/debs/libharfbuzz-dev_8.3.0-2build2_arm64.deb
|
||||
4ef5f13cb3a4cbac89e50f48c70355a658911d8db2ff94f263daf5092074e010 /home/armbian/vdi-build/rkmpp-experiment/debs/libopus-dev_1.4-1build1_arm64.deb
|
||||
d73f6246d98ad03283f6b9a30fd86da52ea360afbf5ed48c2e4eb995d04b87aa /home/armbian/vdi-build/rkmpp-experiment/debs/libpng-dev_1.6.43-5ubuntu0.7_arm64.deb
|
||||
85957d625c083a85b7cade0c3696b99095eea9c03242a3452cb6d4b0cb882c3d /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5qmlworkerscript5_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
e10c14d16d3167b29ff1c69d955d3cde68ccb65dbc2f1362c0140fe88e55274f /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5quickcontrols2-5_5.15.13+dfsg-1_arm64.deb
|
||||
97499cbc6dfed8ac3fc1e126861f4e4f66f5196d64eceb90810cd814a7a59069 /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5quickparticles5_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
66d440824d1ab8845e3422a63e248e650f0efc80a07f961b5842ccdb58c199c3 /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5quickshapes5_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
e5fc6fa488bef184069aa80e046991d8c75ec76d6f0b8e6580b27344b0543577 /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5quicktemplates2-5_5.15.13+dfsg-1_arm64.deb
|
||||
73f7aa7231c06cc6e4e7d215421d60cca4835c4f94d1b69587b73cb41866d45a /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5quicktest5_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
813202055ca9743206d33e955cac3152a3bac7abbbc8254e01c18feda6e39d0d /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5svg5_5.15.13-1_arm64.deb
|
||||
690245647bb8fd8ce21feaf8bece72c4cf64c85747fe6baa96dc20dd4eb95c1d /home/armbian/vdi-build/rkmpp-experiment/debs/libqt5svg5-dev_5.15.13-1_arm64.deb
|
||||
3406a7a3cf98a633c9a1289eb20a31e03a04477afb95c8558f2de7f70abdd0bb /home/armbian/vdi-build/rkmpp-experiment/debs/libsdl2-2.0-0_2.30.0+dfsg-1ubuntu3.1_arm64.deb
|
||||
edcb8ab3594488050f0a1c3fe983cf57d00ed6680ae173a8b919ef6fd99c3c3a /home/armbian/vdi-build/rkmpp-experiment/debs/libsdl2-dev_2.30.0+dfsg-1ubuntu3.1_arm64.deb
|
||||
7a23ed32398355c4e771a8a1eae344f3cbbaca6deffe4172f8ce900dd4154687 /home/armbian/vdi-build/rkmpp-experiment/debs/libsdl2-ttf-2.0-0_2.22.0+dfsg-1_arm64.deb
|
||||
e6a9ddf95bbb39bd55f9587fc874291d00cc8a5723b6d5a721bc50d646565926 /home/armbian/vdi-build/rkmpp-experiment/debs/libsdl2-ttf-dev_2.22.0+dfsg-1_arm64.deb
|
||||
4b287709aaddb404233155f78c4f08bb943515065d99b8a205b7a147b76b4d5d /home/armbian/vdi-build/rkmpp-experiment/debs/libudev-dev_255.4-1ubuntu8.18_arm64.deb
|
||||
a2cc274d08d3b966008d0a1f43545bc569c7934d383355829706fb25220b842e /home/armbian/vdi-build/rkmpp-experiment/debs/libwayland-bin_1.22.0-2.1build1_arm64.deb
|
||||
6d94b723710aae35d0ff765978818601f4320c1dc4e0eec57e73b000943a1758 /home/armbian/vdi-build/rkmpp-experiment/debs/libwayland-dev_1.22.0-2.1build1_arm64.deb
|
||||
213534d13ff7afd55155ae022d972faa6d2c343fcebb1e4517f37d7193b1b6d0 /home/armbian/vdi-build/rkmpp-experiment/debs/libx264-dev_2%3a0.164.3108+git31e19f9-1_arm64.deb
|
||||
de01e5d50d114ddc5419d61cde552d8a956a2dc9e6c004ce50b7f37a02a47c1d /home/armbian/vdi-build/rkmpp-experiment/debs/libxkbcommon-dev_1.6.0-1build1_arm64.deb
|
||||
80edfdbc1cd71202ec56d0643e24f75745f1f60bee0cfaef7afa8a40b290ddf2 /home/armbian/vdi-build/rkmpp-experiment/debs/qml-module-qtqml-models2_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
5315cda68ae300ba6938ac83dbb398644419214a8febf2ed988500d8bc4b3d20 /home/armbian/vdi-build/rkmpp-experiment/debs/qml-module-qtquick2_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
a5c57eefe7ec2dafc5f0d9410fef4a09320349eece173e406be6b73eb4eab985 /home/armbian/vdi-build/rkmpp-experiment/debs/qml-module-qtquick-controls2_5.15.13+dfsg-1_arm64.deb
|
||||
cecf088b56cbe3df083bf3b18d7da264d6ac270bb93796e749b3bd5497253340 /home/armbian/vdi-build/rkmpp-experiment/debs/qml-module-qtquick-layouts_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
775d0c95e6ab30a6002d6c0a0613b4c4b9d9d91616804701f7c707706c51bb0b /home/armbian/vdi-build/rkmpp-experiment/debs/qml-module-qtquick-templates2_5.15.13+dfsg-1_arm64.deb
|
||||
af63b41209ee631ba5a5c7eee3976b4342373fd6cd6e47a51467834ac8aac05b /home/armbian/vdi-build/rkmpp-experiment/debs/qml-module-qtquick-window2_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
02313d79aa812e29f6b0494bcbad04e89df8734368e5d68485ac29c31e48b1a7 /home/armbian/vdi-build/rkmpp-experiment/debs/qt5-qmltooling-plugins_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
a7972aee9593b17742461d0b81e1eec1aae0d50ff76257b2bec01844c523be2f /home/armbian/vdi-build/rkmpp-experiment/debs/qtdeclarative5-dev_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
f4235926cc915848adc215ff279b108a19222d5a0e8f4d28210db0e8ffee5848 /home/armbian/vdi-build/rkmpp-experiment/debs/qtdeclarative5-dev-tools_5.15.13+dfsg-1ubuntu0.1_arm64.deb
|
||||
852dba1e49327be8e609b9235ac5a7374fd4538d4196752075989f6bb357e590 /home/armbian/vdi-build/rkmpp-experiment/debs/qtquickcontrols2-5-dev_5.15.13+dfsg-1_arm64.deb
|
||||
e4fa5eb09a9f3eee12a863718badfc51a986cda32e53e37e841b76756e5caebc /home/armbian/vdi-build/rkmpp-experiment/debs/wayland-protocols_1.45-1~ubuntu0.24.04.2_all.deb
|
||||
5ad30e35e9bb0a66a1af4d1bac3d9f2035658040affec533e058001259e2796f /home/armbian/vdi-build/rkmpp-experiment/debs/zlib1g-dev_1%3a1.3.dfsg-3.1ubuntu2.3_arm64.deb
|
||||
10
docs/evidence/moonlight-20261102/generate-1440p.txt
Normal file
@ -0,0 +1,10 @@
|
||||
[libx264 @ 0xaaaaf7134470] using cpu capabilities: ARMv8 NEON
|
||||
[libx264 @ 0xaaaaf7134470] profile Constrained Baseline, level 5.0, 4:2:0, 8-bit
|
||||
[libx264 @ 0xaaaaf7134470] frame I:1 Avg QP:20.00 size: 15901
|
||||
[libx264 @ 0xaaaaf7134470] frame P:59 Avg QP:16.00 size: 711
|
||||
[libx264 @ 0xaaaaf7134470] mb I I16..4: 100.0% 0.0% 0.0%
|
||||
[libx264 @ 0xaaaaf7134470] mb P I16..4: 1.3% 0.0% 0.0% P16..4: 2.8% 0.0% 0.0% 0.0% 0.0% skip:95.9%
|
||||
[libx264 @ 0xaaaaf7134470] coded y,uvDC,uvAC intra: 0.4% 0.0% 0.0% inter: 0.0% 0.0% 0.0%
|
||||
[libx264 @ 0xaaaaf7134470] i16 v,h,dc,p: 0% 99% 0% 0%
|
||||
[libx264 @ 0xaaaaf7134470] i8c dc,h,v,p: 100% 0% 0% 0%
|
||||
[libx264 @ 0xaaaaf7134470] kb/s:231.42
|
||||
BIN
docs/evidence/moonlight-20261102/kiosk-rkmpp-disconnect.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
docs/evidence/moonlight-20261102/kiosk-rkmpp-final-desktop.png
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
BIN
docs/evidence/moonlight-20261102/kiosk-rkmpp-first-connect.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
13
docs/evidence/moonlight-20261102/kiosk-rkmpp-monitor.txt
Normal file
@ -0,0 +1,13 @@
|
||||
[monitor 2026-11-02 20:10:05] 看门狗启动,监控: /home/armbian/vdi-terminal/bin/kiosk-shell
|
||||
[monitor 2026-11-02 20:10:05] 主进程已启动, pid=63682
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=ticket result=started phase_ms=0 total_ms=0 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=ticket result=ready phase_ms=19 total_ms=19 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=process_start result=started phase_ms=0 total_ms=19 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=process_start result=ready phase_ms=110 total_ms=130 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=stream_ready result=ready phase_ms=9940 total_ms=10071 error=
|
||||
vdi_connection attempt=1 desktop=desk-win10-01 phase=session result=finished phase_ms=170912 total_ms=171043 error=
|
||||
vdi_connection attempt=3 desktop=desk-win10-01 phase=ticket result=started phase_ms=0 total_ms=0 error=
|
||||
vdi_connection attempt=3 desktop=desk-win10-01 phase=ticket result=ready phase_ms=1 total_ms=1 error=
|
||||
vdi_connection attempt=3 desktop=desk-win10-01 phase=process_start result=started phase_ms=0 total_ms=2 error=
|
||||
vdi_connection attempt=3 desktop=desk-win10-01 phase=process_start result=ready phase_ms=62 total_ms=64 error=
|
||||
vdi_connection attempt=3 desktop=desk-win10-01 phase=stream_ready result=ready phase_ms=9638 total_ms=9702 error=
|
||||
BIN
docs/evidence/moonlight-20261102/kiosk-rkmpp-reconnect.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
docs/evidence/moonlight-20261102/kiosk-rkmpp-session.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
452
docs/evidence/moonlight-20261102/kiosk-rkmpp-validation.txt
Normal file
@ -0,0 +1,452 @@
|
||||
|
||||
[VDI launch]
|
||||
profile=low-latency
|
||||
program=/home/armbian/vdi-terminal/bin/vdi-moonlight-rkmpp
|
||||
decoder=hardware
|
||||
codec=H.264
|
||||
vsync=0
|
||||
frame-pacing=0
|
||||
renderer=opengles2
|
||||
video-driver=
|
||||
args=stream 192.168.1.70 Desktop --resolution 2560x1440 --fps 30 --bitrate 30000 --display-mode fullscreen --video-codec H.264 --video-decoder hardware --absolute-mouse --keep-awake --no-vsync --no-frame-pacing --audio-on-host
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.30.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.30.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:02 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:02 - SDL Info (0): SDL found matching display 0
|
||||
00:00:02 - Qt Info: Server GPU: ""
|
||||
00:00:02 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:02 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:02 - SDL Info (0): Audio channel count: 2
|
||||
00:00:02 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:02 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf977dda0] The input looks like it is Annex B already
|
||||
mpp[64569]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf9478020] The input looks like it is Annex B already
|
||||
mpp[64569]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Noticed an info change
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf94e7ed0] Received a frame
|
||||
00:00:03 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:03 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:03 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:06 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:06 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:06 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=1f4223efe39e4eecad4ee7e90ad131e8&appid=881448767&mode=2560x1440x30&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=1&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:07 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:07 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:07 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:07 - Qt Info: Interface MTU: 1500
|
||||
00:00:07 - SDL Info (0): RTSP port: 48010
|
||||
00:00:07 - SDL Info (0): Initializing platform...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Resolving host name...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing audio stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:07 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:07 - SDL Info (0): Audio port: 48000
|
||||
00:00:07 - SDL Info (0): Video port: 47998
|
||||
00:00:07 - SDL Info (0): Control port: 47999
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing video stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting video stream...
|
||||
00:00:07 - SDL Info (0): Video stream is 2560x1440x30 (format 0x1)
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting audio stream...
|
||||
00:00:07 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:07 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:07 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:07 - SDL Info (0): SDL found matching display 0
|
||||
00:00:07 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:07 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:07 - SDL Info (0): V-sync disabled
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf96822d0] The input looks like it is Annex B already
|
||||
mpp[64569]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Wrote 390 bytes to decoder
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Received a frame
|
||||
00:00:08 - SDL Info (0): Not reusing test decoder for h264_rkmpp
|
||||
00:00:08 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:08 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:08 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:08 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Frame pacing disabled: target 60 Hz with 30 FPS stream
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf9fc4600] The input looks like it is Annex B already
|
||||
mpp[64569]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:08 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:08 - SDL Info (0): Renderer 'EGL/GLES' with 'DRM' backend chosen
|
||||
00:00:08 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:08 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Wrote 48152 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Wrote 15128 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Wrote 17880 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Wrote 16504 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf9493c60] Received a frame
|
||||
00:00:08 - SDL Info (0): EGLRenderer: EGLImage pixel format: 179
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_opaque.frag" at ":/data/egl_opaque.frag"
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_overlay.frag" at ":/data/egl_overlay.frag"
|
||||
00:02:50 - SDL Info (0): Detected quit key combo
|
||||
00:02:50 - SDL Info (0): Quit event received
|
||||
00:02:50 - SDL Info (0): Raising 3 keys
|
||||
00:02:50 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 25.52 FPS
|
||||
Decoding frame rate: 25.52 FPS
|
||||
Rendering frame rate: 25.45 FPS
|
||||
Host processing latency min/max/average: 34.0/127.9/45.4 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.10%
|
||||
Average network latency: 8 ms (variance: 4 ms)
|
||||
Average decoding time: 7.06 ms
|
||||
Average frame queue delay: 0.33 ms
|
||||
Average rendering time (including monitor V-sync latency): 1.91 ms
|
||||
00:02:50 - SDL Info (0): Stopping input stream...
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Stopping audio stream...
|
||||
00:02:50 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:02:50 - SDL Info (0): ENet wait interrupted
|
||||
00:02:50 - SDL Info (0): Control stream connection failed: 4
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Stopping video stream...
|
||||
00:02:50 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Stopping control stream...
|
||||
00:02:50 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:02:50 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Cleaning up input stream...
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Cleaning up video stream...
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Cleaning up control stream...
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Cleaning up audio stream...
|
||||
00:02:50 - SDL Info (0): done
|
||||
00:02:50 - SDL Info (0): Cleaning up platform...
|
||||
00:02:50 - SDL Info (0): done
|
||||
|
||||
[VDI launch]
|
||||
profile=low-latency
|
||||
program=/home/armbian/vdi-terminal/bin/vdi-moonlight-rkmpp
|
||||
decoder=hardware
|
||||
codec=H.264
|
||||
vsync=0
|
||||
frame-pacing=0
|
||||
renderer=opengles2
|
||||
video-driver=
|
||||
args=stream 192.168.1.70 Desktop --resolution 2560x1440 --fps 30 --bitrate 30000 --display-mode fullscreen --video-codec H.264 --video-decoder hardware --absolute-mouse --keep-awake --no-vsync --no-frame-pacing --audio-on-host
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.30.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.30.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:01 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:01 - SDL Info (0): SDL found matching display 0
|
||||
00:00:01 - Qt Info: Server GPU: ""
|
||||
00:00:01 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:02 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:02 - SDL Info (0): Audio channel count: 2
|
||||
00:00:02 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:02 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaae8148f80] The input looks like it is Annex B already
|
||||
mpp[66385]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaae859afc0] The input looks like it is Annex B already
|
||||
mpp[66385]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:03 - Qt Info: Gamepad mappings are up to date
|
||||
00:00:06 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:06 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:06 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=90dfc80ae65d4b1bb02c722d2a22325f&appid=881448767&mode=2560x1440x30&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=1&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:06 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:06 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:06 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:06 - Qt Info: Interface MTU: 1500
|
||||
00:00:06 - SDL Info (0): RTSP port: 48010
|
||||
00:00:06 - SDL Info (0): Initializing platform...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Resolving host name...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing audio stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:06 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:06 - SDL Info (0): Audio port: 48000
|
||||
00:00:06 - SDL Info (0): Video port: 47998
|
||||
00:00:06 - SDL Info (0): Control port: 47999
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing video stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting video stream...
|
||||
00:00:07 - SDL Info (0): Video stream is 2560x1440x30 (format 0x1)
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting audio stream...
|
||||
00:00:07 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:07 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:07 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:07 - SDL Info (0): SDL found matching display 0
|
||||
00:00:07 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:07 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:07 - SDL Info (0): V-sync disabled
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:07 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:07 - SDL Info (0): IDR frame request sent
|
||||
00:00:07 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaae89dd090] The input looks like it is Annex B already
|
||||
mpp[66385]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Received a frame
|
||||
00:00:08 - SDL Info (0): Not reusing test decoder for h264_rkmpp
|
||||
00:00:08 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:08 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:08 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:08 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Frame pacing disabled: target 60 Hz with 30 FPS stream
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
mpp[66385]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaae89d8820] The input looks like it is Annex B already
|
||||
00:00:08 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:08 - SDL Info (0): Renderer 'EGL/GLES' with 'DRM' backend chosen
|
||||
00:00:08 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:08 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 46776 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 11000 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Wrote 11000 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaae7adb140] Received a frame
|
||||
00:00:08 - SDL Info (0): EGLRenderer: EGLImage pixel format: 179
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_opaque.frag" at ":/data/egl_opaque.frag"
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_overlay.frag" at ":/data/egl_overlay.frag"
|
||||
BIN
docs/evidence/moonlight-20261102/kiosk-rkmpp-window-drag.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
docs/evidence/moonlight-20261102/low-latency-motion.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
249
docs/evidence/moonlight-20261102/low-latency-software.txt
Normal file
@ -0,0 +1,249 @@
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.33.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.33.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:01 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:01 - SDL Info (0): SDL found matching display 0
|
||||
00:00:01 - Qt Info: Server GPU: ""
|
||||
00:00:01 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:01 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:01 - SDL Info (0): Audio channel count: 2
|
||||
00:00:01 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:02 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Decoding VUI
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format drm_prime chosen by get_format().
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Invalid setup for format drm_prime: missing configuration.
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format drm_prime not usable, retrying get_format() without it.
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format yuv420p chosen by get_format().
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:02 - SDL Warn (0): EGLImage export requires hardware-backed frames
|
||||
00:00:02 - SDL Warn (0): Backend failed to export EGL image for test frame
|
||||
00:00:02 - SDL Warn (0): Test decode failed (testRenderFrame)
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Decoding VUI
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format yuv420p chosen by get_format().
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaaf2adf910] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - SDL Info (0): Encoder configured for 4 slices per frame
|
||||
00:00:02 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:02 - Qt Warning: 你选择的用于强制软件解码的设置可能会导致流式传输性能不佳。
|
||||
00:00:03 - Qt Info: Processing new PC "DESKTOP-Q072ICM.local." from mDNS with local address "192.168.1.70:47989"
|
||||
00:00:03 - Qt Info: Executing request: "http://192.168.1.70:47989/serverinfo?uniqueid=0123456789ABCDEF&uuid=ebc03298cf8c48b08710bdc9e8df351a"
|
||||
00:00:03 - Qt Info: Executing request: "https://192.168.1.70:47984/serverinfo?uniqueid=95da1945b8736669&uuid=81445f65f6e8426bbf57e183f3bda211"
|
||||
00:00:05 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:05 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
00:00:05 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=b788d125e836493a85f7eacede1e24eb&appid=881448767&mode=2560x1440x20&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=0&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:06 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:06 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:06 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:06 - Qt Info: Interface MTU: 1500
|
||||
00:00:06 - SDL Info (0): RTSP port: 48010
|
||||
00:00:06 - SDL Info (0): Initializing platform...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Resolving host name...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing audio stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:06 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:06 - SDL Info (0): Audio port: 48000
|
||||
00:00:06 - SDL Info (0): Video port: 47998
|
||||
00:00:06 - SDL Info (0): Control port: 47999
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing control stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing video stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing input stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting control stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting video stream...
|
||||
00:00:06 - SDL Info (0): Video stream is 2560x1440x20 (format 0x1)
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting audio stream...
|
||||
00:00:06 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:06 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:06 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:06 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting input stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Received first video packet after 100 ms
|
||||
00:00:06 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:06 - SDL Info (0): SDL found matching display 0
|
||||
00:00:06 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:07 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:07 - SDL Info (0): V-sync disabled
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:07 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:07 - SDL Info (0): IDR frame request sent
|
||||
00:00:07 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:07 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:07 - SDL Info (0): Frame pacing disabled: target 60 Hz with 20 FPS stream
|
||||
00:00:07 - SDL Info (0): Using DRM renderer
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Decoding VUI
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format drm_prime chosen by get_format().
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Invalid setup for format drm_prime: missing configuration.
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format drm_prime not usable, retrying get_format() without it.
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format yuv420p chosen by get_format().
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:07 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:07 - SDL Warn (0): EGLImage export requires hardware-backed frames
|
||||
00:00:07 - SDL Warn (0): Backend failed to export EGL image for test frame
|
||||
00:00:07 - SDL Warn (0): Test decode failed (testRenderFrame)
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): Frame pacing disabled: target 60 Hz with 20 FPS stream
|
||||
00:00:07 - SDL Info (0): SDL renderer backend: opengles2
|
||||
00:00:07 - SDL Info (0): SDL renderer backend requires main thread rendering
|
||||
00:00:07 - SDL Info (0): Using DRM renderer
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Decoding VUI
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format yuv420p chosen by get_format().
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaaf2adf910] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:08 - SDL Info (0): Test decode successful
|
||||
00:00:08 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:08 - SDL Info (0): Renderer 'SDL' with 'DRM' backend chosen
|
||||
00:00:08 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] Decoding VUI
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] Format yuvj420p chosen by get_format().
|
||||
00:00:08 - FFmpeg: [h264 @ 0xaaaaf2adf910] Reinit context to 2560x1440, pix_fmt: yuvj420p
|
||||
00:00:08 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:03:27 - SDL Info (0): Raising 3 keys
|
||||
00:03:27 - SDL Info (0): Detected quit key combo
|
||||
00:03:27 - SDL Info (0): Quit event received
|
||||
00:03:27 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 17.07 FPS
|
||||
Decoding frame rate: 17.07 FPS
|
||||
Rendering frame rate: 17.01 FPS
|
||||
Host processing latency min/max/average: 24.1/104.8/35.4 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.29%
|
||||
Average network latency: 11 ms (variance: 6 ms)
|
||||
Average decoding time: 16.96 ms
|
||||
Average frame queue delay: 1.14 ms
|
||||
Average rendering time (including monitor V-sync latency): 10.87 ms
|
||||
00:03:28 - SDL Info (0): Stopping input stream...
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Stopping audio stream...
|
||||
00:03:28 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:03:28 - SDL Info (0): ENet wait interrupted
|
||||
00:03:28 - SDL Info (0): Control stream connection failed: 4
|
||||
00:03:28 - Qt Info: Gamepad mappings are up to date
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Stopping video stream...
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Stopping control stream...
|
||||
00:03:28 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Cleaning up input stream...
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Cleaning up video stream...
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Cleaning up control stream...
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Cleaning up audio stream...
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - SDL Info (0): Cleaning up platform...
|
||||
00:03:28 - SDL Info (0): done
|
||||
00:03:28 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:03:28 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
237
docs/evidence/moonlight-20261102/rkmpp-egl-20-smooth.txt
Normal file
@ -0,0 +1,237 @@
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.30.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.30.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:02 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:02 - SDL Info (0): SDL found matching display 0
|
||||
00:00:02 - Qt Info: Server GPU: ""
|
||||
00:00:02 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:02 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:02 - SDL Info (0): Audio channel count: 2
|
||||
00:00:02 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:02 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaaea8769f0] The input looks like it is Annex B already
|
||||
mpp[51478]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Received a frame
|
||||
00:00:03 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:03 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:03 - SDL Info (0): V-sync disabled
|
||||
00:00:03 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:03 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:03 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:03 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:03 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:03 - SDL Info (0): Using DRM renderer
|
||||
00:00:03 - FFmpeg: [h264_mp4toannexb @ 0xaaaaea88ab90] The input looks like it is Annex B already
|
||||
mpp[51478]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Picked up an existing RKMPP hardware device
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Noticed an info change
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Received a frame
|
||||
00:00:03 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:03 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:03 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:03 - Qt Info: Processing new PC "DESKTOP-Q072ICM.local." from mDNS with local address "192.168.1.70:47989"
|
||||
00:00:03 - Qt Info: Executing request: "http://192.168.1.70:47989/serverinfo?uniqueid=0123456789ABCDEF&uuid=2c210dd36f6e44baaef56040d444099c"
|
||||
00:00:03 - Qt Info: Executing request: "https://192.168.1.70:47984/serverinfo?uniqueid=95da1945b8736669&uuid=5dc654e7557140c5ad4a28a3e0cbf0e7"
|
||||
00:00:05 - Qt Info: Gamepad mappings are up to date
|
||||
00:00:07 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:07 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:07 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=d326392167b5421ab723a1fd3511fae0&appid=881448767&mode=2560x1440x20&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=1&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:07 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:07 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:07 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:07 - Qt Info: Interface MTU: 1500
|
||||
00:00:07 - SDL Info (0): RTSP port: 48010
|
||||
00:00:07 - SDL Info (0): Initializing platform...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Resolving host name...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing audio stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:07 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:07 - SDL Info (0): Audio port: 48000
|
||||
00:00:07 - SDL Info (0): Video port: 47998
|
||||
00:00:07 - SDL Info (0): Control port: 47999
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing video stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting video stream...
|
||||
00:00:07 - SDL Info (0): Video stream is 2560x1440x20 (format 0x1)
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting audio stream...
|
||||
00:00:07 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:07 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:07 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:07 - SDL Info (0): SDL found matching display 0
|
||||
00:00:08 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:08 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:08 - SDL Info (0): V-sync enabled
|
||||
00:00:08 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:08 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:08 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:08 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaaeb135880] The input looks like it is Annex B already
|
||||
mpp[51478]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Noticed an info change
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 390 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Received a frame
|
||||
00:00:09 - SDL Info (0): Not reusing test decoder for h264_rkmpp
|
||||
00:00:09 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:09 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:09 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:09 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:09 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:09 - SDL Info (0): Frame pacing: target 60 Hz with 20 FPS stream
|
||||
00:00:09 - SDL Info (0): Using DRM renderer
|
||||
00:00:09 - FFmpeg: [h264_mp4toannexb @ 0xaaaaeaef0980] The input looks like it is Annex B already
|
||||
mpp[51478]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:09 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Picked up an existing RKMPP hardware device
|
||||
00:00:09 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:09 - SDL Info (0): Renderer 'EGL/GLES' with 'DRM' backend chosen
|
||||
00:00:09 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:09 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 55032 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 13752 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 19256 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Wrote 15128 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Noticed an info change
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:09 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:09 - SDL Info (0): IDR frame request sent
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaea1ff9d0] Received a frame
|
||||
00:00:09 - SDL Info (0): EGLRenderer: EGLImage pixel format: 179
|
||||
00:00:09 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:09 - Qt Info: Found "egl_opaque.frag" at ":/data/egl_opaque.frag"
|
||||
00:00:09 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:09 - Qt Info: Found "egl_overlay.frag" at ":/data/egl_overlay.frag"
|
||||
00:02:21 - SDL Info (0): Raising 3 keys
|
||||
00:02:21 - SDL Info (0): Detected quit key combo
|
||||
00:02:21 - SDL Info (0): Quit event received
|
||||
00:02:21 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 19.14 FPS
|
||||
Decoding frame rate: 19.14 FPS
|
||||
Rendering frame rate: 18.97 FPS
|
||||
Host processing latency min/max/average: 26.6/104.7/38.4 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.20%
|
||||
Average network latency: 8 ms (variance: 8 ms)
|
||||
Average decoding time: 10.53 ms
|
||||
Average frame queue delay: 2.78 ms
|
||||
Average rendering time (including monitor V-sync latency): 2.54 ms
|
||||
00:02:21 - SDL Info (0): Stopping input stream...
|
||||
00:02:21 - Qt Info: Latest supported GFE server: "99.99.99.99"
|
||||
00:02:21 - SDL Info (0): ENet wait interrupted
|
||||
00:02:21 - SDL Info (0): Control stream connection failed: 4
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Stopping audio stream...
|
||||
00:02:21 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Stopping video stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Stopping control stream...
|
||||
00:02:21 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:02:21 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:02:21 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up input stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up video stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up control stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up audio stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up platform...
|
||||
00:02:21 - SDL Info (0): done
|
||||
|
After Width: | Height: | Size: 134 KiB |
240
docs/evidence/moonlight-20261102/rkmpp-egl-30-lowlatency.txt
Normal file
@ -0,0 +1,240 @@
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.30.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.30.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:02 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:02 - SDL Info (0): SDL found matching display 0
|
||||
00:00:02 - Qt Info: Server GPU: ""
|
||||
00:00:02 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:02 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:02 - SDL Info (0): Audio channel count: 2
|
||||
00:00:02 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:02 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf99a27a0] The input looks like it is Annex B already
|
||||
mpp[54250]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf995fa90] The input looks like it is Annex B already
|
||||
mpp[54250]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaaf92e8420] Received a frame
|
||||
00:00:03 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:03 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:03 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:03 - Qt Info: Processing new PC "DESKTOP-Q072ICM.local." from mDNS with local address "192.168.1.70:47989"
|
||||
00:00:03 - Qt Info: Executing request: "http://192.168.1.70:47989/serverinfo?uniqueid=0123456789ABCDEF&uuid=384e05c9dbdc467aa7c65964c14160df"
|
||||
00:00:03 - Qt Info: Executing request: "https://192.168.1.70:47984/serverinfo?uniqueid=95da1945b8736669&uuid=3a95f785091741c090fdffd7d56979e7"
|
||||
00:00:04 - Qt Info: Gamepad mappings are up to date
|
||||
00:00:06 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:06 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:06 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=b7dffe4902d54022a33fa19a3cf2b331&appid=881448767&mode=2560x1440x30&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=1&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:07 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:07 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:07 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:07 - Qt Info: Interface MTU: 1500
|
||||
00:00:07 - SDL Info (0): RTSP port: 48010
|
||||
00:00:07 - SDL Info (0): Initializing platform...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Resolving host name...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing audio stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:07 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:07 - SDL Info (0): Audio port: 48000
|
||||
00:00:07 - SDL Info (0): Video port: 47998
|
||||
00:00:07 - SDL Info (0): Control port: 47999
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing video stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting video stream...
|
||||
00:00:07 - SDL Info (0): Video stream is 2560x1440x30 (format 0x1)
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting audio stream...
|
||||
00:00:07 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:07 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:07 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:07 - SDL Info (0): SDL found matching display 0
|
||||
00:00:07 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:08 - SDL Info (0): V-sync disabled
|
||||
00:00:08 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:08 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:08 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:08 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf96e2d90] The input looks like it is Annex B already
|
||||
mpp[54250]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Wrote 390 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Wrote 390 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Noticed an info change
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Wrote 390 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Received a frame
|
||||
00:00:09 - SDL Info (0): Not reusing test decoder for h264_rkmpp
|
||||
00:00:09 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:09 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:09 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:09 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:09 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:09 - SDL Info (0): Frame pacing disabled: target 60 Hz with 30 FPS stream
|
||||
00:00:09 - SDL Info (0): Using DRM renderer
|
||||
00:00:09 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf96f1610] The input looks like it is Annex B already
|
||||
mpp[54250]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Picked up an existing RKMPP hardware device
|
||||
00:00:09 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:09 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:09 - SDL Info (0): Renderer 'EGL/GLES' with 'DRM' backend chosen
|
||||
00:00:09 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:09 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Wrote 46776 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Wrote 19256 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Wrote 15128 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Wrote 16504 bytes to decoder
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Noticed an info change
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:09 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:09 - SDL Info (0): IDR frame request sent
|
||||
00:00:09 - FFmpeg: [h264_rkmpp @ 0xaaaaf99a26d0] Received a frame
|
||||
00:00:09 - SDL Info (0): EGLRenderer: EGLImage pixel format: 179
|
||||
00:00:09 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:09 - Qt Info: Found "egl_opaque.frag" at ":/data/egl_opaque.frag"
|
||||
00:00:09 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:09 - Qt Info: Found "egl_overlay.frag" at ":/data/egl_overlay.frag"
|
||||
00:02:20 - SDL Info (0): Detected quit key combo
|
||||
00:02:20 - SDL Info (0): Quit event received
|
||||
00:02:20 - SDL Info (0): Raising 3 keys
|
||||
00:02:20 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 23.56 FPS
|
||||
Decoding frame rate: 23.56 FPS
|
||||
Rendering frame rate: 23.46 FPS
|
||||
Host processing latency min/max/average: 29.7/145.8/46.8 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.10%
|
||||
Average network latency: 4 ms (variance: 2 ms)
|
||||
Average decoding time: 9.11 ms
|
||||
Average frame queue delay: 2.39 ms
|
||||
Average rendering time (including monitor V-sync latency): 5.41 ms
|
||||
00:02:20 - SDL Info (0): Stopping input stream...
|
||||
00:02:20 - SDL Info (0): done
|
||||
00:02:20 - Qt Info: Latest supported GFE server: "99.99.99.99"
|
||||
00:02:20 - SDL Info (0): Stopping audio stream...
|
||||
00:02:20 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:02:20 - SDL Info (0): ENet wait interrupted
|
||||
00:02:20 - SDL Info (0): Control stream connection failed: 4
|
||||
00:02:20 - SDL Info (0): done
|
||||
00:02:20 - SDL Info (0): Stopping video stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Stopping control stream...
|
||||
00:02:21 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:02:21 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:02:21 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up input stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up video stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up control stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up audio stream...
|
||||
00:02:21 - SDL Info (0): done
|
||||
00:02:21 - SDL Info (0): Cleaning up platform...
|
||||
00:02:21 - SDL Info (0): done
|
||||
BIN
docs/evidence/moonlight-20261102/rkmpp-egl-30-motion.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 130 KiB |
240
docs/evidence/moonlight-20261102/rkmpp-egl-30-smooth.txt
Normal file
@ -0,0 +1,240 @@
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.30.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.30.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:01 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:01 - SDL Info (0): SDL found matching display 0
|
||||
00:00:01 - Qt Info: Server GPU: ""
|
||||
00:00:01 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:01 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:01 - SDL Info (0): Audio channel count: 2
|
||||
00:00:01 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:02 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaaefd8db30] The input looks like it is Annex B already
|
||||
mpp[52715]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaaf01e0290] The input looks like it is Annex B already
|
||||
mpp[52715]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:03 - Qt Info: Processing new PC "DESKTOP-Q072ICM.local." from mDNS with local address "192.168.1.70:47989"
|
||||
00:00:03 - Qt Info: Executing request: "http://192.168.1.70:47989/serverinfo?uniqueid=0123456789ABCDEF&uuid=bde19ca4ac6f4527a834eac086ade60d"
|
||||
00:00:03 - Qt Info: Executing request: "https://192.168.1.70:47984/serverinfo?uniqueid=95da1945b8736669&uuid=29837995715346aea2f683aa39046423"
|
||||
00:00:05 - Qt Info: Latest supported GFE server: "99.99.99.99"
|
||||
00:00:06 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:06 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:06 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=910b4365f6664f5a894c7e3a58542e6c&appid=881448767&mode=2560x1440x30&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=1&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:06 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:06 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:06 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:06 - Qt Info: Interface MTU: 1500
|
||||
00:00:06 - SDL Info (0): RTSP port: 48010
|
||||
00:00:06 - SDL Info (0): Initializing platform...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Resolving host name...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing audio stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:06 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:06 - SDL Info (0): Audio port: 48000
|
||||
00:00:06 - SDL Info (0): Video port: 47998
|
||||
00:00:06 - SDL Info (0): Control port: 47999
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing video stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting video stream...
|
||||
00:00:07 - SDL Info (0): Video stream is 2560x1440x30 (format 0x1)
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting audio stream...
|
||||
00:00:07 - Qt Info: Gamepad mappings are up to date
|
||||
00:00:07 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:07 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:07 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:07 - SDL Info (0): SDL found matching display 0
|
||||
00:00:07 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:07 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:07 - SDL Info (0): IDR frame request sent
|
||||
00:00:07 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:07 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:07 - SDL Info (0): V-sync enabled
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaaefcb7f90] The input looks like it is Annex B already
|
||||
mpp[52715]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Received a frame
|
||||
00:00:08 - SDL Info (0): Not reusing test decoder for h264_rkmpp
|
||||
00:00:08 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:08 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:08 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:08 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Frame pacing: target 60 Hz with 30 FPS stream
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaaefca77e0] The input looks like it is Annex B already
|
||||
mpp[52715]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:08 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:08 - SDL Info (0): Renderer 'EGL/GLES' with 'DRM' backend chosen
|
||||
00:00:08 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:08 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Wrote 53656 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaaef6fce10] Received a frame
|
||||
00:00:08 - SDL Info (0): EGLRenderer: EGLImage pixel format: 179
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_opaque.frag" at ":/data/egl_opaque.frag"
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_overlay.frag" at ":/data/egl_overlay.frag"
|
||||
00:02:26 - SDL Info (0): Raising 3 keys
|
||||
00:02:26 - SDL Info (0): Detected quit key combo
|
||||
00:02:26 - SDL Info (0): Quit event received
|
||||
00:02:26 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 24.21 FPS
|
||||
Decoding frame rate: 24.21 FPS
|
||||
Rendering frame rate: 23.29 FPS
|
||||
Host processing latency min/max/average: 24.8/86.1/46.2 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 3.02%
|
||||
Average network latency: 9 ms (variance: 6 ms)
|
||||
Average decoding time: 8.24 ms
|
||||
Average frame queue delay: 31.95 ms
|
||||
Average rendering time (including monitor V-sync latency): 4.19 ms
|
||||
00:02:26 - SDL Info (0): Stopping input stream...
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Stopping audio stream...
|
||||
00:02:26 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:02:26 - SDL Info (0): ENet wait interrupted
|
||||
00:02:26 - SDL Info (0): Control stream connection failed: 4
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Stopping video stream...
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Stopping control stream...
|
||||
00:02:26 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Cleaning up input stream...
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Cleaning up video stream...
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Cleaning up control stream...
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Cleaning up audio stream...
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - SDL Info (0): Cleaning up platform...
|
||||
00:02:26 - SDL Info (0): done
|
||||
00:02:26 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:02:26 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
@ -0,0 +1,240 @@
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.30.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.30.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:02 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:02 - SDL Info (0): SDL found matching display 0
|
||||
00:00:02 - Qt Info: Server GPU: ""
|
||||
00:00:02 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:02 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:02 - SDL Info (0): Audio channel count: 2
|
||||
00:00:02 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:02 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:02 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaac0ba40c0] The input looks like it is Annex B already
|
||||
mpp[56346]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264_mp4toannexb @ 0xaaaac0c0e890] The input looks like it is Annex B already
|
||||
mpp[56346]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Picked up an existing RKMPP hardware device
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Noticed an info change
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:02 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Received a frame
|
||||
00:00:02 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:03 - Qt Info: Processing new PC "DESKTOP-Q072ICM.local." from mDNS with local address "192.168.1.70:47989"
|
||||
00:00:03 - Qt Info: Executing request: "http://192.168.1.70:47989/serverinfo?uniqueid=0123456789ABCDEF&uuid=60ec9920646340b7a621736f9ae3ef0f"
|
||||
00:00:03 - Qt Info: Executing request: "https://192.168.1.70:47984/serverinfo?uniqueid=95da1945b8736669&uuid=9ff5b4f5a4e34249a2e35f84ea1114b4"
|
||||
00:00:05 - Qt Info: Latest supported GFE server: "99.99.99.99"
|
||||
00:00:06 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:06 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:06 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=1217e2a33f3e46c282856a4e5d12ee0d&appid=881448767&mode=2560x1440x30&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=1&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:06 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:06 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:06 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:06 - Qt Info: Interface MTU: 1500
|
||||
00:00:06 - SDL Info (0): RTSP port: 48010
|
||||
00:00:06 - SDL Info (0): Initializing platform...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Resolving host name...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing audio stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:07 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:07 - SDL Info (0): Audio port: 48000
|
||||
00:00:07 - SDL Info (0): Video port: 47998
|
||||
00:00:07 - SDL Info (0): Control port: 47999
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing video stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Initializing input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting control stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting video stream...
|
||||
00:00:07 - SDL Info (0): Video stream is 2560x1440x30 (format 0x1)
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting audio stream...
|
||||
00:00:07 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:07 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:07 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Starting input stream...
|
||||
00:00:07 - SDL Info (0): done
|
||||
00:00:07 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:07 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:07 - SDL Info (0): SDL found matching display 0
|
||||
00:00:07 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:07 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:07 - SDL Info (0): V-sync enabled
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:07 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:07 - SDL Info (0): IDR frame request sent
|
||||
00:00:07 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
mpp[56346]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaac1032530] The input looks like it is Annex B already
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:08 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 390 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Received a frame
|
||||
00:00:08 - SDL Info (0): Not reusing test decoder for h264_rkmpp
|
||||
00:00:08 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:08 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:08 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:08 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:08 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:08 - SDL Info (0): Frame pacing disabled: target 60 Hz with 30 FPS stream
|
||||
00:00:08 - SDL Info (0): Using DRM renderer
|
||||
00:00:08 - FFmpeg: [h264_mp4toannexb @ 0xaaaac0ee99b0] The input looks like it is Annex B already
|
||||
mpp[56346]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Picked up an existing RKMPP hardware device
|
||||
00:00:08 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:08 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:08 - SDL Info (0): Renderer 'EGL/GLES' with 'DRM' backend chosen
|
||||
00:00:08 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:08 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 45400 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 15128 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 15128 bytes to decoder
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Noticed an info change
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Wrote 15128 bytes to decoder
|
||||
00:00:08 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:08 - SDL Info (0): IDR frame request sent
|
||||
00:00:08 - FFmpeg: [h264_rkmpp @ 0xaaaac0530820] Received a frame
|
||||
00:00:08 - SDL Info (0): EGLRenderer: EGLImage pixel format: 179
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_opaque.frag" at ":/data/egl_opaque.frag"
|
||||
00:00:08 - Qt Info: Found "egl.vert" at ":/data/egl.vert"
|
||||
00:00:08 - Qt Info: Found "egl_overlay.frag" at ":/data/egl_overlay.frag"
|
||||
00:02:33 - SDL Info (0): Raising 3 keys
|
||||
00:02:33 - SDL Info (0): Detected quit key combo
|
||||
00:02:33 - SDL Info (0): Quit event received
|
||||
00:02:33 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 23.26 FPS
|
||||
Decoding frame rate: 23.26 FPS
|
||||
Rendering frame rate: 22.63 FPS
|
||||
Host processing latency min/max/average: 34.4/110.6/47.5 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 2.23%
|
||||
Average network latency: 13 ms (variance: 8 ms)
|
||||
Average decoding time: 8.28 ms
|
||||
Average frame queue delay: 28.93 ms
|
||||
Average rendering time (including monitor V-sync latency): 4.14 ms
|
||||
00:02:34 - Qt Info: Gamepad mappings are up to date
|
||||
00:02:34 - SDL Info (0): Stopping input stream...
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Stopping audio stream...
|
||||
00:02:34 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:02:34 - SDL Info (0): ENet wait interrupted
|
||||
00:02:34 - SDL Info (0): Control stream connection failed: 4
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Stopping video stream...
|
||||
00:02:34 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:02:34 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Stopping control stream...
|
||||
00:02:34 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Cleaning up input stream...
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Cleaning up video stream...
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Cleaning up control stream...
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Cleaning up audio stream...
|
||||
00:02:34 - SDL Info (0): done
|
||||
00:02:34 - SDL Info (0): Cleaning up platform...
|
||||
00:02:34 - SDL Info (0): done
|
||||
BIN
docs/evidence/moonlight-20261102/rkmpp-egl-motion.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
docs/evidence/moonlight-20261102/rkmpp-first.png
Normal file
|
After Width: | Height: | Size: 2.8 MiB |
300
docs/evidence/moonlight-20261102/rkmpp-stale-sdl.txt
Normal file
@ -0,0 +1,300 @@
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.30.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.30.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:01 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-error_outline-24px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-help_outline-24px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-error_outline-24px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-error_outline-24px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-error_outline-24px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-error_outline-24px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/ic_videogame_asset_white_48px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/update.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/ic_add_to_queue_white_48px.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/discord.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/arrow_left.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/settings.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/question_mark.svg: Unsupported image format
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:02 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-help_outline-24px.svg: Unsupported image format
|
||||
00:00:02 - Qt Warning: qrc:/gui/NavigableMessageDialog.qml:32:9: QML Image: Error decoding: qrc:/res/baseline-error_outline-24px.svg: Unsupported image format
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:02 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:02 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:02 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:02 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:02 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/arrow_left.svg: Unsupported image format
|
||||
00:00:02 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/arrow_left.svg: Unsupported image format
|
||||
00:00:02 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/arrow_left.svg: Unsupported image format
|
||||
00:00:02 - Qt Warning: file:///home/armbian/vdi-build/rkmpp-experiment/deps/usr/lib/aarch64-linux-gnu/qt5/qml/QtQuick/Controls.2/Material/ToolButton.qml: QML IconImage: Error decoding: qrc:/res/arrow_left.svg: Unsupported image format
|
||||
00:00:02 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:03 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:03 - SDL Info (0): SDL found matching display 0
|
||||
00:00:03 - Qt Info: Server GPU: ""
|
||||
00:00:03 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:03 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:03 - SDL Info (0): Audio channel count: 2
|
||||
00:00:03 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:03 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:03 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:03 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:03 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:03 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:03 - SDL Info (0): V-sync disabled
|
||||
00:00:03 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:03 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:03 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:03 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:03 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:03 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:03 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:03 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:03 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:03 - SDL Info (0): Using DRM renderer
|
||||
00:00:03 - FFmpeg: [h264_mp4toannexb @ 0xaaaacc36b700] The input looks like it is Annex B already
|
||||
mpp[44667]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Picked up an existing RKMPP hardware device
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Noticed an info change
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Received a frame
|
||||
00:00:03 - SDL Info (0): Selected hwframe->swframe format: 23 (mapping: yes)
|
||||
00:00:03 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:03 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:03 - SDL Info (0): V-sync disabled
|
||||
00:00:03 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:03 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:03 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:03 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:03 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:03 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:03 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:03 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:03 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:03 - SDL Info (0): Using DRM renderer
|
||||
00:00:03 - FFmpeg: [h264_mp4toannexb @ 0xaaaacc3369a0] The input looks like it is Annex B already
|
||||
mpp[44667]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Picked up an existing RKMPP hardware device
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Noticed an info change
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:03 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Received a frame
|
||||
00:00:03 - SDL Info (0): Selected hwframe->swframe format: 23 (mapping: yes)
|
||||
00:00:03 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:03 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:03 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:05 - Qt Info: Gamepad mappings are up to date
|
||||
00:00:06 - Qt Info: Processing new PC "DESKTOP-Q072ICM.local." from mDNS with local address "192.168.1.70:47989"
|
||||
00:00:06 - Qt Info: Executing request: "http://192.168.1.70:47989/serverinfo?uniqueid=0123456789ABCDEF&uuid=38035ae211ee431ab78b9142e0450ce3"
|
||||
00:00:06 - Qt Info: Executing request: "https://192.168.1.70:47984/serverinfo?uniqueid=95da1945b8736669&uuid=3f6cd9485a3b4e4c92fe07f7076ea0cf"
|
||||
00:00:08 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:08 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:00:08 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=21acc81568604fefac1fa259037e9792&appid=881448767&mode=2560x1440x20&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=1&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:08 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:08 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:08 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:08 - Qt Info: Interface MTU: 1500
|
||||
00:00:08 - SDL Info (0): RTSP port: 48010
|
||||
00:00:08 - SDL Info (0): Initializing platform...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Resolving host name...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Initializing audio stream...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:08 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:08 - SDL Info (0): Audio port: 48000
|
||||
00:00:08 - SDL Info (0): Video port: 47998
|
||||
00:00:08 - SDL Info (0): Control port: 47999
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Initializing control stream...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Initializing video stream...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Initializing input stream...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Starting control stream...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Starting video stream...
|
||||
00:00:08 - SDL Info (0): Video stream is 2560x1440x20 (format 0x1)
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Starting audio stream...
|
||||
00:00:08 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:08 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:08 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:08 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:08 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:08 - SDL Info (0): Starting input stream...
|
||||
00:00:08 - SDL Info (0): done
|
||||
00:00:09 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:09 - SDL Info (0): SDL found matching display 0
|
||||
00:00:09 - SDL Info (0): Found display mode with video resolution: 2560x1440x60
|
||||
00:00:09 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:09 - SDL Info (0): IDR frame request sent
|
||||
00:00:09 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:11 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:11 - SDL Info (0): IDR frame request sent
|
||||
00:00:11 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:13 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:13 - SDL Info (0): IDR frame request sent
|
||||
00:00:13 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:14 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:14 - SDL Info (0): V-sync enabled
|
||||
00:00:14 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:14 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:14 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:14 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:14 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:14 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:14 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:14 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:14 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:15 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:15 - SDL Info (0): IDR frame request sent
|
||||
00:00:15 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:15 - SDL Info (0): Using DRM renderer
|
||||
00:00:15 - FFmpeg: [h264_mp4toannexb @ 0xaaaacc468440] The input looks like it is Annex B already
|
||||
mpp[44667]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:15 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Picked up an existing RKMPP hardware device
|
||||
00:00:15 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:15 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:15 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Noticed an info change
|
||||
00:00:15 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:15 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Configured with size: 1280x720 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 390 bytes to decoder
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Received a frame
|
||||
00:00:16 - SDL Info (0): Selected hwframe->swframe format: 23 (mapping: yes)
|
||||
00:00:16 - SDL Info (0): Not reusing test decoder for h264_rkmpp
|
||||
00:00:16 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:16 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:16 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:16 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:16 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:16 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
mpp[44667]: mpp_info: mpp version: 7916c3c author: Xiaoxu Chen 2026-10-28 fix[utils]: Fix AVC cu_map allocation stride
|
||||
00:00:16 - SDL Info (0): Frame pacing: target 60 Hz with 20 FPS stream
|
||||
00:00:16 - SDL Info (0): SDL renderer backend: opengles2
|
||||
00:00:16 - SDL Info (0): SDL renderer backend requires main thread rendering
|
||||
00:00:16 - SDL Info (0): Using DRM renderer
|
||||
00:00:16 - FFmpeg: [h264_mp4toannexb @ 0xaaaaccea90d0] The input looks like it is Annex B already
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Picked up an existing RKMPP hardware device
|
||||
00:00:16 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:16 - SDL Info (0): Renderer 'SDL' with 'DRM' backend chosen
|
||||
00:00:16 - SDL Warn (0): Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp
|
||||
00:00:16 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 184376 bytes to decoder
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Noticed an info change
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Decoder options: deint=true afbc=0 fast_parse=true buf_mode=0
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Configured with size: 2560x1440 | pix_fmt: drm_prime | sw_pix_fmt: nv12
|
||||
00:00:16 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:16 - SDL Info (0): IDR frame request sent
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 77048 bytes to decoder
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 101816 bytes to decoder
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Wrote 129336 bytes to decoder
|
||||
00:00:16 - FFmpeg: [h264_rkmpp @ 0xaaaacb767aa0] Received a frame
|
||||
00:00:16 - SDL Info (0): Selected hwframe->swframe format: 23 (mapping: yes)
|
||||
00:02:40 - SDL Info (0): Raising 3 keys
|
||||
00:02:40 - SDL Info (0): Detected quit key combo
|
||||
00:02:40 - SDL Info (0): Quit event received
|
||||
00:02:40 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 8.72 FPS
|
||||
Decoding frame rate: 8.72 FPS
|
||||
Rendering frame rate: 8.61 FPS
|
||||
Host processing latency min/max/average: 25.8/35.9/30.7 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.24%
|
||||
Average network latency: 2 ms (variance: 0 ms)
|
||||
Average decoding time: 16.89 ms
|
||||
Average frame queue delay: 1.07 ms
|
||||
Average rendering time (including monitor V-sync latency): 44.80 ms
|
||||
00:02:40 - SDL Info (0): Stopping input stream...
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Stopping audio stream...
|
||||
00:02:40 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:02:40 - SDL Info (0): ENet wait interrupted
|
||||
00:02:40 - SDL Info (0): Control stream connection failed: 4
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Stopping video stream...
|
||||
00:02:40 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:02:40 - SDL Info (0): Loaded 436 new gamepad mappings
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Stopping control stream...
|
||||
00:02:40 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Cleaning up input stream...
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Cleaning up video stream...
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Cleaning up control stream...
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Cleaning up audio stream...
|
||||
00:02:40 - SDL Info (0): done
|
||||
00:02:40 - SDL Info (0): Cleaning up platform...
|
||||
00:02:40 - SDL Info (0): done
|
||||
BIN
docs/evidence/moonlight-20261102/smooth-motion.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
250
docs/evidence/moonlight-20261102/smooth-software.txt
Normal file
@ -0,0 +1,250 @@
|
||||
00:00:00 - SDL Info (0): Compiled with SDL 2.33.0
|
||||
00:00:00 - SDL Info (0): Running with SDL 2.33.0
|
||||
00:00:00 - Qt Info: Successfully loaded translation for "zh_CN"
|
||||
00:00:00 - Qt Info: Loaded unique ID from settings: "95da1945b8736669"
|
||||
00:00:00 - Qt Warning: qrc:/gui/main.qml:13:1: QML ApplicationWindow: ToolTip must be attached to an Item
|
||||
00:00:01 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:01 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 192.168.1.70:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 255.255.255.255:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via 60.21.96.193:48010
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:9
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47009
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47998
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:47999
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48000
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48002
|
||||
00:00:01 - Qt Info: Sent WoL packet to DESKTOP-Q072ICM via ff02::1%wlan0:48010
|
||||
00:00:01 - Qt Debug: Current Moonlight version: "6.2.0"
|
||||
00:00:01 - Qt Info: "DESKTOP-Q072ICM" is now online at "192.168.1.70:47989"
|
||||
00:00:01 - Qt Info: Found "ModeSeven.ttf" at ":/data/ModeSeven.ttf"
|
||||
00:00:01 - Qt Info: Discovered mDNS host: "DESKTOP-Q072ICM.local."
|
||||
00:00:01 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:01 - SDL Info (0): SDL found matching display 0
|
||||
00:00:01 - Qt Info: Server GPU: ""
|
||||
00:00:01 - Qt Info: Server GFE version: "3.23.0.74"
|
||||
00:00:01 - SDL Info (0): Video bitrate: 30000 kbps
|
||||
00:00:01 - SDL Info (0): Audio channel count: 2
|
||||
00:00:01 - SDL Info (0): Audio channel mask: 3
|
||||
00:00:01 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:01 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:01 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:02 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:02 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
00:00:02 - SDL Info (0): V-sync disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:02 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Decoding VUI
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format drm_prime chosen by get_format().
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Invalid setup for format drm_prime: missing configuration.
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format drm_prime not usable, retrying get_format() without it.
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format yuv420p chosen by get_format().
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:02 - SDL Warn (0): EGLImage export requires hardware-backed frames
|
||||
00:00:02 - SDL Warn (0): Backend failed to export EGL image for test frame
|
||||
00:00:02 - SDL Warn (0): Test decode failed (testRenderFrame)
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:02 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:02 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:02 - SDL Info (0): Using DRM renderer
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Decoding VUI
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format yuv420p chosen by get_format().
|
||||
00:00:02 - FFmpeg: [h264 @ 0xaaaabb28ac40] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:02 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:02 - SDL Info (0): Encoder configured for 4 slices per frame
|
||||
00:00:02 - Qt Warning: 启用远程桌面鼠标模式可能会导致游戏出现问题。
|
||||
00:00:02 - Qt Warning: 你选择的用于强制软件解码的设置可能会导致流式传输性能不佳。
|
||||
00:00:03 - Qt Info: Processing new PC "DESKTOP-Q072ICM.local." from mDNS with local address "192.168.1.70:47989"
|
||||
00:00:03 - Qt Info: Executing request: "http://192.168.1.70:47989/serverinfo?uniqueid=0123456789ABCDEF&uuid=6962458dceb442b4b6bd8028e70a3b36"
|
||||
00:00:03 - Qt Info: Executing request: "https://192.168.1.70:47984/serverinfo?uniqueid=95da1945b8736669&uuid=24015164fe774f5790b5e26dcbdac0a3"
|
||||
00:00:04 - Qt Info: Gamepad mappings are up to date
|
||||
00:00:05 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:00:05 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
00:00:05 - Qt Info: Executing request: "https://192.168.1.70:47984/resume?uniqueid=95da1945b8736669&uuid=49737f9390044dc28228a93b794837cb&appid=881448767&mode=2560x1440x20&additionalStates=1&sops=1&rikey=REDACTED&rikeyid=REDACTED&localAudioPlayMode=0&surroundAudioInfo=196610&remoteControllersBitmap=0&gcmap=0&gcpersist=0&corever=1"
|
||||
00:00:06 - Qt Info: Launch response: "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<root status_code=\"200\"><sessionUrl0>rtspenc://192.168.1.70:48010</sessionUrl0><resume>1</resume></root>"
|
||||
00:00:06 - Qt Info: Found matching interface: "wlan0" "88:00:33:77:30:B6" QFlags<QNetworkInterface::InterfaceFlag>(IsUp|IsRunning|CanBroadcast|CanMulticast)
|
||||
00:00:06 - Qt Info: Interface Type: QNetworkInterface::Wifi
|
||||
00:00:06 - Qt Info: Interface MTU: 1500
|
||||
00:00:06 - SDL Info (0): RTSP port: 48010
|
||||
00:00:06 - SDL Info (0): Initializing platform...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Resolving host name...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing audio stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting RTSP handshake...
|
||||
00:00:06 - SDL Info (0): Reference frame invalidation is not supported by this host
|
||||
00:00:06 - SDL Info (0): Audio port: 48000
|
||||
00:00:06 - SDL Info (0): Video port: 47998
|
||||
00:00:06 - SDL Info (0): Control port: 47999
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing control stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing video stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Initializing input stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting control stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting video stream...
|
||||
00:00:06 - SDL Info (0): Video stream is 2560x1440x20 (format 0x1)
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting audio stream...
|
||||
00:00:06 - SDL Info (0): Desired audio buffer: 720 samples (5760 bytes)
|
||||
00:00:06 - SDL Info (0): Obtained audio buffer: 720 samples (5760 bytes)
|
||||
00:00:06 - SDL Info (0): SDL audio driver: pulseaudio
|
||||
00:00:06 - SDL Info (0): Received first video packet after 0 ms
|
||||
00:00:06 - SDL Info (0): Audio stream has 2 channels
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Starting input stream...
|
||||
00:00:06 - SDL Info (0): done
|
||||
00:00:06 - SDL Info (0): Qt UI screen is at (0,0)
|
||||
00:00:06 - SDL Info (0): SDL found matching display 0
|
||||
00:00:06 - SDL Info (0): Found display mode with desktop resolution: 2560x1440x60
|
||||
00:00:06 - SDL Info (0): Recreating renderer for window event: 1 (0 0)
|
||||
00:00:06 - SDL Info (0): V-sync enabled
|
||||
00:00:06 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:06 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:06 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:06 - SDL Info (0): DRM backend supports exporting EGLImage
|
||||
00:00:07 - SDL Info (0): Video decode unit queue overflow
|
||||
00:00:07 - SDL Info (0): IDR frame request sent
|
||||
00:00:07 - SDL Info (0): Waiting for IDR frame
|
||||
00:00:07 - SDL Info (0): Color buffer is: R8G8B8A0
|
||||
00:00:07 - SDL Info (0): Frame pacing: target 60 Hz with 20 FPS stream
|
||||
00:00:07 - SDL Info (0): Using DRM renderer
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Decoding VUI
|
||||
00:00:07 - SDL Warn (0): Unable to set render thread to high priority: setpriority() failed
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format drm_prime chosen by get_format().
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Invalid setup for format drm_prime: missing configuration.
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format drm_prime not usable, retrying get_format() without it.
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format yuv420p chosen by get_format().
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:07 - SDL Warn (0): EGLImage export requires hardware-backed frames
|
||||
00:00:07 - SDL Warn (0): Backend failed to export EGL image for test frame
|
||||
00:00:07 - SDL Warn (0): Test decode failed (testRenderFrame)
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): Opened DRM render node: /dev/dri/renderD128
|
||||
00:00:07 - SDL Info (0): GPU driver: rockchip
|
||||
00:00:07 - SDL Info (0): Direct rendering via DRM is disabled
|
||||
00:00:07 - SDL Info (0): Frame pacing: target 60 Hz with 20 FPS stream
|
||||
00:00:07 - SDL Info (0): SDL renderer backend: opengles2
|
||||
00:00:07 - SDL Info (0): SDL renderer backend requires main thread rendering
|
||||
00:00:07 - SDL Info (0): Using DRM renderer
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Decoding VUI
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format yuv420p chosen by get_format().
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Reinit context to 1280x720, pix_fmt: yuv420p
|
||||
00:00:07 - SDL Info (0): Test decode successful
|
||||
00:00:07 - SDL Info (0): Using H.264 SPS fixup
|
||||
00:00:07 - SDL Info (0): Renderer 'SDL' with 'DRM' backend chosen
|
||||
00:00:07 - SDL Info (0): FFmpeg-based video decoder chosen
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 7(SPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 8(PPS), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] nal_unit_type: 5(IDR), nal_ref_idc: 3
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Decoding VUI
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Format yuvj420p chosen by get_format().
|
||||
00:00:07 - FFmpeg: [h264 @ 0xaaaabb28ac40] Reinit context to 2560x1440, pix_fmt: yuvj420p
|
||||
00:00:07 - SDL Info (0): Dropping window event during flush: 6 (2560 1440)
|
||||
00:00:07 - SDL Info (0): IDR frame request sent
|
||||
00:01:54 - SDL Info (0): Raising 3 keys
|
||||
00:01:54 - SDL Info (0): Detected quit key combo
|
||||
00:01:54 - SDL Info (0): Quit event received
|
||||
00:01:54 - SDL Info (0):
|
||||
Global video stats
|
||||
------------------
|
||||
Incoming frame rate from network: 17.16 FPS
|
||||
Decoding frame rate: 17.16 FPS
|
||||
Rendering frame rate: 17.07 FPS
|
||||
Host processing latency min/max/average: 24.1/53.8/33.6 ms
|
||||
Frames dropped by your network connection: 0.00%
|
||||
Frames dropped due to network jitter: 0.44%
|
||||
Average network latency: 11 ms (variance: 7 ms)
|
||||
Average decoding time: 14.07 ms
|
||||
Average frame queue delay: 0.95 ms
|
||||
Average rendering time (including monitor V-sync latency): 8.38 ms
|
||||
00:01:54 - SDL Info (0): Stopping input stream...
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Stopping audio stream...
|
||||
00:01:54 - SDL Info (0): No audio traffic was ever received from the host!
|
||||
00:01:54 - SDL Info (0): ENet wait interrupted
|
||||
00:01:54 - SDL Info (0): Control stream connection failed: 4
|
||||
00:01:54 - Qt Info: Found "gamecontrollerdb.txt" at "/home/armbian/.cache/Moonlight Game Streaming Project/Moonlight/gamecontrollerdb.txt"
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Stopping video stream...
|
||||
00:01:54 - SDL Info (0): Loaded 435 new gamepad mappings
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Stopping control stream...
|
||||
00:01:54 - SDL Info (0): ENet peer acknowledged disconnection
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Cleaning up input stream...
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Cleaning up video stream...
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Cleaning up control stream...
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Cleaning up audio stream...
|
||||
00:01:54 - Qt Warning: stream 1 finished with error: "Connection closed"
|
||||
00:01:54 - SDL Info (0): done
|
||||
00:01:54 - SDL Info (0): Cleaning up platform...
|
||||
00:01:54 - SDL Info (0): done
|
||||
49
docs/gpu-restart-diagnosis-20261102.md
Normal file
@ -0,0 +1,49 @@
|
||||
# GTX 965M 重启故障诊断(2026-11-02)
|
||||
|
||||
## 结论
|
||||
|
||||
未找到已验证有效的重启后 NVENC 恢复方案。所有实验配置已恢复,VM100 可继续使用软件编码回退;VM101/102 全程保持运行。
|
||||
|
||||
此前582.78、DXGI与NVENC确实工作过;此轮故障状态为Windows Code43、nvlddmkm停止、nvidia-smi失败、Sunshine回退libx264。不能以设备管理器显示型号或PnP暂时OK作为恢复成功的依据。
|
||||
|
||||
## 原始配置与备份
|
||||
|
||||
宿主机备份目录:`/root/vdi-gpu-recovery-20261102/`,包含100.conf、vfio.conf、ROM及PCI信息。
|
||||
|
||||
- hostpci0:`0000:01:00.0,pcie=1,rombar=1,romfile=gtx965m-pci.rom`
|
||||
- args:`-set device.hostpci0.x-pci-sub-vendor-id=0x1558 -set device.hostpci0.x-pci-sub-device-id=0x6557`
|
||||
- GPU:10de:13d9,子系统1558:6557,总线01仅此设备。
|
||||
- 原ROM SHA256:`080d9765337a5ea3bceefb1f632f073e14b09d215ef44b885e2d97cb04d27160`
|
||||
- `/etc/modprobe.d/vfio.conf`:`options vfio-pci ids=10de:13d9 disable_idle_d3=1`,本轮未修改该文件。
|
||||
- Windows快速启动原值HiberbootEnabled=1;本轮临时关闭后无收益,已恢复1。
|
||||
|
||||
## 实验与结果
|
||||
|
||||
| 实验 | 结果 |
|
||||
|---|---|
|
||||
| 关闭Windows快速启动,VM完整停止/启动 | Code43仍存在 |
|
||||
| 临时disable_idle_d3=N,再解绑/重绑VFIO | D0 active、runtime_usage=1;无法证明完成电源周期 |
|
||||
| 干净卸载并重载仅vfio_pci模块,disable_idle_d3=0 | 引用计数1→0;实测runtime suspended、D3cold;启动VM后D0,但Code43/NVML失败仍存在 |
|
||||
| 原供体ROM校验和修正副本 | Windows Guest Agent未上线,未保留 |
|
||||
| 本机既有sysfs ROM副本 | Windows启动但Code43/NVML失败 |
|
||||
| 本机ROM+已确认D3cold电源周期 | 同样失败,未保留 |
|
||||
|
||||
没有写PMCSR、没有刷写显卡固件、没有重启宿主机、没有卸载KVM或VFIO核心模块;仅在VM100停止且无VFIO使用者时重载vfio_pci。最终模块参数已恢复Y,原ROM配置已恢复。
|
||||
|
||||
## ROM证据与局限
|
||||
|
||||
1. 当前原始供体ROM为184320字节:传统BIOS镜像110080字节,PCIR ID10de:13d9,镜像和模256为1;第二UEFI镜像74240字节仍为10de:13d8。版本84.04.22.00.11。这些是明确的不一致,但不能认定为唯一故障原因;VM使用SeaBIOS,UEFI ID不匹配不等同于此次启动必然失败。
|
||||
2. 既有本机sysfs ROM为110592字节,10de:13d9、校验和0、版本84.04.2B.00.13,字符串含HWDIAG。尚未确认是完整的、适配此板卡的生产版固件;不能只凭校验和正常就当作可靠替代。
|
||||
3. 两份ROM均未刷入硬件。测试副本留在宿主机,当前VM不使用它们。
|
||||
|
||||
## 下一步所需条件
|
||||
|
||||
- 优先由运维/设备厂商提供该CLEVO板卡的生产版GM204M/13D9 vBIOS及适配依据,保留原件后再验证。
|
||||
- 如需要宿主机冷启动、内核/VFIO升级或平台固件实验,先安排维护窗口,备份全部VM与宿主启动配置;不能影响其他VM而不协调。
|
||||
- 当前证据只证明D3cold电源周期可实现,并不证明它能够修复此显卡;不要添加反复复位/重启任务充当永久修复。
|
||||
|
||||
## 验收标准
|
||||
|
||||
nvidia-smi成功、DXGI枚举NVIDIA、Sunshine实际选择h264_nvenc、真实串流有编码利用率;随后Windows重启和VM停启后重复通过。2K显示、20FPS配置和正常Windows单光标应同时保留。
|
||||
|
||||
参考:[Linux PCI](https://docs.kernel.org/PCI/pci.html)、[VFIO](https://docs.kernel.org/driver-api/vfio.html)、[PCI sysfs](https://docs.kernel.org/PCI/sysfs-pci.html)、[Proxmox qm](https://pve.proxmox.com/pve-docs/qm.1.html)。
|
||||
62
docs/independent-cursor-design-20261103.md
Normal file
@ -0,0 +1,62 @@
|
||||
# 独立光标二次开发设计与接入条件
|
||||
|
||||
状态:源码核实完成,尚未实现 Sunshine/Moonlight 的独立光标通道,不应标记为已部署。当前保留单个 Windows 远程白色光标。
|
||||
|
||||
## 已核实的实际路径
|
||||
|
||||
- 盒子固定 Moonlight Qt 6.2.0,现有 absolute mouse 输入仍经 moonlight-common-c 的可靠输入通道发送。
|
||||
- 当前 RKMPP/EGL 路径使用 PacerRender 独立线程;实际诊断会话没有主线程 render 调用,输入优先调度不会改变这个渲染路径。
|
||||
- Sunshine `input.cpp` 的 Ctrl+Alt+Shift+N 直接翻转全局 `display_cursor`。`video.cpp` 将其地址传入 display capture。它没有按会话的目标状态、确认或租约,不能作为可靠的独立光标协议。
|
||||
- Windows Desktop Duplication 可能返回独立光标形状,也可能返回已含光标的画面;不能假定所有显示设备都能从视频中无损移除光标。
|
||||
- Windows 当前没有现成的 Sunshine C++ 构建环境。因此本轮可以构建盒子客户端、验证输入和刷新率,但不能把未构建的服务端补丁当成已完成联调。
|
||||
|
||||
参考:[Sunshine input.cpp](https://github.com/LizardByte/Sunshine/blob/master/src/input.cpp)、[video.cpp](https://github.com/LizardByte/Sunshine/blob/master/src/video.cpp)、[Windows RAM capture](https://github.com/LizardByte/Sunshine/blob/master/src/platform/windows/display_ram.cpp)、[Microsoft Desktop Duplication 光标说明](https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api)。master 仅用于核实设计,实际修改须先固定现场 Sunshine 版本对应提交。
|
||||
|
||||
## 实施方式
|
||||
|
||||
在 Sunshine 与 moonlight-common-c/Moonlight 间扩展现有加密控制通道;不另外开放未经认证的 UDP 光标端口。默认仍使用远程视频光标,仅在双方协商并确认支持后启用。新增消息必须有协议版本、会话标识、显示配置代数及严格的大小校验。
|
||||
|
||||
| 消息 | 必要内容与作用 |
|
||||
| --- | --- |
|
||||
| 能力协商 | 支持形状类型、最大尺寸、显隐/视频帧交接能力;旧客户端保持原行为 |
|
||||
| 光标形状 | 形状版本、尺寸、热点、像素/掩码格式;形状变化时发送并缓存 |
|
||||
| 光标状态 | 状态序号、形状版本、显隐、坐标、显示区域及缩放配置代数 |
|
||||
| 交接请求/确认 | 明确目标模式,携带首个采用该模式的视频帧 ID;不能使用无确认的 toggle |
|
||||
| 位置校正 | 服务端主动移动与最近输入序号关联;用户持续移动时不能用旧位置反复拉回 |
|
||||
| 心跳/结束 | 会话租约、显式结束;连接丢失时服务端自动恢复视频光标 |
|
||||
|
||||
光标移动由盒子的本地指针立即显示,形状和显隐仍取自服务端。窗口、按钮响应和内容更新继续走视频,所以独立光标不等于窗口拖动零延迟。
|
||||
|
||||
## 单光标交接
|
||||
|
||||
1. 服务端确认当前捕获后端可独立控制光标,客户端收到并成功创建当前形状;否则保持远程模式。
|
||||
2. 服务端在明确的视频帧边界停止混合光标,并发出该帧 ID。客户端显示到这个边界后才开启本地光标,避免旧视频仍有光标时出现双指针。
|
||||
3. 结束独立模式时反向交接,在开始包含远程光标的视频帧上隐藏本地光标。
|
||||
4. 辅助状态超时、形状不支持、捕获设备更换、显示缩放改变、解码器重建、第二路会话接入时,执行确认后的回退。控制连接完全断开且无法继续交接时结束串流,返回选择页。
|
||||
5. 不能通过替换 Windows 全局鼠标主题为透明图片实现;不能把普通箭头覆盖在视频光标上。
|
||||
|
||||
心跳和租约先按 250ms/1000ms 做实验参数,最终值由 Wi-Fi 抖动及故障恢复测试决定。现有全局 display_cursor 还须改为与会话/捕获生命周期一致的状态,防止多个客户端互相覆盖。
|
||||
|
||||
## Windows 特殊情况
|
||||
|
||||
- 处理彩色 alpha、单色 AND/XOR 和 masked-color;不支持的形状明确回退。不能把 XOR 像素简单当透明像素。
|
||||
- 热点随流画面缩放映射,窗口信箱区域不发送越界输入;切换分辨率后废弃旧代数的光标消息。
|
||||
- 服务端隐藏指针、文字选择、拖动缩放、忙碌动画必须正确;锁屏/UAC 桌面切换不能继续显示过期光标。
|
||||
- SDL 硬件指针操作留在主线程;网络线程仅提交有界状态,禁止直接调用 SDL_SetCursor/释放正在使用的 cursor。
|
||||
- 本地移动与远程主动 warp 分开处理,避免拖动时抖动、回弹;点击仍使用已修复的按钮坐标/输入顺序。
|
||||
|
||||
## 必须通过的验收
|
||||
|
||||
| 场景 | 要求 |
|
||||
| --- | --- |
|
||||
| 移动/拖动/右键/快速双击 | 单光标、点击准确、无丢失的按键释放 |
|
||||
| 箭头/文字/调整大小/忙碌/隐藏/自定义 | 形状、热点及显隐正确;不支持时可靠回退 |
|
||||
| 100%/125%/150% 缩放、分辨率切换 | 无偏移;旧代数消息失效 |
|
||||
| 辅助消息停止、控制断开、服务器重启 | 无持久双光标或无光标状态 |
|
||||
| 窗口失焦、鼠标离开、重新捕获 | 不锁死本地系统指针;恢复后坐标正确 |
|
||||
| 旧服务端/客户端、多会话 | 不误启用;保持原有远程模式 |
|
||||
| 高速摄像对照 | 分别报告指针移动、点击响应、拖窗内容更新的 P50/P95 |
|
||||
|
||||
## 下一阶段开始条件
|
||||
|
||||
固定现场 Sunshine 版本及源码提交,在独立构建目录准备可复现 Windows 构建,备份原安装并在测试实例验证后,再修改双方协议和捕获交接。不得为部署光标实验重装当前 Windows、刷 GPU ROM 或中断其他虚拟机。
|
||||
51
docs/input-rendering-optimization-20261103.md
Normal file
@ -0,0 +1,51 @@
|
||||
# 鼠标点击与画面跳转优化(2026-11-03)
|
||||
|
||||
本轮针对用户反馈的“鼠标拖动/点击有残影、点击后画面跳转慢”做了输入队列和低延迟呈现优化。已有单白色 Windows 远程光标、显示器开关自动恢复和 RKMPP/EGL 客户端均保留。
|
||||
|
||||
## 现场根因
|
||||
|
||||
1. **点击位置顺序会被旧的绝对鼠标移动批次覆盖。** Moonlight 上游为了减少包数,会让一个尚未发送的绝对鼠标包持续吸收后续位置。高速移动后点击时,点击包与位置包在网络队列中的边界不明确,画面中的 Windows 控件可能在旧位置响应。32 次左右交替点击的实测中,修改前收到 32 条点击记录,其中第 1、13 条落在错误的一侧(30/32 正确)。这是延迟体感之外的可重复顺序错误。
|
||||
2. **鼠标移动合并会扫描 SDL 队列。** 原逻辑只按 `SDL_MOUSEMOTION` 类型取事件,可能跨过按钮/键盘/窗口事件,把点击后的移动提前合并。修改后只消费紧邻且属于同一鼠标设备/窗口/按键状态的移动,遇到边界立即停止,每次最多处理 64 条,避免输入线程长时间占用。
|
||||
3. **低延迟模式的解码帧积压。** 当前服务端仍为软件 `libx264`、约 30 FPS;盒子已使用 `h264_rkmpp` + `drm_prime` + EGL/GLES。修改后的非 VSync pacing 呈现队列可以丢弃尚未呈现的等待帧,只保留最新等待帧,减少画面落后于点击的时间。正在呈现的帧、上一帧延迟释放和解码参考帧不会被释放。
|
||||
|
||||
## 实现
|
||||
|
||||
- `terminal/moonlight/patches/0001-vdi-input-and-latest-frame.patch`
|
||||
- SDL 输入事件按边界合并。
|
||||
- 绝对鼠标按钮使用该按钮事件的坐标先入队。
|
||||
- `VDI_LATEST_FRAME=1` 且未启用 VSync pacing 时只替换等待呈现帧;默认 wrapper 开启,smooth/pacing 档保持上游行为。
|
||||
- `terminal/moonlight/patches/0002-vdi-absolute-click-barrier.patch`
|
||||
- 每个点击封住前一位置批次,点击后的移动进入新批次。
|
||||
- 发送线程只解除自己包的“可吸收新位置”状态,不误清除点击后新批次。
|
||||
- `terminal/kiosk-shell/scripts/vdi-moonlight-rkmpp` 默认 `VDI_LATEST_FRAME=1`,仍不创建本地黑光标、不叠加第二个光标。
|
||||
- `tools/build-rkmpp-client.sh` 固定 Moonlight/MPP/FFmpeg 提交,构建前检查并幂等应用补丁;出现源码漂移会失败,不强行覆盖。
|
||||
- `tools/set-desktop-responsiveness.ps1` 已在 Windows 登录用户会话执行:备份原设置,关闭窗口缩放动画、菜单等待从 400ms 改为 100ms;通过 `SystemParametersInfoW` 设置并读回校验成功,临时执行任务已删除。失败时脚本会自动恢复。
|
||||
- 盒子显示守护改读 Xorg 当前配置 `xrandr --current`,保留热插拔恢复,避免每 2 秒重新探测 EDID/显示模式引发 vendor 驱动时钟日志;对应 9 个场景测试通过。
|
||||
- 用户明确蓝框发生于盒子登录/选择桌面页:QLabel 继承 QFrame,原 `QFrame:hover` 蓝框会作用于文字。移除该悬停规则,卡片样式限定到对象名,移除登录输入框的蓝色焦点边框。实际悬停截图文字/卡片区域亮蓝色像素从 8,302 降到 0,按钮仍可正常使用。
|
||||
|
||||
## 自动化与现场测试
|
||||
|
||||
| 测试 | 结果 |
|
||||
|---|---|
|
||||
| SDL 事件边界、64 条上限、触摸鼠标隔离、最新帧 helper | 通过 |
|
||||
| 绝对输入 1,000 轮“位置→位置→按下→位置→释放→位置” | 通过 |
|
||||
| AddressSanitizer 版本上述 native 测试 | 通过,无内存错误 |
|
||||
| 修改前 32 次交替点击 | 30/32 正确,错误序号 1、13 |
|
||||
| 修改后 32 次交替点击 | 32/32 正确 |
|
||||
| 修改后真实 RKMPP/EGL 串流 | 日志确认 `VDI latest-frame queue: enabled`、`h264_rkmpp`、2560×1440 DRM PRIME |
|
||||
| 配对对照串流 | 原版:28.93 接收/28.48 渲染 FPS,队列 3.39ms,解码 10.49ms,呈现 6.84ms;补丁:28.40/28.09 FPS,队列 2.14ms,解码 7.96ms,呈现 6.12ms |
|
||||
| 会话连续性 | 测试退出后没有遗留测试串流;显示守护 active;盒子仍 2560×1440 |
|
||||
|
||||
对照数据不是严格实验室基准:两段会话的网络、Windows 软件编码负载和页面内容会波动。补丁最明确的收益是点击顺序正确和队列深度下降约 1.25ms;它不能把当前服务端软件编码变成 NVENC,也不能保证端到端零延迟。测试期间出现过一次 Wi-Fi 从 completed 到 disconnected 后自动重连,受影响的数据已单独保留,未作为性能结论。
|
||||
|
||||
## Windows 桌面跳转动画
|
||||
|
||||
执行前 Windows 登录用户状态为 `DragFullWindows=1`、`MouseTrails=0`、`MinAnimate=1`、`MenuShowDelay=400`。已将窗口动画改为 0、子菜单等待改为 100ms,API 读回校验成功,保留完整窗口拖动和原远程单光标。原值备份到 `%LOCALAPPDATA%\VDI\desktop-responsiveness-before-20261103.json`,恢复使用同一脚本的 `-Restore`。这些设置只减少 Windows 自身的动画和子菜单等待,不代表网页加载或网络响应变快。API 依据为 [Microsoft SystemParametersInfoW](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow)。
|
||||
|
||||
## 当前状态与回退
|
||||
|
||||
补丁客户端已接入默认 wrapper,启用最新帧队列。kiosk 为移除蓝色悬停框做了局部编译、CTest 3/3、原监控器拉起新版页面;未运行完整部署脚本,未重启盒子、VM 或宿主。UI 和 wrapper 备份为 `~/vdi-terminal/backups/input-rendering-20261103-114542/`。补丁源码、测试和构建说明均在 `terminal/moonlight/`,证据在 `docs/evidence/input-latency-20261103/`。
|
||||
|
||||
如需临时回退客户端,下次启动 wrapper 时设置 `VDI_RKMPP_CLIENT=/home/armbian/vdi-build/rkmpp-experiment/build/moonlight/app/moonlight.before-input-20261103`、`VDI_LATEST_FRAME=0`。旧二进制 SHA256 为 `a3575f86b9ebfd3b9f2a6ae4c73b057b2c8cd489cc44549a8838ff459c5e89dc`,新二进制为 `35de7b1a4ade583823b23b5f2e012307f6d0a3848c8eb97bd6d4de9660afa00f`。回退后重新连接并查看统计;不要直接覆盖运行中的 ELF。
|
||||
|
||||
下一步为用户真实鼠标拖窗/右键/快速双击体验验收;严格延迟需通过高速摄像或外部触发测输入到屏幕 P50/P95。当前数据不能宣称“无延迟”,只能确认点击排序和客户端排队得到改善。
|
||||
67
docs/moonlight-rendering-profile-20261102.md
Normal file
@ -0,0 +1,67 @@
|
||||
# Moonlight 客户端渲染 profile
|
||||
|
||||
## 目的
|
||||
|
||||
统一 `kiosk-shell` 产品入口与现场调试入口的 Moonlight 呈现参数,避免测试时只改了
|
||||
`vdi-moonlight` 脚本而正式页面仍使用另一套 VSync、Frame Pacing 和解码器配置。
|
||||
|
||||
代码默认 profile 是 `smooth`;RK3528现场在硬解与EGL验证通过后,通过render.conf
|
||||
选择了 `low-latency` 和2K30。软件基线和其他未验证设备仍使用smooth。
|
||||
不把关闭同步当成通用修复,现场对照与风险见 `rendering-execution-20261102.md`。
|
||||
|
||||
## 产品入口环境变量
|
||||
|
||||
这些变量由 `kiosk-shell` 和 `vdi-moonlight` 调试启动器读取,重启串流进程后生效:
|
||||
|
||||
```text
|
||||
VDI_STREAM_PROFILE=smooth # 默认,VSync + Frame Pacing
|
||||
VDI_STREAM_PROFILE=low-latency # 关闭 VSync + Frame Pacing,减少呈现等待
|
||||
VDI_STREAM_PROFILE=diagnostic # smooth + Moonlight 性能叠图
|
||||
VDI_STREAM_STATS=1 # 独立开启叠图,可同时比较smooth和low-latency
|
||||
VDI_MOONLIGHT_DECODER=software # 系统客户端默认;RKMPP现场配置使用 hardware
|
||||
VDI_MOONLIGHT_CODEC=H.264 # 当前默认,先不切换 HEVC/AV1
|
||||
VDI_MOONLIGHT_PROGRAM=... # 可指定独立构建的Moonlight启动器,不覆盖系统二进制
|
||||
VDI_SDL_FORCE_EGL=1 # 仅现场验证 SDL X11 EGL 时设置
|
||||
VDI_SDL_VIDEODRIVER=wayland # 仅实验;正式入口的X11窗口激活逻辑尚需适配
|
||||
```
|
||||
|
||||
每次会话启动时,最终 profile、解码器、编解码器、同步开关、SDL renderer 和完整参数
|
||||
会写入 `~/vdi-terminal/logs/moonlight-YYYYMMDD.log` 的 `[VDI launch]` 段落。
|
||||
|
||||
## A/B 顺序
|
||||
|
||||
1. 先恢复并确认 Sunshine 使用 `h264_nvenc`,否则客户端 A/B 不能说明服务端问题已经解决。
|
||||
2. 1080p60:比较 `smooth` 与 `low-latency`,两组都设置 `VDI_STREAM_STATS=1` 收集 queue/render/jitter。
|
||||
3. RK3528 硬解与 EGL/GLES 现场路径已验证;后续仍需单独完成 2K60 验收,不能由 2K30 结果推断。
|
||||
4. 任何 profile 都必须保留 `--absolute-mouse`;当前已解决的双光标行为不应回退。
|
||||
|
||||
## GPU 重启故障边界
|
||||
|
||||
`gpu-restart-diagnosis-20261102.md` 已确认当前没有经过验证的重启后软件恢复办法。profile
|
||||
只改变客户端呈现,不会修复 Windows Code 43、NVML 失败或 Sunshine 回退 `libx264`。
|
||||
GPU 修复仍需设备厂商提供匹配的 GM204M/13D9 生产版 vBIOS,并在维护窗口内按验收标准
|
||||
重复验证 `nvidia-smi`、DXGI、`h264_nvenc` 和 Windows/VM 重启后的持久性。
|
||||
|
||||
## RK3528现场配置与回退
|
||||
|
||||
`~/.config/vdi-terminal/render.conf` 当前内容:
|
||||
|
||||
```ini
|
||||
profile=low-latency
|
||||
stats=0
|
||||
program=/home/armbian/vdi-terminal/bin/vdi-moonlight-rkmpp
|
||||
decoder=hardware
|
||||
codec=H.264
|
||||
```
|
||||
|
||||
Windows桌面卡当前请求2560x1440@30、30Mbps,实际持续动画约23FPS;
|
||||
虚拟屏仍为30Hz。私有构建位于 `~/vdi-build/rkmpp-experiment`,不要删除该目录。
|
||||
目前是用户目录内的POC部署,尚未打包为完整OTA镜像。
|
||||
|
||||
如现场发现关闭同步导致明显撕裂,可先将profile改为smooth,并将桌面卡FPS改回20。
|
||||
如需彻底退回系统客户端,退出串流后将render.conf改名保存,并恢复
|
||||
`desktops.before-rkmpp-20261102.json` 为desktops.json,然后重新启动kiosk受管栈。
|
||||
系统 `/usr/bin/moonlight-qt` 未被覆盖,不需要卸载MPP或替换系统FFmpeg。
|
||||
|
||||
设备访问规则是 `/etc/udev/rules.d/70-vdi-rockchip-video.rules`,限定video组0660;
|
||||
部署工具会安装并重载规则。udev匹配已验证,本轮未重启盒子做重启后串流复验。
|
||||
33
docs/mouse-optimization-plan-20261103.md
Normal file
@ -0,0 +1,33 @@
|
||||
# 鼠标与拖窗优化实施计划及结果(2026-11-03)
|
||||
|
||||
## 目标与边界
|
||||
|
||||
降低鼠标输入等待和画面更新延迟,保留单个 Windows 白色光标、正确点击位置、完整窗口拖动及现有显示器恢复功能。用实测决定是否启用,不能将帧间隔、客户端统计或本地光标响应称为端到端零延迟。
|
||||
|
||||
现场初检:盒子实际启动 2560×1440 / 30 FPS / RKMPP / EGL;Windows GTX 965M 仍 Code 43,Sunshine 实际 libx264,静态画面最低目标约 15 FPS。没有可直接构建 Sunshine 的现成 Windows C++ 工具链。
|
||||
|
||||
## 执行顺序
|
||||
|
||||
1. **记录基线。** 保存当前配置、二进制校验及串流日志,确认 GPU、虚拟屏刷新率、网络和解码路径。静态画面重复帧不能作为动态画面性能基准。
|
||||
2. **验证刷新率整条链路。** 用临时测试窗口对比虚拟屏/串流 30 与 60 FPS;修改必须支持只读查询、枚举、测试、临时应用和恢复。只有动态画面实测改善且解码/丢帧可接受,才更改默认配置;否则恢复 2K30。
|
||||
3. **改进 Moonlight 输入调度。** 检查主线程呈现阻塞输入的问题。允许帧呈现前先处理紧邻的有限数量输入,保持输入间原始顺序、窗口/焦点边界及工作量上限;增加可关闭的输入队列年龄与呈现阻塞统计。编译、自动化边界测试及真实串流对照后决定是否启用。
|
||||
4. **核实独立光标的落地条件。** 必须同步光标形状/热点/显隐、单光标交接、缩放及重连回退。Sunshine 现有 Ctrl+Alt+Shift+N 是全局开关,没有按会话确认,不能据此可靠实现断线回退;不能只叠加本地箭头后宣称完成。先形成与实际源码相符的协议和验收要求,具备服务端构建条件后才能集成双方修改并验收。
|
||||
5. **交付与现场恢复。** 移除临时测试任务/窗口,恢复正常云桌面连接;记录实际部署状态、测试结果、回退命令和未完成项。
|
||||
|
||||
## 验收
|
||||
|
||||
- 输入:快速交替点击无错位;双击、右键、拖动中的按下/释放顺序保持正确;失焦及退出快捷键正常。
|
||||
- 调度:窗口和焦点事件不能越过;高频鼠标不能无限拖延视频;禁用新开关可恢复旧调度。
|
||||
- 视频:相同动态测试源、相同分辨率/码率下记录接收/渲染 FPS、主机处理、解码、排队、呈现及网络丢帧;避免用空闲画面的平均 FPS 下结论。
|
||||
- 光标:只有一个指针;文字/缩放/忙碌形状、显隐正确;断线/辅助通道故障不能无光标或双光标。
|
||||
- 严格输入到屏幕延迟留待高速摄像/外部触发验证,客户端软件统计仅衡量其中一段。
|
||||
|
||||
## GPU 前置条件
|
||||
|
||||
本轮不重启宿主、不刷 ROM、不动 VM101/102。Code 43 仍需按现有运维方案排查,修复后再验收实际 NVIDIA D3D11 和 NVENC;不能只设置 encoder=nvenc 就认定修复。
|
||||
|
||||
## 执行结果
|
||||
|
||||
代码修改、自动化测试和现场配对串流对照已完成,结果见
|
||||
`docs/input-rendering-optimization-20261103.md`。当前状态为:点击排序和客户端排队已改善,
|
||||
仍需用户对真实拖窗、右键、快速双击进行体验验收;严格的输入到显示延迟仍需高速摄像或外部触发测量。
|
||||
168
docs/rendering-execution-20261102.md
Normal file
@ -0,0 +1,168 @@
|
||||
# Windows 云桌面渲染优化执行记录(2026-11-02)
|
||||
|
||||
## 执行顺序
|
||||
|
||||
1. 复核 GPU、实际编码器、客户机解码器、显示刷新率,保存原始证据。
|
||||
2. 用持续动画做同步参数 A/B;排除静态桌面的按需发帧影响。
|
||||
3. 在独立目录接通 MPP、RKMPP、DRM PRIME,先验证真实视频解码,再验证 Moonlight 串流。
|
||||
4. 只有真实串流通过后才启用新客户端,保留系统 Moonlight 的回退入口。
|
||||
5. GPU/NVENC 恢复后再做 1080p60、1440p30/60 和输入到屏幕延迟验收。
|
||||
|
||||
## 当前 GPU 证据
|
||||
|
||||
本轮经 Guest Agent 重新采集:GTX 965M 的 ConfigManagerErrorCode=43,NVML 查询失败,
|
||||
DXGI 没有枚举到 NVIDIA 适配器,Sunshine 的最新实际编码器为 `libx264`。配置已是
|
||||
`sw_preset=ultrafast`,当前 Windows 虚拟屏为 2560x1440@30。
|
||||
|
||||
没有再次复位设备、重载 VFIO、替换 ROM 或重启宿主机。本轮未改变其他 VM。
|
||||
仍没有证据确认唯一故障原因;匹配此板卡的生产版 vBIOS 或另一块可稳定直通的 GPU
|
||||
是下一轮服务端验证的候选条件,而非已完成修复。
|
||||
|
||||
验收工具更新为 `tools/validate-sunshine-nvenc.ps1` + `tools/probe-nvidia-d3d.cs`:
|
||||
实际创建 NVIDIA D3D11 设备、检查 PnP 错误码、检查最新一次实际编码器创建及时间,
|
||||
并核验 NVENC 会话与编码利用率。不会把启动阶段的编码器探测记录当作实际串流。
|
||||
|
||||
## 同步参数 A/B
|
||||
|
||||
环境:系统 Moonlight 6.2.0,H.264 软件解码,2560x1440@20、30Mbps,输出约60Hz,
|
||||
MATE compositor 已关闭,SDL OpenGL ES 2。Windows 用
|
||||
`tools/stream-motion-test.html` 持续移动条纹与棋盘;源 RAF 约30 FPS。
|
||||
125% DPI 下页面显示逻辑2048x1152,视频流和 HDMI 仍是物理2560x1440。
|
||||
|
||||
下表来自两段完整会话结束日志,包含启动/退出阶段,时长不同;属于现场初步对照,
|
||||
不构成严格统计学基准。原始日志与叠图保存在 `evidence/moonlight-20261102/`。
|
||||
|
||||
| 指标 | smooth | low-latency |
|
||||
|---|---:|---:|
|
||||
| 接收/解码 FPS | 17.16 | 17.07 |
|
||||
| 渲染 FPS | 17.07 | 17.01 |
|
||||
| 主机处理平均 ms | 33.6 | 35.4 |
|
||||
| 网络丢帧 | 0.00% | 0.00% |
|
||||
| jitter 分类丢帧 | 0.44% | 0.29% |
|
||||
| 网络延迟平均 ms | 11 | 11 |
|
||||
| 解码平均 ms | 14.07 | 16.96 |
|
||||
| 帧队列平均 ms | 0.95 | 1.14 |
|
||||
| 呈现平均 ms(含同步) | 8.38 | 10.87 |
|
||||
|
||||
系统客户端软件解码的对照中,关闭同步没有改善帧率或排队,因此软件基线保留 smooth。上述耗时
|
||||
不能直接相加当作端到端输入延迟;后续须用高速摄像/外部触发测量 P50/P95。
|
||||
|
||||
日志中的启动测试 EGLImage 导出失败和单次队列溢出,不能单独证明持续运行时故障。
|
||||
最终选中的系统路径是软件视频帧上传后的 SDL 呈现;`Using DRM renderer` 也不等于
|
||||
已经使用 VPU 或直接扫描输出。
|
||||
|
||||
## RKMPP 已验证部分
|
||||
|
||||
- 为 `/dev/mpp_service`、`/dev/rga`、`/dev/dma_heap/*` 增加 video 组读写权限;
|
||||
持久化规则为 `terminal/kiosk-shell/etc/70-vdi-rockchip-video.rules`。
|
||||
- 普通用户执行 MPP H.264 初始化,create/init/destroy 全部返回0。
|
||||
- 从固定提交构建 MPP 和 FFmpeg-Rockchip 6.1,目录是
|
||||
`/home/armbian/vdi-build/rkmpp-experiment`;依赖只下载解包,不安装或升级系统包。
|
||||
- 用 `generate-h264-sample.c` 生成60帧2560x1440 H.264样本。`h264_rkmpp` 全部解出,0错误。
|
||||
- CPU NV12输出耗时2.620秒;`-hwaccel rkmpp -hwaccel_output_format drm_prime` 输出耗时
|
||||
0.290秒,CPU时间0.120秒,日志明确为 DRM PRIME 帧,0解码错误。
|
||||
|
||||
样本纹理简单且测试期间有编译负载;这些数字仅证明硬解/帧导出可工作,不能替代
|
||||
Moonlight 真实串流、显示呈现、复杂内容或2K60验收。
|
||||
|
||||
## 产品接入点
|
||||
|
||||
`VDI_STREAM_STATS=1` 独立于 profile,可公平比较两档。解码器覆盖只接受
|
||||
software/hardware/auto;RKMPP通过 `H264_DECODER_HINT=h264_rkmpp` 选择,不把
|
||||
`h264_rkmpp` 当作 Moonlight `--video-decoder` 的值。
|
||||
|
||||
`VDI_MOONLIGHT_PROGRAM` 可指定独立客户端启动器。`vdi-kiosk-start` 支持读取
|
||||
`~/.config/vdi-terminal/render.conf` 的 allowlist 字段,不执行配置文件:
|
||||
|
||||
```ini
|
||||
profile=smooth
|
||||
stats=0
|
||||
program=/home/armbian/vdi-terminal/bin/vdi-moonlight-rkmpp
|
||||
decoder=hardware
|
||||
codec=H.264
|
||||
```
|
||||
|
||||
文件不存在时沿用系统客户端。上述为 smooth 档示例;本机实际部署档位见下表后说明。
|
||||
|
||||
## 构建与页面接入修正
|
||||
|
||||
私有客户端固定为 Moonlight v6.2.0 `de2467e433821664cdd2224aad8c89a625be1ad9`,
|
||||
MPP `7916c3cc000fefc0bdf96636b7d54fe174724f44`,FFmpeg-Rockchip 6.1
|
||||
`797387de1c9caa9170100d7217ee093d1897f750`。复现入口为
|
||||
`tools/build-rkmpp-client.sh`,仅在盒子的用户目录下载、解包和构建依赖。
|
||||
|
||||
- Qt 5 构建需要显式为上游 `drm.h` 补入 `<optional>`,脚本幂等应用。
|
||||
- 补齐 EGL 开发依赖,重新执行 qmake 功能探测,并在缺少 HAVE_EGL 时终止构建。
|
||||
- qmake 改变功能开关不会自动使旧对象失效;构建脚本记录编译/链接参数指纹,
|
||||
参数变化时清理应用对象,防止“探测有 EGL、实际对象无 EGL”。
|
||||
- RKMPP 使用独立测试解码器,上游成功路径不输出旧的 `Test decode successful`,
|
||||
而输出 `Not reusing test decoder for h264_rkmpp`。页面就绪解析同时兼容两者,
|
||||
仍要求实际 renderer 已选中,并在连接失败时拒绝进入就绪状态。
|
||||
- 私有启动器设置 QML、Qt 插件和共享库目录,系统 Moonlight 不被覆盖。
|
||||
|
||||
第一轮真实串流已输出 2560x1440 的 `h264_rkmpp / drm_prime`,但显示选中 SDL,
|
||||
并出现 `Selected hwframe->swframe ... (mapping: yes)`,因此该轮不作为零拷贝验收。
|
||||
对应证据为 `rkmpp-stale-sdl.txt` 与 `rkmpp-first.png`,包含构建负载和启动阶段。
|
||||
|
||||
另已核查用户注册表:`MouseTrails=0`、`DragFullWindows=1`,不通过添加第二个光标
|
||||
或重新设置透明光标来掩盖视频延迟。
|
||||
|
||||
## 后续顺序与验收要求
|
||||
|
||||
1. 先验证硬解实际串流与 EGL 呈现,记录持续动画下的接收、解码、呈现 FPS,
|
||||
解码/排队/呈现耗时及丢帧;没有通过则保留系统软件客户端默认入口。
|
||||
2. 通过后接入页面启动链,验证过场层退出、快捷键回列表、再次连接及持久配置。
|
||||
保留2K20现有配置作为基线,只有实测更好才提高请求帧率。
|
||||
3. 服务端 GPU 修复需匹配板卡的生产 ROM 或可稳定直通的替代设备,并重复通过
|
||||
PnP、NVML、DXGI/D3D11、真实 NVENC 以及重启后的验收。
|
||||
4. 服务端恢复后按1080p60、1440p30、1440p60逐档验证,并同步虚拟屏刷新率。
|
||||
1440p60还需要将当前30Hz虚拟屏调整到60Hz,不能只改客户端FPS参数。
|
||||
5. 用高速摄像或外部触发测输入到显示的P50/P95,另外观察快速拖窗与光标残影。
|
||||
如延迟仍主要来自光标随视频传输,再评估服务端光标位置/形状侧通道与客户端
|
||||
单光标显示的二次开发,需同时保证隐藏视频中的旧光标,不能直接叠加本地光标。
|
||||
|
||||
客户端应优先接通硬解与显示路径;镜像内安装补帧/运动插值插件不能修复 GPU Code 43,
|
||||
也不能代替真实输入响应。当前不把插帧作为低延迟方案。
|
||||
|
||||
## 真实串流对照与现场选择
|
||||
|
||||
清理旧对象后,日志明确选择 `Renderer 'EGL/GLES' with 'DRM' backend chosen`,
|
||||
实际解码尺寸2560x1440、`h264_rkmpp`、`drm_prime`,呈现使用 EGLImage。
|
||||
未见实际运行路径的 hwframe→swframe 映射回退。四组均为持续动画、30Mbps、
|
||||
源RAF30FPS、终端HDMI约60Hz、服务端libx264;均为约2分钟会话,统计包含启动/退出。
|
||||
会话按顺序进行,网络与服务端负载会波动,不能当作严格控制变量的实验室基准。
|
||||
|
||||
| 客户端/请求档位 | 接收/解码 FPS | 呈现 FPS | 主机平均 ms | 解码 ms | 队列 ms | 呈现 ms | 网络/jitter丢帧 |
|
||||
|---|---:|---:|---:|---:|---:|---:|---|
|
||||
| 系统软件解码 / 2K20 smooth(先前基线) | 17.16 | 17.07 | 33.6 | 14.07 | 0.95 | 8.38 | 0% / 0.44% |
|
||||
| RKMPP+EGL / 2K20 smooth | 19.14 | 18.97 | 38.4 | 10.53 | 2.78 | 2.54 | 0% / 0.20% |
|
||||
| RKMPP+EGL / 2K30 smooth | 24.21 | 23.29 | 46.2 | 8.24 | 31.95 | 4.19 | 0% / 3.02% |
|
||||
| RKMPP+EGL / 2K30 low-latency | 23.56 | 23.46 | 46.8 | 9.11 | 2.39 | 5.41 | 0% / 0.10% |
|
||||
| RKMPP+EGL / 2K30 VSync开、Frame Pacing关 | 23.26 | 22.63 | 47.5 | 8.28 | 28.93 | 4.14 | 0% / 2.23% |
|
||||
|
||||
对应原始统计分别为 `rkmpp-egl-20-smooth.txt`、`rkmpp-egl-30-smooth.txt`、
|
||||
`rkmpp-egl-30-lowlatency.txt`、`rkmpp-egl-30-vsync-no-pacing.txt`,均在证据目录中。
|
||||
|
||||
本机选择2K30、`profile=low-latency`、RKMPP硬解、H.264,常态关闭叠图。
|
||||
这是在当前设备上的取舍:相较2K30 smooth,平均帧队列少约30ms;关闭VSync存在
|
||||
撕裂风险,需要现场动态观察。保留2K20 smooth作为平稳显示的回退档,不将其删除。
|
||||
截图可见单个白色远程光标,但静态截图不能证明快速移动没有残影或输入延迟为零。
|
||||
|
||||
当前会话平均呈现仍只有约23FPS,未达到请求的30FPS;服务端GPU故障和libx264路径
|
||||
仍未修复。不能将这一轮称为2K60、NVENC恢复或“鼠标无延迟”验收通过。
|
||||
|
||||
## 正式入口部署验证
|
||||
|
||||
已运行 `tools/deploy_kiosk.sh` 同步、编译、CTest、安装和重启盒子的kiosk受管栈;
|
||||
CTest 2/2通过。render.conf选择上述私有硬解客户端,桌面卡请求帧率持久保存为30,
|
||||
原文件备份在盒子 `~/.config/vdi-terminal/desktops.before-rkmpp-20261102.json`。
|
||||
|
||||
两次从实际列表页点击Windows连接,日志分别在约10.1秒、9.7秒进入stream_ready,
|
||||
均明确选中 `EGL/GLES + DRM`、`h264_rkmpp`,过场层退出后画面可见。
|
||||
`Ctrl+Alt+Shift+Q` 正常退出code=0并回列表,再次连接通过;没有遗留第二条串流。
|
||||
配置已经写入现有自启链,但本轮未重启盒子、VM或宿主机;不声称完成重启后验收。
|
||||
|
||||
截图 `kiosk-rkmpp-session.png`、`kiosk-rkmpp-disconnect.png`、
|
||||
`kiosk-rkmpp-reconnect.png` 保留了产品入口验证。单白光标可见,未修改原光标策略。
|
||||
自动化拖窗未形成可计量的动态验收结果,仍需现场鼠标操作与外部摄像测量。
|
||||
专用Edge测试浏览器已关闭,临时VDIRenderBench任务已删除,未关闭其他浏览器。
|
||||
@ -55,6 +55,11 @@ target_link_libraries(vdi-kiosk-monitor PRIVATE Threads::Threads)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Test)
|
||||
if(UNIX)
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
add_test(NAME display-guard COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tests/test_display_guard.py)
|
||||
endif()
|
||||
|
||||
add_executable(test-moonlight-session
|
||||
tests/test_moonlight_session.cpp
|
||||
|
||||
4
terminal/kiosk-shell/etc/70-vdi-rockchip-video.rules
Normal file
@ -0,0 +1,4 @@
|
||||
# RK3528 vendor-kernel media interfaces. Members of video may use the VPU.
|
||||
KERNEL=="mpp_service", GROUP="video", MODE="0660"
|
||||
KERNEL=="rga", GROUP="video", MODE="0660"
|
||||
SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660"
|
||||
@ -18,6 +18,7 @@
|
||||
# NVENC重启故障及各档性能记录见 docs/moonlight-kiosk-20261028.md。
|
||||
# frame-pacing 1=开启帧率匀速(--frame-pacing),0=关闭(--no-frame-pacing)
|
||||
# performance-overlay 1=显示性能叠图(调试用)
|
||||
# profile smooth / low-latency / diagnostic;为空时保留下方显式开关
|
||||
# hang-timeout 串流假死判定时间(秒),0 表示关闭该检测
|
||||
host=192.168.1.70
|
||||
port=47984
|
||||
@ -34,6 +35,7 @@ absolute-mouse=1
|
||||
vsync=1
|
||||
frame-pacing=1
|
||||
performance-overlay=0
|
||||
profile=smooth
|
||||
retry=3
|
||||
retry-delay=5
|
||||
hang-timeout=90
|
||||
|
||||
14
terminal/kiosk-shell/etc/vdi-display-guard.service
Normal file
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=VDI HDMI mode recovery after monitor power cycle (X11 POC)
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=DISPLAY=:0
|
||||
Environment=XAUTHORITY=%h/.Xauthority
|
||||
ExecStart=%h/vdi-terminal/bin/vdi-display-guard
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
TimeoutStopSec=15
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
170
terminal/kiosk-shell/scripts/vdi-display-guard
Normal file
@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Restore this RK3528 terminal's verified HDMI timing after X11 hotplug."""
|
||||
|
||||
import argparse
|
||||
import fcntl
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
|
||||
OUTPUT = "HDMI-1"
|
||||
MODE = "2560x1440_60_fixed297"
|
||||
# The vendor PHY rejects the EDID's 241.70 MHz timing. Keep the verified PLL.
|
||||
TIMING = "297.00 2560 2608 2640 2720 1440 1443 1448 1820 +HSync -VSync".split()
|
||||
POLL_SECONDS = 2
|
||||
SETTLE_SECONDS = 2
|
||||
|
||||
|
||||
def log(message):
|
||||
print(time.strftime("%Y-%m-%d %H:%M:%S"), message, flush=True)
|
||||
|
||||
|
||||
def xrandr(*args):
|
||||
result = subprocess.run(["xrandr", *args], capture_output=True, text=True,
|
||||
timeout=10, check=False)
|
||||
if result.returncode:
|
||||
raise RuntimeError((result.stderr or result.stdout).strip()[:400])
|
||||
return result.stdout
|
||||
|
||||
|
||||
@dataclass
|
||||
class DisplayState:
|
||||
connected: bool
|
||||
geometry: str
|
||||
active_mode: str
|
||||
modes: set
|
||||
defined: bool
|
||||
|
||||
@property
|
||||
def healthy(self):
|
||||
return (self.connected and self.geometry == "2560x1440+0+0"
|
||||
and self.active_mode == MODE)
|
||||
|
||||
|
||||
def parse_state(query):
|
||||
connected, geometry, active = False, "", ""
|
||||
modes, defined, in_output = set(), False, False
|
||||
for line in query.splitlines():
|
||||
fields = line.split()
|
||||
if not fields:
|
||||
continue
|
||||
if fields[0] == MODE:
|
||||
defined = True # Includes a globally defined but detached mode.
|
||||
if not line[0].isspace():
|
||||
in_output = fields[0] == OUTPUT
|
||||
if in_output:
|
||||
connected = len(fields) > 1 and fields[1] == "connected"
|
||||
geometry = next((f for f in fields[2:]
|
||||
if re.fullmatch(r"\d+x\d+\+\d+\+\d+", f)), "")
|
||||
elif in_output and len(fields) > 1 and re.match(r"^\d+(?:\.\d+)?[+*]*$", fields[1]):
|
||||
modes.add(fields[0])
|
||||
if "*" in " ".join(fields[1:]):
|
||||
active = fields[0]
|
||||
return DisplayState(connected, geometry, active, modes, defined)
|
||||
|
||||
|
||||
class Guard:
|
||||
def __init__(self, runner=xrandr, reporter=log):
|
||||
self.run = runner
|
||||
self.log = reporter
|
||||
self.bad_since = None
|
||||
self.next_retry = 0
|
||||
self.failures = 0
|
||||
self.last_status = None
|
||||
|
||||
def report(self, status):
|
||||
if status != self.last_status:
|
||||
self.log(status)
|
||||
self.last_status = status
|
||||
|
||||
def step(self, now):
|
||||
try:
|
||||
# Xorg already receives DRM hotplug events. Read its current state
|
||||
# without probing every EDID/mode: the vendor driver logs clock
|
||||
# warnings for those probes, adding unnecessary work while streaming.
|
||||
state = parse_state(self.run("--current"))
|
||||
except (OSError, RuntimeError, subprocess.TimeoutExpired) as error:
|
||||
self.bad_since = None
|
||||
self.report("X11 unavailable; waiting: " + str(error)[:400])
|
||||
return False
|
||||
if not state.connected:
|
||||
self.bad_since = None
|
||||
self.next_retry = 0
|
||||
self.failures = 0
|
||||
self.report(OUTPUT + " disconnected; no mode changes")
|
||||
return False
|
||||
if state.healthy:
|
||||
self.bad_since = None
|
||||
self.next_retry = 0
|
||||
self.failures = 0
|
||||
self.report("healthy: " + MODE)
|
||||
return True
|
||||
self.report("mode drift: " + (state.active_mode or "off") + " " + state.geometry)
|
||||
if self.bad_since is None:
|
||||
self.bad_since = now
|
||||
if now - self.bad_since < SETTLE_SECONDS or now < self.next_retry:
|
||||
return False
|
||||
try:
|
||||
if not state.defined:
|
||||
self.run("--newmode", MODE, *TIMING)
|
||||
if MODE not in state.modes:
|
||||
self.run("--addmode", OUTPUT, MODE)
|
||||
self.run("--output", OUTPUT, "--mode", MODE, "--pos", "0x0")
|
||||
if not parse_state(self.run("--current")).healthy:
|
||||
raise RuntimeError("mode was not retained after apply")
|
||||
except (OSError, RuntimeError, subprocess.TimeoutExpired) as error:
|
||||
self.failures = min(self.failures + 1, 6)
|
||||
delay = min(60, 2 ** self.failures)
|
||||
# Base backoff on completion, including a slow/timed-out modeset.
|
||||
self.next_retry = time.monotonic() + delay
|
||||
self.log("restore failed; retry in %ds: %s" % (delay, str(error)[:400]))
|
||||
return False
|
||||
self.bad_since = None
|
||||
self.next_retry = 0
|
||||
self.failures = 0
|
||||
self.report("restored: " + MODE + " (stream process untouched)")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--once", action="store_true",
|
||||
help="initial display recovery with a 20s retry window, then exit")
|
||||
args = parser.parse_args()
|
||||
os.environ.setdefault("DISPLAY", ":0")
|
||||
os.environ.setdefault("XAUTHORITY", str(Path.home() / ".Xauthority"))
|
||||
runtime = Path(os.environ.get("XDG_RUNTIME_DIR", str(Path.home() / ".cache/vdi-terminal")))
|
||||
runtime.mkdir(parents=True, exist_ok=True)
|
||||
# Same lock for startup and the systemd service. Never run competing guards.
|
||||
with (runtime / "vdi-display-guard.lock").open("a") as lock:
|
||||
try:
|
||||
fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except BlockingIOError:
|
||||
log("display guard already running")
|
||||
return 0
|
||||
stop = False
|
||||
|
||||
def request_stop(signum, frame):
|
||||
nonlocal stop
|
||||
stop = True
|
||||
|
||||
signal.signal(signal.SIGTERM, request_stop)
|
||||
signal.signal(signal.SIGINT, request_stop)
|
||||
guard = Guard()
|
||||
deadline = time.monotonic() + 20
|
||||
while not stop:
|
||||
if guard.step(time.monotonic()) and args.once:
|
||||
return 0
|
||||
if args.once and time.monotonic() >= deadline:
|
||||
return 1
|
||||
time.sleep(POLL_SECONDS)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@ -3,26 +3,28 @@
|
||||
export DISPLAY="${DISPLAY:-:0}"
|
||||
export XAUTHORITY="${XAUTHORITY:-/home/armbian/.Xauthority}"
|
||||
|
||||
# Match the local output to the 2K Moonlight stream.
|
||||
# This kernel rejects the monitor's 241.70 MHz timing but accepts the 297 MHz
|
||||
# PLL rate. Longer vertical blanking produces 2560x1440 at approximately 60 Hz.
|
||||
# HDMI can appear a few seconds after the desktop autostart entry runs.
|
||||
: >/tmp/vdi-display-mode.log
|
||||
mode="2560x1440_60_fixed297"
|
||||
for _ in $(seq 1 20); do
|
||||
if xrandr --query 2>>/tmp/vdi-display-mode.log | grep -q '^HDMI-1 connected'; then
|
||||
xrandr --newmode "$mode" 297.00 \
|
||||
2560 2608 2640 2720 1440 1443 1448 1820 \
|
||||
+HSync -VSync >>/tmp/vdi-display-mode.log 2>&1 || true
|
||||
xrandr --addmode HDMI-1 "$mode" >>/tmp/vdi-display-mode.log 2>&1 || true
|
||||
if xrandr --output HDMI-1 --mode "$mode" >>/tmp/vdi-display-mode.log 2>&1; then
|
||||
break
|
||||
fi
|
||||
xrandr --output HDMI-1 --mode 1920x1080 --rate 60 \
|
||||
>>/tmp/vdi-display-mode.log 2>&1 || true
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# Optional verified rendering deployment. Parse an allowlist as data; never
|
||||
# source/eval configuration. Explicit environment overrides the saved defaults.
|
||||
render_conf="${VDI_RENDER_CONF:-$HOME/.config/vdi-terminal/render.conf}"
|
||||
if [ -r "$render_conf" ]; then
|
||||
while IFS='=' read -r key value || [ -n "$key" ]; do
|
||||
case "$key" in
|
||||
profile) export VDI_STREAM_PROFILE="${VDI_STREAM_PROFILE:-$value}" ;;
|
||||
stats) export VDI_STREAM_STATS="${VDI_STREAM_STATS:-$value}" ;;
|
||||
program) export VDI_MOONLIGHT_PROGRAM="${VDI_MOONLIGHT_PROGRAM:-$value}" ;;
|
||||
decoder) export VDI_MOONLIGHT_DECODER="${VDI_MOONLIGHT_DECODER:-$value}" ;;
|
||||
codec) export VDI_MOONLIGHT_CODEC="${VDI_MOONLIGHT_CODEC:-$value}" ;;
|
||||
esac
|
||||
done < "$render_conf"
|
||||
fi
|
||||
|
||||
# Use the same idempotent recovery for boot and HDMI hotplug. The user service
|
||||
# supervises ongoing recovery; a singleton lock prevents competing instances.
|
||||
"$(dirname "$0")/vdi-display-guard" --once >>/tmp/vdi-display-mode.log 2>&1 || true
|
||||
if ! systemctl --user start vdi-display-guard.service >>/tmp/vdi-display-mode.log 2>&1; then
|
||||
echo 'WARNING: display guard service unavailable; only boot recovery active' \
|
||||
>>/tmp/vdi-display-mode.log
|
||||
fi
|
||||
|
||||
exec /home/armbian/vdi-terminal/bin/vdi-kiosk-monitor -- \
|
||||
/home/armbian/vdi-terminal/bin/kiosk-shell
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
#
|
||||
# 职责:
|
||||
# 1. 读取本地配置(主机、应用、分辨率、帧率、码率、编解码)
|
||||
# 2. 以软件解码拉起 moonlight-qt,全屏串流云桌面
|
||||
# 2. 按配置拉起 Moonlight,全屏串流云桌面
|
||||
# 3. 写心跳文件,供 vdi-kiosk-monitor 判断是否假死
|
||||
# 4. 检测串流假死(CPU 与网络均无流量)并杀掉重连
|
||||
#
|
||||
@ -12,7 +12,8 @@
|
||||
#
|
||||
# 说明:RK3528 当前没有可用的 V4L2 request/m2m 硬解设备,moonlight-qt 的
|
||||
# --video-decoder auto 会选到 h264_v4l2m2m 并报 "Could not find a valid device",
|
||||
# 因此配置里显式指定 decoder=software。接入 MPP/VPU 硬解后再改回 auto。
|
||||
# 因此系统客户端默认 decoder=software;验证后的独立 RKMPP 客户端
|
||||
# 通过 VDI_MOONLIGHT_PROGRAM 与 decoder=hardware 显式启用。
|
||||
|
||||
set -u
|
||||
|
||||
@ -38,9 +39,10 @@ DECODER="software"
|
||||
DISPLAY_MODE="fullscreen"
|
||||
AUDIO=1
|
||||
ABSOLUTE_MOUSE=1
|
||||
VSYNC=0
|
||||
FRAME_PACING=0
|
||||
VSYNC=1
|
||||
FRAME_PACING=1
|
||||
PERFORMANCE_OVERLAY=0
|
||||
PROFILE=""
|
||||
RETRY=3
|
||||
RETRY_DELAY=5
|
||||
HANG_TIMEOUT=90
|
||||
@ -76,6 +78,7 @@ load_config() {
|
||||
vsync) VSYNC="$value" ;;
|
||||
frame-pacing) FRAME_PACING="$value" ;;
|
||||
performance-overlay) PERFORMANCE_OVERLAY="$value" ;;
|
||||
profile) PROFILE="$value" ;;
|
||||
retry) RETRY="$value" ;;
|
||||
retry-delay) RETRY_DELAY="$value" ;;
|
||||
hang-timeout) HANG_TIMEOUT="$value" ;;
|
||||
@ -84,6 +87,33 @@ load_config() {
|
||||
done < "$CONF"
|
||||
}
|
||||
|
||||
apply_profile() {
|
||||
case "$PROFILE" in
|
||||
smooth)
|
||||
VSYNC=1
|
||||
FRAME_PACING=1
|
||||
;;
|
||||
low-latency)
|
||||
VSYNC=0
|
||||
FRAME_PACING=0
|
||||
;;
|
||||
diagnostic)
|
||||
VSYNC=1
|
||||
FRAME_PACING=1
|
||||
PERFORMANCE_OVERLAY=1
|
||||
;;
|
||||
"")
|
||||
# 兼容旧配置:没有profile时保留moonlight.conf中的显式开关。
|
||||
;;
|
||||
*)
|
||||
log "未知串流 profile=$PROFILE,回退 smooth"
|
||||
PROFILE=smooth
|
||||
VSYNC=1
|
||||
FRAME_PACING=1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 默认路由出接口的累计收字节数,用于判断串流是否还有数据流入
|
||||
rx_bytes() {
|
||||
iface=$(awk '$2=="00000000" {print $1; exit}' /proc/net/route)
|
||||
@ -145,7 +175,7 @@ disable_screensaver() {
|
||||
build_cmd() {
|
||||
# moonlight-qt stream 只接受 <host> <app> 位置参数,没有 --port 选项,
|
||||
# 服务端端口由 moonlight 自身按 GameStream 协议协商。
|
||||
CMD="moonlight-qt stream $HOST $APP"
|
||||
CMD="${VDI_MOONLIGHT_PROGRAM:-moonlight-qt} stream $HOST $APP"
|
||||
CMD="$CMD --resolution ${WIDTH}x${HEIGHT}"
|
||||
CMD="$CMD --fps $FPS"
|
||||
CMD="$CMD --bitrate $BITRATE"
|
||||
@ -155,7 +185,7 @@ build_cmd() {
|
||||
CMD="$CMD --keep-awake"
|
||||
[ "$ABSOLUTE_MOUSE" = "1" ] && CMD="$CMD --absolute-mouse"
|
||||
[ "$AUDIO" = "1" ] && CMD="$CMD --audio-on-host" || CMD="$CMD --no-audio-on-host"
|
||||
# 低延迟开关:默认关闭 vsync 与 frame-pacing,削减帧队列/呈现延迟
|
||||
# 按profile选择同步策略;默认保持当前稳定档。
|
||||
[ "$VSYNC" = "1" ] && CMD="$CMD --vsync" || CMD="$CMD --no-vsync"
|
||||
[ "$FRAME_PACING" = "1" ] && CMD="$CMD --frame-pacing" || CMD="$CMD --no-frame-pacing"
|
||||
[ "$PERFORMANCE_OVERLAY" = "1" ] && CMD="$CMD --performance-overlay"
|
||||
@ -163,7 +193,7 @@ build_cmd() {
|
||||
|
||||
run_stream() {
|
||||
build_cmd
|
||||
log "启动串流: $CMD"
|
||||
log "启动串流 profile=${PROFILE:-config} decoder=$DECODER codec=$CODEC vsync=$VSYNC frame-pacing=$FRAME_PACING renderer=${SDL_RENDER_DRIVER:-} video-driver=${SDL_VIDEODRIVER:-}: $CMD"
|
||||
# shellcheck disable=SC2086
|
||||
$CMD >> "$LOG_FILE" 2>&1 &
|
||||
ML_PID=$!
|
||||
@ -220,6 +250,19 @@ stop)
|
||||
esac
|
||||
|
||||
load_config
|
||||
PROFILE="${VDI_STREAM_PROFILE:-$PROFILE}"
|
||||
apply_profile
|
||||
DECODER="${VDI_MOONLIGHT_DECODER:-$DECODER}"
|
||||
CODEC="${VDI_MOONLIGHT_CODEC:-$CODEC}"
|
||||
case "$DECODER" in
|
||||
software|hardware|auto) ;;
|
||||
*) log "未知解码器 $DECODER,回退 software"; DECODER=software ;;
|
||||
esac
|
||||
case "$CODEC" in
|
||||
H.264|HEVC|AV1|auto) ;;
|
||||
*) log "未知视频编码 $CODEC,回退 H.264"; CODEC=H.264 ;;
|
||||
esac
|
||||
PERFORMANCE_OVERLAY="${VDI_STREAM_STATS:-$PERFORMANCE_OVERLAY}"
|
||||
if [ -z "$HOST" ]; then
|
||||
log "配置缺失或缺少 host: $CONF"
|
||||
exit 2
|
||||
@ -227,6 +270,10 @@ fi
|
||||
|
||||
export DISPLAY="${VDI_DISPLAY:-:0}"
|
||||
export XAUTHORITY="${VDI_XAUTHORITY:-$HOME/.Xauthority}"
|
||||
export SDL_RENDER_DRIVER="${VDI_SDL_RENDER_DRIVER:-opengles2}"
|
||||
export SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR="${VDI_SDL_BYPASS_COMPOSITOR:-1}"
|
||||
[ -n "${VDI_SDL_FORCE_EGL:-}" ] && export SDL_VIDEO_X11_FORCE_EGL="$VDI_SDL_FORCE_EGL"
|
||||
[ -n "${VDI_SDL_VIDEODRIVER:-}" ] && export SDL_VIDEODRIVER="$VDI_SDL_VIDEODRIVER"
|
||||
|
||||
disable_screensaver
|
||||
kill_stale
|
||||
|
||||
20
terminal/kiosk-shell/scripts/vdi-moonlight-rkmpp
Normal file
@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
# Select explicitly after RKMPP decode + real stream validation. Does not replace
|
||||
# the distribution Moonlight or add a second cursor.
|
||||
set -eu
|
||||
task_root="${VDI_RKMPP_BUILD_ROOT:-$HOME/vdi-build/rkmpp-experiment}"
|
||||
client="${VDI_RKMPP_CLIENT:-$task_root/build/moonlight/app/moonlight}"
|
||||
if [ ! -x "$client" ] || [ ! -r /dev/mpp_service ] || [ ! -w /dev/mpp_service ]; then
|
||||
echo 'RKMPP client or device access unavailable' >&2
|
||||
exit 78
|
||||
fi
|
||||
export LD_LIBRARY_PATH="$task_root/runtime/lib:$task_root/deps/usr/lib/aarch64-linux-gnu${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
export QML2_IMPORT_PATH="$task_root/deps/usr/lib/aarch64-linux-gnu/qt5/qml${QML2_IMPORT_PATH:+:$QML2_IMPORT_PATH}"
|
||||
export QT_PLUGIN_PATH="$task_root/deps/usr/lib/aarch64-linux-gnu/qt5/plugins${QT_PLUGIN_PATH:+:$QT_PLUGIN_PATH}"
|
||||
export GL_IS_SLOW="${GL_IS_SLOW:-0}"
|
||||
export H264_DECODER_HINT=h264_rkmpp
|
||||
export HEVC_DECODER_HINT=hevc_rkmpp
|
||||
# Only affects unpaced rendering in the patched client. Leave the last presented
|
||||
# frame and decoder references intact; replace only waiting decoded frames.
|
||||
export VDI_LATEST_FRAME="${VDI_LATEST_FRAME:-1}"
|
||||
exec "$client" "$@"
|
||||
@ -82,10 +82,10 @@ void DesktopListPage::rebuildCards() {
|
||||
|
||||
for (const DesktopInfo& d : desktops_) {
|
||||
auto* card = new QFrame(this);
|
||||
card->setObjectName(QStringLiteral("desktopCard"));
|
||||
card->setMinimumHeight(96);
|
||||
card->setStyleSheet(QStringLiteral(
|
||||
"QFrame { background: #1a2233; border: 1px solid #2b3654; border-radius: 10px; }"
|
||||
"QFrame:hover { border: 1px solid #2f6feb; }"
|
||||
"QFrame#desktopCard { background: #1a2233; border: 1px solid #2b3654; border-radius: 10px; }"
|
||||
"QLabel { border: none; background: transparent; }"));
|
||||
|
||||
auto* row = new QHBoxLayout(card);
|
||||
|
||||
@ -64,7 +64,6 @@ void MainWindow::setupUi() {
|
||||
QStringLiteral("QWidget { background: #0f1420; color: #e6e9ef; }"
|
||||
"QLineEdit { background: #1a2233; border: 1px solid #2b3654; "
|
||||
"border-radius: 4px; padding: 8px; color: #e6e9ef; }"
|
||||
"QLineEdit:focus { border: 1px solid #2f6feb; }"
|
||||
"QPushButton { background: #232d44; border: 1px solid #2b3654; "
|
||||
"border-radius: 6px; color: #e6e9ef; }"
|
||||
"QPushButton:hover { background: #2b3654; }"));
|
||||
@ -289,11 +288,8 @@ void MainWindow::onEditDesktopRequested(const QString& desktopId) {
|
||||
}
|
||||
|
||||
bool MainWindow::startMoonlightSession(const ConnectionTicket& ticket, quint64 attempt) {
|
||||
MoonlightSession::Options opts;
|
||||
opts.decoder = QStringLiteral("software");
|
||||
opts.videoCodec = QStringLiteral("H.264");
|
||||
opts.audioOnHost = true;
|
||||
moonlightSession_->setOptions(opts);
|
||||
moonlightSession_->setOptions(MoonlightSession::optionsFromEnvironment(
|
||||
QProcessEnvironment::systemEnvironment()));
|
||||
|
||||
phaseClock_.restart();
|
||||
connectionPhase_ = ConnectionPhase::kProcessStart;
|
||||
|
||||
@ -14,7 +14,11 @@ constexpr int kReadyStableMs = 750;
|
||||
constexpr int kTerminateGraceMs = 2000;
|
||||
|
||||
bool isTestDecodeLine(const QByteArray& line) {
|
||||
return line.toLower().contains("test decode successful");
|
||||
const QByteArray lower = line.toLower();
|
||||
// Hardware decoders use a separate test context. Upstream logs this only
|
||||
// after that context has successfully decoded and validated a test frame.
|
||||
return lower.contains("test decode successful") ||
|
||||
lower.contains("not reusing test decoder for ");
|
||||
}
|
||||
|
||||
bool isRendererLine(const QByteArray& line) {
|
||||
@ -105,6 +109,66 @@ void MoonlightSession::setOptions(const Options& options) {
|
||||
options_ = options;
|
||||
}
|
||||
|
||||
MoonlightSession::Options MoonlightSession::optionsFromEnvironment(
|
||||
const QProcessEnvironment& environment) {
|
||||
Options options;
|
||||
const QString profile = environment.value(QStringLiteral("VDI_STREAM_PROFILE"));
|
||||
if (profile == QStringLiteral("low-latency")) {
|
||||
options.profile = profile;
|
||||
options.vsync = false;
|
||||
options.framePacing = false;
|
||||
} else if (profile == QStringLiteral("diagnostic")) {
|
||||
options.profile = profile;
|
||||
options.performanceOverlay = true;
|
||||
}
|
||||
// Statistics must be independently selectable for a fair profile A/B test.
|
||||
if (environment.contains(QStringLiteral("VDI_STREAM_STATS"))) {
|
||||
options.performanceOverlay = environment.value(QStringLiteral("VDI_STREAM_STATS")) == QStringLiteral("1");
|
||||
}
|
||||
const QString decoder = environment.value(QStringLiteral("VDI_MOONLIGHT_DECODER"));
|
||||
if (QStringList{QStringLiteral("software"), QStringLiteral("hardware"),
|
||||
QStringLiteral("auto")}.contains(decoder)) {
|
||||
options.decoder = decoder;
|
||||
}
|
||||
const QString codec = environment.value(QStringLiteral("VDI_MOONLIGHT_CODEC"));
|
||||
if (QStringList{QStringLiteral("H.264"), QStringLiteral("HEVC"),
|
||||
QStringLiteral("AV1"), QStringLiteral("auto")}.contains(codec)) {
|
||||
options.videoCodec = codec;
|
||||
}
|
||||
const QString program = environment.value(QStringLiteral("VDI_MOONLIGHT_PROGRAM"));
|
||||
if (!program.isEmpty()) {
|
||||
options.program = program;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
QStringList MoonlightSession::buildStreamArguments(const ConnectionTicket& ticket,
|
||||
const Options& options) {
|
||||
const int bitrateKbps = ticket.width >= 2560 ? 30000 : 20000;
|
||||
QStringList args;
|
||||
args << QStringLiteral("stream")
|
||||
<< ticket.endpoint
|
||||
<< ticket.app
|
||||
<< QStringLiteral("--resolution")
|
||||
<< QStringLiteral("%1x%2").arg(ticket.width).arg(ticket.height)
|
||||
<< QStringLiteral("--fps") << QString::number(ticket.fps)
|
||||
<< QStringLiteral("--bitrate") << QString::number(bitrateKbps)
|
||||
<< QStringLiteral("--display-mode") << QStringLiteral("fullscreen")
|
||||
<< QStringLiteral("--video-codec") << options.videoCodec
|
||||
<< QStringLiteral("--video-decoder") << options.decoder
|
||||
<< QStringLiteral("--absolute-mouse")
|
||||
<< QStringLiteral("--keep-awake")
|
||||
<< (options.vsync ? QStringLiteral("--vsync") : QStringLiteral("--no-vsync"))
|
||||
<< (options.framePacing ? QStringLiteral("--frame-pacing")
|
||||
: QStringLiteral("--no-frame-pacing"));
|
||||
if (options.performanceOverlay) {
|
||||
args << QStringLiteral("--performance-overlay");
|
||||
}
|
||||
args << (options.audioOnHost ? QStringLiteral("--audio-on-host")
|
||||
: QStringLiteral("--no-audio-on-host"));
|
||||
return args;
|
||||
}
|
||||
|
||||
bool MoonlightSession::isRunning() const {
|
||||
return process_->state() != QProcess::NotRunning;
|
||||
}
|
||||
@ -156,34 +220,26 @@ bool MoonlightSession::start(const ConnectionTicket& ticket, EventCallback callb
|
||||
readyTimer_->stop();
|
||||
killTimer_->stop();
|
||||
|
||||
process_->setProgram(QStringLiteral("moonlight-qt"));
|
||||
process_->setProgram(options_.program);
|
||||
QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
|
||||
environment.insert(QStringLiteral("GL_IS_SLOW"), QStringLiteral("0"));
|
||||
environment.insert(QStringLiteral("SDL_RENDER_DRIVER"), QStringLiteral("opengles2"));
|
||||
environment.insert(QStringLiteral("SDL_RENDER_DRIVER"),
|
||||
environment.value(QStringLiteral("VDI_SDL_RENDER_DRIVER"), QStringLiteral("opengles2")));
|
||||
// Xorg下绕过桌面合成器;Wayland/KMS部署时可通过SDL_VIDEODRIVER切换,
|
||||
// 不在客户端里硬编码会话类型,避免当前Xorg镜像无法启动。
|
||||
environment.insert(QStringLiteral("SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR"),
|
||||
environment.value(QStringLiteral("VDI_SDL_BYPASS_COMPOSITOR"), QStringLiteral("1")));
|
||||
const QString forceEgl = qEnvironmentVariable("VDI_SDL_FORCE_EGL");
|
||||
if (!forceEgl.isEmpty()) {
|
||||
environment.insert(QStringLiteral("SDL_VIDEO_X11_FORCE_EGL"), forceEgl);
|
||||
}
|
||||
const QString sdlVideoDriver = qEnvironmentVariable("VDI_SDL_VIDEODRIVER");
|
||||
if (!sdlVideoDriver.isEmpty()) {
|
||||
environment.insert(QStringLiteral("SDL_VIDEODRIVER"), sdlVideoDriver);
|
||||
}
|
||||
process_->setProcessEnvironment(environment);
|
||||
|
||||
const int bitrateKbps = ticket.width >= 2560 ? 30000 : 20000;
|
||||
QStringList args;
|
||||
args << QStringLiteral("stream")
|
||||
<< ticket.endpoint
|
||||
<< ticket.app
|
||||
<< QStringLiteral("--resolution")
|
||||
<< QStringLiteral("%1x%2").arg(ticket.width).arg(ticket.height)
|
||||
<< QStringLiteral("--fps") << QString::number(ticket.fps)
|
||||
<< QStringLiteral("--bitrate") << QString::number(bitrateKbps)
|
||||
<< QStringLiteral("--display-mode") << QStringLiteral("fullscreen")
|
||||
<< QStringLiteral("--video-codec") << options_.videoCodec
|
||||
<< QStringLiteral("--video-decoder") << options_.decoder
|
||||
<< QStringLiteral("--absolute-mouse")
|
||||
<< QStringLiteral("--keep-awake");
|
||||
args << (options_.vsync ? QStringLiteral("--vsync") : QStringLiteral("--no-vsync"));
|
||||
args << (options_.framePacing ? QStringLiteral("--frame-pacing")
|
||||
: QStringLiteral("--no-frame-pacing"));
|
||||
if (options_.performanceOverlay) {
|
||||
args << QStringLiteral("--performance-overlay");
|
||||
}
|
||||
args << (options_.audioOnHost ? QStringLiteral("--audio-on-host")
|
||||
: QStringLiteral("--no-audio-on-host"));
|
||||
const QStringList args = buildStreamArguments(ticket, options_);
|
||||
process_->setArguments(args);
|
||||
|
||||
const QString logDir = QDir::homePath() + QStringLiteral("/vdi-terminal/logs");
|
||||
@ -191,6 +247,23 @@ bool MoonlightSession::start(const ConnectionTicket& ticket, EventCallback callb
|
||||
logPath_ = logDir + QStringLiteral("/moonlight-%1.log")
|
||||
.arg(QDate::currentDate().toString(QStringLiteral("yyyyMMdd")));
|
||||
|
||||
// 把最终生效的环境和参数写入日志,避免只看Moonlight叠图时无法判断
|
||||
// 产品入口到底使用了哪一套呈现策略。
|
||||
QFile launchLog(logPath_);
|
||||
if (launchLog.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) {
|
||||
QTextStream stream(&launchLog);
|
||||
stream << "\n[VDI launch]\n"
|
||||
<< "profile=" << options_.profile << "\n"
|
||||
<< "program=" << options_.program << "\n"
|
||||
<< "decoder=" << options_.decoder << "\n"
|
||||
<< "codec=" << options_.videoCodec << "\n"
|
||||
<< "vsync=" << (options_.vsync ? "1" : "0") << "\n"
|
||||
<< "frame-pacing=" << (options_.framePacing ? "1" : "0") << "\n"
|
||||
<< "renderer=" << environment.value(QStringLiteral("SDL_RENDER_DRIVER")) << "\n"
|
||||
<< "video-driver=" << environment.value(QStringLiteral("SDL_VIDEODRIVER")) << "\n"
|
||||
<< "args=" << args.join(QLatin1Char(' ')) << "\n";
|
||||
}
|
||||
|
||||
process_->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QProcess>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
|
||||
@ -37,7 +39,13 @@ class MoonlightSession : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// 产品入口与调试脚本遵循相同的profile语义。
|
||||
// smooth:优先稳定呈现,适合当前2K20/2K30;
|
||||
// low-latency:关闭客户端额外的同步等待,适合1080p60 A/B;
|
||||
// diagnostic:在smooth基础上打开Moonlight性能叠图。
|
||||
struct Options {
|
||||
QString program = QStringLiteral("moonlight-qt");
|
||||
QString profile = QStringLiteral("smooth");
|
||||
bool vsync = true;
|
||||
bool framePacing = true;
|
||||
bool performanceOverlay = false;
|
||||
@ -64,6 +72,9 @@ public:
|
||||
~MoonlightSession() override;
|
||||
|
||||
void setOptions(const Options& options);
|
||||
static Options optionsFromEnvironment(const QProcessEnvironment& environment);
|
||||
static QStringList buildStreamArguments(const ConnectionTicket& ticket,
|
||||
const Options& options);
|
||||
bool start(const ConnectionTicket& ticket, EventCallback callback);
|
||||
void stop();
|
||||
bool isRunning() const;
|
||||
|
||||
140
terminal/kiosk-shell/tests/test_display_guard.py
Normal file
@ -0,0 +1,140 @@
|
||||
"""Failure and hotplug scenarios; no real display or sleep required."""
|
||||
|
||||
from pathlib import Path
|
||||
import runpy
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
guard_module = runpy.run_path(str(Path(__file__).resolve().parents[1] / "scripts/vdi-display-guard"))
|
||||
Guard = guard_module["Guard"]
|
||||
MODE = guard_module["MODE"]
|
||||
|
||||
|
||||
class FakeRandR:
|
||||
def __init__(self):
|
||||
self.connected = True
|
||||
self.defined = True
|
||||
self.attached = True
|
||||
self.active = "1920x1440"
|
||||
self.writes = []
|
||||
self.fail_apply = False
|
||||
self.query_error = False
|
||||
self.keep_wrong_mode = False
|
||||
|
||||
def __call__(self, *args):
|
||||
if args == ("--current",):
|
||||
if self.query_error:
|
||||
raise RuntimeError("Can't open display :0")
|
||||
status = "connected primary " + ("2560x1440+0+0" if self.active == MODE else "1920x1440+0+0")
|
||||
if not self.connected:
|
||||
status = "disconnected"
|
||||
query = "Screen 0: current 1920 x 1440\nHDMI-1 " + status + " (normal)\n"
|
||||
if self.connected:
|
||||
query += " 1920x1440 75.00" + ("*" if self.active != MODE else "") + "\n"
|
||||
if self.attached:
|
||||
query += " " + MODE + " 60.00" + ("*" if self.active == MODE else "") + "\n"
|
||||
if self.defined and (not self.attached or not self.connected):
|
||||
query += " " + MODE + " (0x189) 297.000MHz +HSync -VSync\n"
|
||||
query += " h: width 2560 start 2608\n v: height 1440 start 1443\n"
|
||||
return query
|
||||
self.writes.append(args)
|
||||
if args[0] == "--newmode":
|
||||
if self.defined:
|
||||
raise RuntimeError("BadName: duplicate mode")
|
||||
self.defined = True
|
||||
elif args[0] == "--addmode":
|
||||
assert self.defined
|
||||
self.attached = True
|
||||
elif args[0] == "--output":
|
||||
if self.fail_apply:
|
||||
raise RuntimeError("Configure crtc failed")
|
||||
assert self.attached
|
||||
if not self.keep_wrong_mode:
|
||||
self.active = MODE
|
||||
return ""
|
||||
|
||||
|
||||
class DisplayGuardTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.xr = FakeRandR()
|
||||
self.logs = []
|
||||
self.guard = Guard(self.xr, self.logs.append)
|
||||
|
||||
def tick(self, now):
|
||||
with patch("time.monotonic", return_value=now):
|
||||
return self.guard.step(now)
|
||||
|
||||
def test_mode_drift_restores_after_settling(self):
|
||||
self.assertFalse(self.tick(0))
|
||||
self.assertEqual(self.xr.writes, [])
|
||||
self.assertTrue(self.tick(2))
|
||||
self.assertEqual(len(self.xr.writes), 1)
|
||||
self.assertEqual(self.xr.active, MODE)
|
||||
|
||||
def test_healthy_display_does_not_modeset_or_repeat_logs(self):
|
||||
self.xr.active = MODE
|
||||
for now in range(0, 100, 2):
|
||||
self.assertTrue(self.tick(now))
|
||||
self.assertEqual(self.xr.writes, [])
|
||||
self.assertEqual(len(self.logs), 1)
|
||||
|
||||
def test_disconnected_never_writes_and_reconnect_settles(self):
|
||||
self.tick(0)
|
||||
self.xr.connected = False
|
||||
for now in range(2, 20, 2):
|
||||
self.assertFalse(self.tick(now))
|
||||
self.assertEqual(self.xr.writes, [])
|
||||
self.xr.connected = True
|
||||
self.assertFalse(self.tick(20))
|
||||
self.assertTrue(self.tick(22))
|
||||
|
||||
def test_new_x_server_recreates_and_attaches_mode(self):
|
||||
self.xr.defined = self.xr.attached = False
|
||||
self.tick(0)
|
||||
self.assertTrue(self.tick(2))
|
||||
self.assertEqual([w[0] for w in self.xr.writes], ["--newmode", "--addmode", "--output"])
|
||||
|
||||
def test_hotplug_detached_mode_is_not_created_twice(self):
|
||||
self.xr.attached = False
|
||||
self.tick(0)
|
||||
self.assertTrue(self.tick(2))
|
||||
self.assertEqual([w[0] for w in self.xr.writes], ["--addmode", "--output"])
|
||||
|
||||
def test_late_desktop_settings_overwrite_is_corrected_again(self):
|
||||
self.tick(0)
|
||||
self.assertTrue(self.tick(2))
|
||||
self.xr.active = "1920x1440"
|
||||
self.assertFalse(self.tick(4))
|
||||
self.assertTrue(self.tick(6))
|
||||
self.assertEqual(len(self.xr.writes), 2)
|
||||
|
||||
def test_modeset_failure_backs_off_and_eventually_recovers(self):
|
||||
self.xr.fail_apply = True
|
||||
self.tick(0)
|
||||
self.tick(2) # retry at 4
|
||||
self.tick(4) # retry at 8
|
||||
self.tick(6) # no write
|
||||
self.assertEqual(len(self.xr.writes), 2)
|
||||
self.xr.fail_apply = False
|
||||
self.assertTrue(self.tick(8))
|
||||
self.assertEqual(len(self.xr.writes), 3)
|
||||
|
||||
def test_apply_success_must_be_verified(self):
|
||||
self.xr.keep_wrong_mode = True
|
||||
self.tick(0)
|
||||
self.assertFalse(self.tick(2))
|
||||
self.assertIn("not retained", self.logs[-1])
|
||||
|
||||
def test_x11_unavailable_does_not_write_and_then_recovers(self):
|
||||
self.xr.query_error = True
|
||||
for now in range(0, 20, 2):
|
||||
self.assertFalse(self.tick(now))
|
||||
self.assertEqual(self.xr.writes, [])
|
||||
self.assertEqual(len(self.logs), 1)
|
||||
self.xr.query_error = False
|
||||
self.assertFalse(self.tick(20))
|
||||
self.assertTrue(self.tick(22))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@ -10,7 +10,11 @@ class MoonlightSessionTest : public QObject {
|
||||
private slots:
|
||||
void parsesSplitReadyMarkers();
|
||||
void requiresBothReadyMarkers();
|
||||
void acceptsSeparateHardwareTestDecoder();
|
||||
void rejectsSecondStart();
|
||||
void buildsConsistentStreamArguments();
|
||||
void selectsProfileWithoutLosingStats();
|
||||
void rejectsInvalidDecoderOverride();
|
||||
};
|
||||
|
||||
void MoonlightSessionTest::parsesSplitReadyMarkers() {
|
||||
@ -38,6 +42,19 @@ void MoonlightSessionTest::requiresBothReadyMarkers() {
|
||||
QVERIFY(!parser.isReady());
|
||||
}
|
||||
|
||||
void MoonlightSessionTest::acceptsSeparateHardwareTestDecoder() {
|
||||
MoonlightOutputParser parser;
|
||||
parser.append("Using custom H.264 decoder (H264_DECODER_HINT): h264_rkmpp\n");
|
||||
QVERIFY(!parser.isReady());
|
||||
parser.append("Not reusing test decoder for h264_rkmpp\n");
|
||||
QVERIFY(parser.hasTestDecode());
|
||||
QVERIFY(!parser.isReady());
|
||||
parser.append("Renderer 'EGL' with 'DRM' backend chosen\n");
|
||||
QVERIFY(parser.isReady());
|
||||
parser.append("Connection terminated: -1\n");
|
||||
QVERIFY(!parser.isReady());
|
||||
}
|
||||
|
||||
void MoonlightSessionTest::rejectsSecondStart() {
|
||||
QTemporaryDir tempDir;
|
||||
QVERIFY(tempDir.isValid());
|
||||
@ -90,5 +107,61 @@ void MoonlightSessionTest::rejectsSecondStart() {
|
||||
qputenv("PATH", oldPath);
|
||||
}
|
||||
|
||||
void MoonlightSessionTest::buildsConsistentStreamArguments() {
|
||||
ConnectionTicket ticket;
|
||||
ticket.endpoint = QStringLiteral("192.168.1.70");
|
||||
ticket.app = QStringLiteral("Desktop");
|
||||
ticket.width = 2560;
|
||||
ticket.height = 1440;
|
||||
ticket.fps = 30;
|
||||
|
||||
MoonlightSession::Options options;
|
||||
options.profile = QStringLiteral("low-latency");
|
||||
options.decoder = QStringLiteral("software");
|
||||
options.videoCodec = QStringLiteral("H.264");
|
||||
options.vsync = false;
|
||||
options.framePacing = false;
|
||||
options.performanceOverlay = true;
|
||||
|
||||
const QStringList args = MoonlightSession::buildStreamArguments(ticket, options);
|
||||
QVERIFY(args.contains(QStringLiteral("--resolution")));
|
||||
QVERIFY(args.contains(QStringLiteral("2560x1440")));
|
||||
QVERIFY(args.contains(QStringLiteral("--fps")));
|
||||
QVERIFY(args.contains(QStringLiteral("30")));
|
||||
QVERIFY(args.contains(QStringLiteral("--bitrate")));
|
||||
QVERIFY(args.contains(QStringLiteral("30000")));
|
||||
QVERIFY(args.contains(QStringLiteral("--no-vsync")));
|
||||
QVERIFY(args.contains(QStringLiteral("--no-frame-pacing")));
|
||||
QVERIFY(args.contains(QStringLiteral("--performance-overlay")));
|
||||
QVERIFY(args.contains(QStringLiteral("--absolute-mouse")));
|
||||
}
|
||||
|
||||
void MoonlightSessionTest::selectsProfileWithoutLosingStats() {
|
||||
QProcessEnvironment environment;
|
||||
environment.insert(QStringLiteral("VDI_STREAM_PROFILE"), QStringLiteral("low-latency"));
|
||||
environment.insert(QStringLiteral("VDI_STREAM_STATS"), QStringLiteral("1"));
|
||||
auto options = MoonlightSession::optionsFromEnvironment(environment);
|
||||
QVERIFY(!options.vsync);
|
||||
QVERIFY(!options.framePacing);
|
||||
QVERIFY(options.performanceOverlay);
|
||||
environment.insert(QStringLiteral("VDI_STREAM_PROFILE"), QStringLiteral("smooth"));
|
||||
options = MoonlightSession::optionsFromEnvironment(environment);
|
||||
QVERIFY(options.vsync);
|
||||
QVERIFY(options.framePacing);
|
||||
QVERIFY(options.performanceOverlay);
|
||||
}
|
||||
|
||||
void MoonlightSessionTest::rejectsInvalidDecoderOverride() {
|
||||
QProcessEnvironment environment;
|
||||
environment.insert(QStringLiteral("VDI_MOONLIGHT_DECODER"), QStringLiteral("h264_rkmpp"));
|
||||
environment.insert(QStringLiteral("VDI_STREAM_PROFILE"), QStringLiteral("invalid"));
|
||||
auto options = MoonlightSession::optionsFromEnvironment(environment);
|
||||
QCOMPARE(options.decoder, QStringLiteral("software"));
|
||||
QCOMPARE(options.profile, QStringLiteral("smooth"));
|
||||
environment.insert(QStringLiteral("VDI_MOONLIGHT_DECODER"), QStringLiteral("hardware"));
|
||||
options = MoonlightSession::optionsFromEnvironment(environment);
|
||||
QCOMPARE(options.decoder, QStringLiteral("hardware"));
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(MoonlightSessionTest)
|
||||
#include "test_moonlight_session.moc"
|
||||
|
||||
40
terminal/moonlight/README.md
Normal file
@ -0,0 +1,40 @@
|
||||
# VDI Moonlight 交互优化补丁
|
||||
|
||||
本目录维护当前 RK3528 / Xorg POC 私有客户端的源码修改,不替换系统 Moonlight。
|
||||
|
||||
基线:Moonlight Qt v6.2.0 `de2467e433821664cdd2224aad8c89a625be1ad9`,其检出的 moonlight-common-c 子模块保持对应版本。MPP、FFmpeg 版本仍由 `tools/build-rkmpp-client.sh` 固定。
|
||||
|
||||
## 补丁
|
||||
|
||||
- `0001-vdi-input-and-latest-frame.patch` 在 Moonlight Qt 根目录应用。鼠标移动只合并队首连续事件,遇到按钮、键盘、窗口、呈现事件或其他鼠标设备立即停止;每次最多额外合并 64 个事件。绝对模式在发送按键前使用该按键事件的坐标。低延迟队列可选地把已等待的解码帧替换成新帧。
|
||||
- `0002-vdi-absolute-click-barrier.patch` 在 `moonlight-common-c/moonlight-common-c` 中应用。鼠标按钮封住此前的位置批次,后续移动只能进入新批次;发送线程只锁定自己的批次,避免旧包出队时误清除新批次。所有包依旧走原可靠鼠标通道,保留 1ms 合并限流和原坐标边界修正。
|
||||
- `0003-vdi-input-priority.patch` 在 Qt 根目录应用。可选地让帧就绪后的连续输入先执行,最多 32 条或 2ms,不能跨窗口/焦点/其他事件。`VDI_INPUT_PRIORITY=1` 才启用,默认关闭。另提供 `VDI_INPUT_TIMING=1` 的汇总统计,区分 SDL 输入派发年龄与主线程呈现调用耗时,不代表端到端延迟。
|
||||
|
||||
2026-11-03 的现场 RKMPP/EGL 使用独立 PacerRender 线程,诊断会话主线程 render 调用数为 0;因此第三补丁的新调度没有已证明的现场收益,未启用。诊断候选二进制保存为 `moonlight.input-priority-20261103`;默认客户端已恢复到本轮前 SHA256 `35de7b1a4ade583823b23b5f2e012307f6d0a3848c8eb97bd6d4de9660afa00f`。详细计划/初测限制见 `docs/mouse-optimization-plan-20261103.md`,独立光标接入设计见 `docs/independent-cursor-design-20261103.md`。
|
||||
|
||||
`VDI_LATEST_FRAME=1` 只在没有 VSync pacing source 的呈现队列生效。最多保留一个待呈现解码帧,丢弃数计入原 `pacerDroppedFrames`。不丢压缩包,不改变 H.264 参考链,也不提前释放正在呈现或延迟释放的上一帧。未设置或设为 `0` 时保留上游帧队列策略;kiosk 私有 wrapper 默认设为 `1`。smooth 档仍使用原 pacing 行为。
|
||||
|
||||
这些补丁不增加本地光标,不隐藏 Windows 光标,不改变控制协议。远程光标仍随视频显示,其延迟仍受服务器捕获/编码、网络、解码和显示影响。
|
||||
|
||||
## 构建与测试
|
||||
|
||||
在盒子上运行构建器时,将本目录的 `patches/` 一起复制过去,通过 `VDI_MOONLIGHT_PATCH_DIR` 指定目录。构建器先检查固定提交,再检查补丁:已完整应用则跳过;上下文不匹配则失败,不强行覆盖其他修改。
|
||||
|
||||
```bash
|
||||
VDI_BUILD_STAGE=moonlight \
|
||||
VDI_MOONLIGHT_PATCH_DIR="$HOME/vdi-build/rkmpp-experiment/patches" \
|
||||
bash tools/build-rkmpp-client.sh
|
||||
```
|
||||
|
||||
`tests/` 的文件复制到盒子 `$VDI_RKMPP_BUILD_ROOT/latency-tests/` 后运行:
|
||||
|
||||
```bash
|
||||
bash tools/test-moonlight-latency.sh
|
||||
VDI_TEST_SANITIZE=1 ASAN_OPTIONS=detect_leaks=1 bash tools/test-moonlight-latency.sh
|
||||
```
|
||||
|
||||
测试直接包含实际修改后的 SDL helper、AVFrame 队列 helper 与 `InputStream.c`,并链接客户端实际使用的 native 队列/线程库。覆盖跨点击合并、键盘/呈现边界、工作量上限、触摸隔离、200 帧的积压替换、已呈现帧所有权及 1,000 轮“移动→按下→移动→释放→移动”的发送线程滞后场景。测试显式启用断言,避免上游 release 头文件的 NDEBUG 使检查失效。
|
||||
|
||||
新增 `test_input_priority.cpp` 验证优先调度不越过焦点/窗口/退出/解码器重置事件,保持输入 FIFO,隔离其他窗口与合成触摸,并验证数量与时间限制。普通与 ASAN 版本均通过。当前 RKMPP/EGL 没有主线程呈现事件,新调度开关不能用作该路径的性能提升宣传。
|
||||
|
||||
现场数据、局限与完整回退入口见 `docs/input-rendering-optimization-20261103.md`。
|
||||
271
terminal/moonlight/patches/0001-vdi-input-and-latest-frame.patch
Normal file
@ -0,0 +1,271 @@
|
||||
--- a/app/streaming/input/mouse.cpp
|
||||
+++ b/app/streaming/input/mouse.cpp
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "input.h"
|
||||
+#include "vdi_mouse_batch.h"
|
||||
|
||||
#include <Limelight.h>
|
||||
#include "SDL_compat.h"
|
||||
@@ -84,6 +85,11 @@
|
||||
button = BUTTON_RIGHT;
|
||||
}
|
||||
|
||||
+ // Button coordinates are captured with this event, not a later mouse state.
|
||||
+ if (m_AbsoluteMouseMode) {
|
||||
+ sendAbsoluteMousePosition(event->x, event->y);
|
||||
+ }
|
||||
+
|
||||
LiSendMouseButtonEvent(event->state == SDL_PRESSED ?
|
||||
BUTTON_ACTION_PRESS :
|
||||
BUTTON_ACTION_RELEASE,
|
||||
@@ -101,81 +107,78 @@
|
||||
return;
|
||||
}
|
||||
|
||||
- // Batch all pending mouse motion events to save CPU time
|
||||
- Sint32 x = event->x, y = event->y, xrel = event->xrel, yrel = event->yrel;
|
||||
- SDL_Event nextEvent;
|
||||
- while (SDL_PeepEvents(&nextEvent, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) > 0) {
|
||||
- event = &nextEvent.motion;
|
||||
-
|
||||
- // Ignore synthetic mouse events
|
||||
- if (event->which != SDL_TOUCH_MOUSEID) {
|
||||
- x = event->x;
|
||||
- y = event->y;
|
||||
- xrel += event->xrel;
|
||||
- yrel += event->yrel;
|
||||
- }
|
||||
- }
|
||||
+ // Coalesce only adjacent motions. Never consume motion past a click/key
|
||||
+ // or render event, and bound work so a fast mouse cannot starve rendering.
|
||||
+ SDL_MouseMotionEvent batched = *event;
|
||||
+ vdiBatchMouseMotion(batched);
|
||||
+ Sint32 x = batched.x, y = batched.y;
|
||||
+ Sint32 xrel = batched.xrel, yrel = batched.yrel;
|
||||
|
||||
// We should not reference the original event anymore
|
||||
event = nullptr;
|
||||
|
||||
if (m_AbsoluteMouseMode) {
|
||||
- int windowWidth, windowHeight;
|
||||
- SDL_GetWindowSize(m_Window, &windowWidth, &windowHeight);
|
||||
-
|
||||
- SDL_Rect src, dst;
|
||||
- bool mouseInVideoRegion;
|
||||
-
|
||||
- src.x = src.y = 0;
|
||||
- src.w = m_StreamWidth;
|
||||
- src.h = m_StreamHeight;
|
||||
-
|
||||
- dst.x = dst.y = 0;
|
||||
- dst.w = windowWidth;
|
||||
- dst.h = windowHeight;
|
||||
-
|
||||
- // Use the stream and window sizes to determine the video region
|
||||
- StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
||||
-
|
||||
- mouseInVideoRegion = isMouseInVideoRegion(x, y, windowWidth, windowHeight);
|
||||
-
|
||||
- // Clamp motion to the video region
|
||||
- x = qMin(qMax(x - dst.x, 0), dst.w);
|
||||
- y = qMin(qMax(y - dst.y, 0), dst.h);
|
||||
-
|
||||
- // Send the mouse position update if one of the following is true:
|
||||
- // a) it is in the video region now
|
||||
- // b) it just left the video region (to ensure the mouse is clamped to the video boundary)
|
||||
- // c) a mouse button is still down from before the cursor left the video region (to allow smooth dragging)
|
||||
- Uint32 buttonState = SDL_GetMouseState(nullptr, nullptr);
|
||||
- if (buttonState == 0) {
|
||||
- if (m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
|
||||
- if (m_NeedsManualCaptureOnLeave) {
|
||||
- // Stop capturing the mouse now
|
||||
- SDL_CaptureMouse(SDL_FALSE);
|
||||
- }
|
||||
- m_PendingMouseButtonsAllUpOnVideoRegionLeave = false;
|
||||
- }
|
||||
- }
|
||||
- if (mouseInVideoRegion || m_MouseWasInVideoRegion || m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
|
||||
- LiSendMousePositionEvent((short)x, (short)y, dst.w, dst.h);
|
||||
- }
|
||||
-
|
||||
- // Adjust the cursor visibility if applicable
|
||||
- if (mouseInVideoRegion ^ m_MouseWasInVideoRegion) {
|
||||
- SDL_ShowCursor((mouseInVideoRegion && m_MouseCursorCapturedVisibilityState == SDL_DISABLE) ? SDL_DISABLE : SDL_ENABLE);
|
||||
- if (!mouseInVideoRegion && buttonState != 0) {
|
||||
- // If we still have a button pressed on leave, wait for that to come up
|
||||
- // before we stop sending mouse position events.
|
||||
- m_PendingMouseButtonsAllUpOnVideoRegionLeave = true;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- m_MouseWasInVideoRegion = mouseInVideoRegion;
|
||||
+ sendAbsoluteMousePosition(x, y);
|
||||
}
|
||||
else {
|
||||
LiSendMouseMoveEvent(xrel, yrel);
|
||||
}
|
||||
+}
|
||||
+
|
||||
+void SdlInputHandler::sendAbsoluteMousePosition(Sint32 x, Sint32 y)
|
||||
+{
|
||||
+ int windowWidth, windowHeight;
|
||||
+ SDL_GetWindowSize(m_Window, &windowWidth, &windowHeight);
|
||||
+
|
||||
+ SDL_Rect src, dst;
|
||||
+ bool mouseInVideoRegion;
|
||||
+
|
||||
+ src.x = src.y = 0;
|
||||
+ src.w = m_StreamWidth;
|
||||
+ src.h = m_StreamHeight;
|
||||
+
|
||||
+ dst.x = dst.y = 0;
|
||||
+ dst.w = windowWidth;
|
||||
+ dst.h = windowHeight;
|
||||
+
|
||||
+ // Use the stream and window sizes to determine the video region
|
||||
+ StreamUtils::scaleSourceToDestinationSurface(&src, &dst);
|
||||
+
|
||||
+ mouseInVideoRegion = isMouseInVideoRegion(x, y, windowWidth, windowHeight);
|
||||
+
|
||||
+ // Clamp motion to the video region
|
||||
+ x = qMin(qMax(x - dst.x, 0), dst.w);
|
||||
+ y = qMin(qMax(y - dst.y, 0), dst.h);
|
||||
+
|
||||
+ // Send the mouse position update if one of the following is true:
|
||||
+ // a) it is in the video region now
|
||||
+ // b) it just left the video region (to ensure the mouse is clamped to the video boundary)
|
||||
+ // c) a mouse button is still down from before the cursor left the video region (to allow smooth dragging)
|
||||
+ Uint32 buttonState = SDL_GetMouseState(nullptr, nullptr);
|
||||
+ if (buttonState == 0) {
|
||||
+ if (m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
|
||||
+ if (m_NeedsManualCaptureOnLeave) {
|
||||
+ // Stop capturing the mouse now
|
||||
+ SDL_CaptureMouse(SDL_FALSE);
|
||||
+ }
|
||||
+ m_PendingMouseButtonsAllUpOnVideoRegionLeave = false;
|
||||
+ }
|
||||
+ }
|
||||
+ if (mouseInVideoRegion || m_MouseWasInVideoRegion || m_PendingMouseButtonsAllUpOnVideoRegionLeave) {
|
||||
+ LiSendMousePositionEvent((short)x, (short)y, dst.w, dst.h);
|
||||
+ }
|
||||
+
|
||||
+ // Adjust the cursor visibility if applicable
|
||||
+ if (mouseInVideoRegion ^ m_MouseWasInVideoRegion) {
|
||||
+ SDL_ShowCursor((mouseInVideoRegion && m_MouseCursorCapturedVisibilityState == SDL_DISABLE) ? SDL_DISABLE : SDL_ENABLE);
|
||||
+ if (!mouseInVideoRegion && buttonState != 0) {
|
||||
+ // If we still have a button pressed on leave, wait for that to come up
|
||||
+ // before we stop sending mouse position events.
|
||||
+ m_PendingMouseButtonsAllUpOnVideoRegionLeave = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ m_MouseWasInVideoRegion = mouseInVideoRegion;
|
||||
}
|
||||
|
||||
void SdlInputHandler::handleMouseWheelEvent(SDL_MouseWheelEvent* event)
|
||||
--- a/app/streaming/input/input.h
|
||||
+++ b/app/streaming/input/input.h
|
||||
@@ -95,6 +95,8 @@
|
||||
void handleMouseButtonEvent(SDL_MouseButtonEvent* event);
|
||||
|
||||
void handleMouseMotionEvent(SDL_MouseMotionEvent* event);
|
||||
+
|
||||
+ void sendAbsoluteMousePosition(Sint32 x, Sint32 y);
|
||||
|
||||
void handleMouseWheelEvent(SDL_MouseWheelEvent* event);
|
||||
|
||||
--- /dev/null
|
||||
+++ b/app/streaming/input/vdi_mouse_batch.h
|
||||
@@ -0,0 +1,22 @@
|
||||
+#pragma once
|
||||
+#include <SDL.h>
|
||||
+
|
||||
+// Only the SDL main thread consumes events; other threads may append events.
|
||||
+inline void vdiBatchMouseMotion(SDL_MouseMotionEvent& motion)
|
||||
+{
|
||||
+ for (int i = 0; i < 64; ++i) {
|
||||
+ SDL_Event next;
|
||||
+ if (SDL_PeepEvents(&next, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) != 1 ||
|
||||
+ next.type != SDL_MOUSEMOTION || next.motion.which != motion.which ||
|
||||
+ next.motion.windowID != motion.windowID || next.motion.state != motion.state) {
|
||||
+ break;
|
||||
+ }
|
||||
+ if (SDL_PeepEvents(&next, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) != 1) {
|
||||
+ break;
|
||||
+ }
|
||||
+ motion.x = next.motion.x;
|
||||
+ motion.y = next.motion.y;
|
||||
+ motion.xrel += next.motion.xrel;
|
||||
+ motion.yrel += next.motion.yrel;
|
||||
+ }
|
||||
+}
|
||||
--- a/app/streaming/video/ffmpeg-renderers/pacer/pacer.cpp
|
||||
+++ b/app/streaming/video/ffmpeg-renderers/pacer/pacer.cpp
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "pacer.h"
|
||||
+#include "vdi_latest_frame.h"
|
||||
#include "streaming/streamutils.h"
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
@@ -34,6 +35,7 @@
|
||||
m_VsyncThread(nullptr),
|
||||
m_DeferredFreeFrame(nullptr),
|
||||
m_Stopping(false),
|
||||
+ m_LatestFrameOnly(qEnvironmentVariableIntValue("VDI_LATEST_FRAME") == 1),
|
||||
m_VsyncSource(nullptr),
|
||||
m_VsyncRenderer(renderer),
|
||||
m_MaxVideoFps(0),
|
||||
@@ -178,7 +180,14 @@
|
||||
|
||||
void Pacer::enqueueFrameForRenderingAndUnlock(AVFrame *frame)
|
||||
{
|
||||
- dropFrameForEnqueue(m_RenderQueue);
|
||||
+ if (m_LatestFrameOnly && m_VsyncSource == nullptr) {
|
||||
+ // Drop only decoded, never presented frames. Keep the decoder reference
|
||||
+ // chain and the deferred free of the last presented frame intact.
|
||||
+ m_VideoStats->pacerDroppedFrames += vdiDiscardQueuedFrames(m_RenderQueue);
|
||||
+ }
|
||||
+ else {
|
||||
+ dropFrameForEnqueue(m_RenderQueue);
|
||||
+ }
|
||||
m_RenderQueue.enqueue(frame);
|
||||
|
||||
m_FrameQueueLock.unlock();
|
||||
@@ -261,6 +270,8 @@
|
||||
|
||||
bool Pacer::initialize(SDL_Window* window, int maxVideoFps, bool enablePacing)
|
||||
{
|
||||
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "VDI latest-frame queue: %s",
|
||||
+ (m_LatestFrameOnly && !enablePacing) ? "enabled" : "disabled");
|
||||
m_MaxVideoFps = maxVideoFps;
|
||||
m_DisplayFps = StreamUtils::getDisplayRefreshRate(window);
|
||||
m_RendererAttributes = m_VsyncRenderer->getRendererAttributes();
|
||||
--- a/app/streaming/video/ffmpeg-renderers/pacer/pacer.h
|
||||
+++ b/app/streaming/video/ffmpeg-renderers/pacer/pacer.h
|
||||
@@ -68,6 +68,7 @@
|
||||
SDL_Thread* m_VsyncThread;
|
||||
AVFrame* m_DeferredFreeFrame;
|
||||
bool m_Stopping;
|
||||
+ bool m_LatestFrameOnly;
|
||||
|
||||
IVsyncSource* m_VsyncSource;
|
||||
IFFmpegRenderer* m_VsyncRenderer;
|
||||
--- /dev/null
|
||||
+++ b/app/streaming/video/ffmpeg-renderers/pacer/vdi_latest_frame.h
|
||||
@@ -0,0 +1,16 @@
|
||||
+#pragma once
|
||||
+#include <QQueue>
|
||||
+extern "C" {
|
||||
+#include <libavutil/frame.h>
|
||||
+}
|
||||
+
|
||||
+inline unsigned vdiDiscardQueuedFrames(QQueue<AVFrame*>& queue)
|
||||
+{
|
||||
+ unsigned dropped = 0;
|
||||
+ while (!queue.isEmpty()) {
|
||||
+ AVFrame* stale = queue.dequeue();
|
||||
+ av_frame_free(&stale);
|
||||
+ ++dropped;
|
||||
+ }
|
||||
+ return dropped;
|
||||
+}
|
||||
143
terminal/moonlight/patches/0002-vdi-absolute-click-barrier.patch
Normal file
@ -0,0 +1,143 @@
|
||||
--- a/src/InputStream.c
|
||||
+++ b/src/InputStream.c
|
||||
@@ -86,11 +86,16 @@
|
||||
int deltaX, deltaY;
|
||||
bool dirty; // Update ready to send (queued packet holder in packetQueue)
|
||||
} currentRelativeMouseState;
|
||||
-static struct {
|
||||
- int x, y;
|
||||
- int width, height;
|
||||
- bool dirty; // Update ready to send (queued packet holder in packetQueue)
|
||||
-} currentAbsoluteMouseState;
|
||||
+// Only this packet may absorb newer positions. A button event seals the batch.
|
||||
+static PPACKET_HOLDER currentQueuedAbsoluteMousePacket;
|
||||
+
|
||||
+static void latchAbsoluteMousePacket(PPACKET_HOLDER holder) {
|
||||
+ PltLockMutex(&batchedInputMutex);
|
||||
+ if (currentQueuedAbsoluteMousePacket == holder) {
|
||||
+ currentQueuedAbsoluteMousePacket = NULL;
|
||||
+ }
|
||||
+ PltUnlockMutex(&batchedInputMutex);
|
||||
+}
|
||||
|
||||
// Initializes the input stream
|
||||
int initializeInputStream(void) {
|
||||
@@ -120,7 +125,7 @@
|
||||
|
||||
memset(currentGamepadSensorState, 0, sizeof(currentGamepadSensorState));
|
||||
memset(¤tRelativeMouseState, 0, sizeof(currentRelativeMouseState));
|
||||
- memset(¤tAbsoluteMouseState, 0, sizeof(currentAbsoluteMouseState));
|
||||
+ currentQueuedAbsoluteMousePacket = NULL;
|
||||
PltCreateMutex(&batchedInputMutex);
|
||||
|
||||
return 0;
|
||||
@@ -444,24 +449,9 @@
|
||||
now = PltGetMillis();
|
||||
}
|
||||
|
||||
- PltLockMutex(&batchedInputMutex);
|
||||
-
|
||||
- // Populate the packet with the latest state
|
||||
- holder->packet.mouseMoveAbs.x = BE16(currentAbsoluteMouseState.x);
|
||||
- holder->packet.mouseMoveAbs.y = BE16(currentAbsoluteMouseState.y);
|
||||
-
|
||||
- // There appears to be a rounding error in GFE's scaling calculation which prevents
|
||||
- // the cursor from reaching the far edge of the screen when streaming at smaller
|
||||
- // resolutions with a higher desktop resolution (like streaming 720p with a desktop
|
||||
- // resolution of 1080p, or streaming 720p/1080p with a desktop resolution of 4K).
|
||||
- // Subtracting one from the reference dimensions seems to work around this issue.
|
||||
- holder->packet.mouseMoveAbs.width = BE16(currentAbsoluteMouseState.width - 1);
|
||||
- holder->packet.mouseMoveAbs.height = BE16(currentAbsoluteMouseState.height - 1);
|
||||
-
|
||||
- // The state change is no longer pending
|
||||
- currentAbsoluteMouseState.dirty = false;
|
||||
-
|
||||
- PltUnlockMutex(&batchedInputMutex);
|
||||
+ // Payload was filled by the producer under the same mutex. Latch
|
||||
+ // only our packet; a later batch may already be queued after a click.
|
||||
+ latchAbsoluteMousePacket(holder);
|
||||
|
||||
lastMousePacketTime = now;
|
||||
}
|
||||
@@ -780,52 +770,37 @@
|
||||
}
|
||||
|
||||
PltLockMutex(&batchedInputMutex);
|
||||
-
|
||||
- // Overwrite the previous mouse location with the new one
|
||||
- currentAbsoluteMouseState.x = x;
|
||||
- currentAbsoluteMouseState.y = y;
|
||||
- currentAbsoluteMouseState.width = referenceWidth;
|
||||
- currentAbsoluteMouseState.height = referenceHeight;
|
||||
-
|
||||
- // Queue a packet holder if this is the only pending absolute mouse event
|
||||
- if (!currentAbsoluteMouseState.dirty) {
|
||||
- // Set the dirty flag to claim ownership of inserting the packet holder
|
||||
- // and unlock to allow other threads to enqueue or process input.
|
||||
- currentAbsoluteMouseState.dirty = true;
|
||||
- PltUnlockMutex(&batchedInputMutex);
|
||||
-
|
||||
+ holder = currentQueuedAbsoluteMousePacket;
|
||||
+ bool newPacket = holder == NULL;
|
||||
+ if (newPacket) {
|
||||
holder = allocatePacketHolder(0);
|
||||
if (holder == NULL) {
|
||||
- currentAbsoluteMouseState.dirty = false;
|
||||
+ PltUnlockMutex(&batchedInputMutex);
|
||||
return -1;
|
||||
}
|
||||
-
|
||||
holder->channelId = CTRL_CHANNEL_MOUSE;
|
||||
-
|
||||
- // TODO: Send this as unreliable sequenced when we have a delayed reliable retransmission thread
|
||||
holder->enetPacketFlags = ENET_PACKET_FLAG_RELIABLE;
|
||||
-
|
||||
holder->packet.mouseMoveAbs.header.size = BE32(sizeof(NV_ABS_MOUSE_MOVE_PACKET) - sizeof(uint32_t));
|
||||
holder->packet.mouseMoveAbs.header.magic = LE32(MOUSE_MOVE_ABS_MAGIC);
|
||||
holder->packet.mouseMoveAbs.unused = 0;
|
||||
-
|
||||
- // Remaining fields are set in the input thread based on the latest currentAbsoluteMouseState values
|
||||
-
|
||||
+ }
|
||||
+ holder->packet.mouseMoveAbs.x = BE16(x);
|
||||
+ holder->packet.mouseMoveAbs.y = BE16(y);
|
||||
+ // Preserve upstream's far-edge rounding workaround.
|
||||
+ holder->packet.mouseMoveAbs.width = BE16(referenceWidth - 1);
|
||||
+ holder->packet.mouseMoveAbs.height = BE16(referenceHeight - 1);
|
||||
+ err = 0;
|
||||
+ if (newPacket) {
|
||||
+ currentQueuedAbsoluteMousePacket = holder;
|
||||
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||
if (err != LBQ_SUCCESS) {
|
||||
+ currentQueuedAbsoluteMousePacket = NULL;
|
||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||
Limelog("Input queue reached maximum size limit\n");
|
||||
freePacketHolder(holder);
|
||||
-
|
||||
- // We weren't able to insert the entry, so let the next call try again
|
||||
- currentAbsoluteMouseState.dirty = false;
|
||||
- }
|
||||
- }
|
||||
- else {
|
||||
- // There's already a packet holder queued to send this event
|
||||
- PltUnlockMutex(&batchedInputMutex);
|
||||
- err = 0;
|
||||
- }
|
||||
+ }
|
||||
+ }
|
||||
+ PltUnlockMutex(&batchedInputMutex);
|
||||
|
||||
// This is not thread safe, but it's not a big deal because callers that want to
|
||||
// use LiSendRelativeMotionAsMousePositionEvent() must not mix these function
|
||||
@@ -872,7 +847,11 @@
|
||||
holder->packet.mouseButton.header.magic = LE32(holder->packet.mouseButton.header.magic);
|
||||
holder->packet.mouseButton.button = (uint8_t)button;
|
||||
|
||||
+ PltLockMutex(&batchedInputMutex);
|
||||
+ // Do not let a later position overwrite the move preceding this click.
|
||||
+ currentQueuedAbsoluteMousePacket = NULL;
|
||||
err = LbqOfferQueueItem(&packetQueue, holder, &holder->entry);
|
||||
+ PltUnlockMutex(&batchedInputMutex);
|
||||
if (err != LBQ_SUCCESS) {
|
||||
LC_ASSERT(err == LBQ_BOUND_EXCEEDED);
|
||||
Limelog("Input queue reached maximum size limit\n");
|
||||
179
terminal/moonlight/patches/0003-vdi-input-priority.patch
Normal file
@ -0,0 +1,179 @@
|
||||
--- a/app/streaming/session.cpp
|
||||
+++ b/app/streaming/session.cpp
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <QImage>
|
||||
#include <QGuiApplication>
|
||||
#include <QCursor>
|
||||
+#include "input/vdi_input_priority.h"
|
||||
#include <QScreen>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
@@ -1962,8 +1963,14 @@
|
||||
|
||||
// Hijack this thread to be the SDL main thread. We have to do this
|
||||
// because we want to suspend all Qt processing until the stream is over.
|
||||
+ VdiInputPriority vdiInputPriority(qEnvironmentVariableIntValue("VDI_INPUT_PRIORITY") == 1,
|
||||
+ SDL_CODE_FRAME_READY);
|
||||
+ VdiInputTiming vdiInputTiming(qEnvironmentVariableIntValue("VDI_INPUT_TIMING") == 1);
|
||||
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "VDI input priority: %s",
|
||||
+ qEnvironmentVariableIntValue("VDI_INPUT_PRIORITY") == 1 ? "enabled" : "disabled");
|
||||
SDL_Event event;
|
||||
for (;;) {
|
||||
+ if (!vdiInputPriority.takeDeferred(event, SDL_GetWindowID(m_Window))) {
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 18) && !defined(STEAM_LINK)
|
||||
// SDL 2.0.18 has a proper wait event implementation that uses platform
|
||||
// support to block on events rather than polling on Windows, macOS, X11,
|
||||
@@ -1995,6 +2002,11 @@
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
+ if (vdiInputPriority.deferFrame(event)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ vdiInputTiming.observe(event, SDL_GetWindowID(m_Window));
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
@@ -2005,7 +2017,9 @@
|
||||
switch (event.user.code) {
|
||||
case SDL_CODE_FRAME_READY:
|
||||
if (m_VideoDecoder != nullptr) {
|
||||
+ const auto renderStart = vdiInputTiming.startRender();
|
||||
m_VideoDecoder->renderFrameOnMainThread();
|
||||
+ vdiInputTiming.endRender(renderStart);
|
||||
}
|
||||
break;
|
||||
case SDL_CODE_FLUSH_WINDOW_EVENT_BARRIER:
|
||||
@@ -2308,6 +2322,7 @@
|
||||
}
|
||||
|
||||
DispatchDeferredCleanup:
|
||||
+ vdiInputTiming.report(vdiInputPriority.prioritized());
|
||||
// Switch back to synchronous logging mode
|
||||
StreamUtils::exitAsyncLoggingMode();
|
||||
|
||||
--- /dev/null
|
||||
+++ b/app/streaming/input/vdi_input_priority.h
|
||||
@@ -0,0 +1,121 @@
|
||||
+#pragma once
|
||||
+#include <SDL.h>
|
||||
+#include <array>
|
||||
+#include <algorithm>
|
||||
+#include <cstdint>
|
||||
+
|
||||
+// SDL main thread only. Inputs may pass one frame-ready notification, never a
|
||||
+// window/focus/quit/other notification or another frame. Input FIFO is preserved.
|
||||
+class VdiInputPriority {
|
||||
+public:
|
||||
+ VdiInputPriority(bool enabled, Sint32 frameCode)
|
||||
+ : m_Enabled(enabled), m_FrameCode(frameCode) {}
|
||||
+
|
||||
+ bool deferFrame(const SDL_Event& event) {
|
||||
+ if (!m_Enabled || event.type != SDL_USEREVENT || event.user.code != m_FrameCode)
|
||||
+ return false;
|
||||
+ SDL_assert(!m_Pending);
|
||||
+ m_Frame = event;
|
||||
+ m_Pending = true;
|
||||
+ m_Count = 0;
|
||||
+ m_Start = SDL_GetPerformanceCounter();
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ bool takeDeferred(SDL_Event& event, Uint32 windowId) {
|
||||
+ if (!m_Pending) return false;
|
||||
+ SDL_Event next;
|
||||
+ const auto elapsed = SDL_GetPerformanceCounter() - m_Start;
|
||||
+ if (m_Count < 32 && elapsed < SDL_GetPerformanceFrequency() / 500 &&
|
||||
+ SDL_PeepEvents(&next, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) == 1 &&
|
||||
+ isInputForWindow(next, windowId) &&
|
||||
+ SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) == 1) {
|
||||
+ ++m_Count;
|
||||
+ ++m_Prioritized;
|
||||
+ return true;
|
||||
+ }
|
||||
+ event = m_Frame;
|
||||
+ m_Pending = false;
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ uint64_t prioritized() const { return m_Prioritized; }
|
||||
+
|
||||
+ static bool isInputForWindow(const SDL_Event& event, Uint32 windowId) {
|
||||
+ switch (event.type) {
|
||||
+ case SDL_MOUSEMOTION:
|
||||
+ return event.motion.windowID == windowId && event.motion.which != SDL_TOUCH_MOUSEID;
|
||||
+ case SDL_MOUSEBUTTONDOWN:
|
||||
+ case SDL_MOUSEBUTTONUP:
|
||||
+ return event.button.windowID == windowId && event.button.which != SDL_TOUCH_MOUSEID;
|
||||
+ case SDL_MOUSEWHEEL:
|
||||
+ return event.wheel.windowID == windowId && event.wheel.which != SDL_TOUCH_MOUSEID;
|
||||
+ case SDL_KEYDOWN:
|
||||
+ case SDL_KEYUP:
|
||||
+ return event.key.windowID == windowId;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+private:
|
||||
+ bool m_Enabled;
|
||||
+ Sint32 m_FrameCode;
|
||||
+ bool m_Pending = false;
|
||||
+ SDL_Event m_Frame{};
|
||||
+ unsigned m_Count = 0;
|
||||
+ Uint64 m_Start = 0;
|
||||
+ uint64_t m_Prioritized = 0;
|
||||
+};
|
||||
+
|
||||
+// Aggregated only when explicitly requested. Ages are SDL queue/dispatch ages,
|
||||
+// not network RTT or physical input-to-photon latency. 0.1 ms histogram bins.
|
||||
+class VdiInputTiming {
|
||||
+public:
|
||||
+ explicit VdiInputTiming(bool enabled) : m_Enabled(enabled) {}
|
||||
+ void observe(const SDL_Event& event, Uint32 windowId) {
|
||||
+ if (!m_Enabled || !event.common.timestamp ||
|
||||
+ !VdiInputPriority::isInputForWindow(event, windowId)) return;
|
||||
+ const Uint32 age = SDL_GetTicks() - event.common.timestamp;
|
||||
+ // Ignore invalid/future synthetic timestamps; subtraction handles wrap.
|
||||
+ if (age < 60000) m_Input.add(Uint64(age) * 10);
|
||||
+ }
|
||||
+ Uint64 startRender() const { return m_Enabled ? SDL_GetPerformanceCounter() : 0; }
|
||||
+ void endRender(Uint64 start) {
|
||||
+ if (m_Enabled) m_Render.add((SDL_GetPerformanceCounter() - start) * 10000 / SDL_GetPerformanceFrequency());
|
||||
+ }
|
||||
+ void report(uint64_t prioritized) const {
|
||||
+ if (!m_Enabled) return;
|
||||
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
+ "VDI input timing: SDL dispatch age only; prioritized=%llu",
|
||||
+ (unsigned long long)prioritized);
|
||||
+ m_Input.report("input dispatch age");
|
||||
+ m_Render.report("main-thread render call");
|
||||
+ }
|
||||
+private:
|
||||
+ struct Histogram {
|
||||
+ std::array<uint64_t, 1024> bins{};
|
||||
+ uint64_t count = 0, total = 0, max = 0;
|
||||
+ void add(uint64_t tenths) {
|
||||
+ ++bins[std::min<uint64_t>(tenths, bins.size()-1)];
|
||||
+ ++count; total += tenths; max = std::max(max, tenths);
|
||||
+ }
|
||||
+ double quantile(unsigned percent) const {
|
||||
+ const uint64_t rank = (count * percent + 99) / 100;
|
||||
+ uint64_t accumulated = 0;
|
||||
+ for (size_t i = 0; i < bins.size(); ++i) {
|
||||
+ accumulated += bins[i];
|
||||
+ if (accumulated >= rank) return i / 10.0;
|
||||
+ }
|
||||
+ return 0;
|
||||
+ }
|
||||
+ void report(const char* label) const {
|
||||
+ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
+ "VDI %s: samples=%llu avg=%.2f p50=%.1f p95=%.1f max=%.1f ms (percentiles capped at 102.3ms)",
|
||||
+ label, (unsigned long long)count, count ? total / (10.0*count) : 0,
|
||||
+ count ? quantile(50) : 0, count ? quantile(95) : 0, max / 10.0);
|
||||
+ }
|
||||
+ };
|
||||
+ bool m_Enabled;
|
||||
+ Histogram m_Input, m_Render;
|
||||
+};
|
||||
63
terminal/moonlight/tests/test_absolute_input.c
Normal file
@ -0,0 +1,63 @@
|
||||
// Include the production implementation so batching can be inspected without
|
||||
// starting a real network connection. Unused transport code is linker-collected.
|
||||
#include "InputStream.c"
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
static PPACKET_HOLDER pop(void) {
|
||||
PPACKET_HOLDER holder = NULL;
|
||||
assert(LbqPollQueueElement(&packetQueue, (void**)&holder) == LBQ_SUCCESS);
|
||||
return holder;
|
||||
}
|
||||
|
||||
static void expectPosition(int x) {
|
||||
PPACKET_HOLDER holder = pop();
|
||||
assert(holder->packet.header.magic == LE32(MOUSE_MOVE_ABS_MAGIC));
|
||||
latchAbsoluteMousePacket(holder);
|
||||
assert(holder->packet.mouseMoveAbs.x == BE16(x));
|
||||
assert((uint16_t)holder->packet.mouseMoveAbs.width == (uint16_t)BE16(2559));
|
||||
freePacketHolder(holder);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
AppVersionQuad[0] = 7;
|
||||
LbqInitializeLinkedBlockingQueue(&packetQueue, MAX_QUEUED_INPUT_PACKETS);
|
||||
LbqInitializeLinkedBlockingQueue(&packetHolderFreeList, MAX_QUEUED_INPUT_PACKETS);
|
||||
PltCreateMutex(&batchedInputMutex);
|
||||
initialized = true;
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
// A deliberately stalled sender must preserve each click's coordinates.
|
||||
assert(LiSendMousePositionEvent(10, 10, 2560, 1440) == 0);
|
||||
assert(LiSendMousePositionEvent(20, 20, 2560, 1440) == 0);
|
||||
assert(LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT) == 0);
|
||||
assert(LiSendMousePositionEvent(30, 30, 2560, 1440) == 0);
|
||||
assert(LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT) == 0);
|
||||
assert(LiSendMousePositionEvent(40, 40, 2560, 1440) == 0);
|
||||
expectPosition(20);
|
||||
PPACKET_HOLDER press = pop();
|
||||
assert(press->packet.header.magic == LE32(BUTTON_ACTION_PRESS + 1));
|
||||
freePacketHolder(press);
|
||||
expectPosition(30);
|
||||
PPACKET_HOLDER release = pop();
|
||||
assert(release->packet.header.magic == LE32(BUTTON_ACTION_RELEASE + 1));
|
||||
freePacketHolder(release);
|
||||
// Latching an older packet above must not prevent the latest batch
|
||||
// from still absorbing newer positions.
|
||||
assert(LiSendMousePositionEvent(50, 50, 2560, 1440) == 0);
|
||||
expectPosition(50);
|
||||
PPACKET_HOLDER empty;
|
||||
assert(LbqPollQueueElement(&packetQueue, (void**)&empty) == LBQ_NO_ELEMENT);
|
||||
}
|
||||
initialized = false;
|
||||
PLINKED_BLOCKING_QUEUE_ENTRY entry = LbqDestroyLinkedBlockingQueue(&packetQueue);
|
||||
assert(entry == NULL);
|
||||
entry = LbqDestroyLinkedBlockingQueue(&packetHolderFreeList);
|
||||
while (entry) {
|
||||
PLINKED_BLOCKING_QUEUE_ENTRY next = entry->flink;
|
||||
free(entry->data);
|
||||
entry = next;
|
||||
}
|
||||
PltDeleteMutex(&batchedInputMutex);
|
||||
puts("PASS: 1000 queued move/press/move/release cycles preserve positions");
|
||||
return 0;
|
||||
}
|
||||
86
terminal/moonlight/tests/test_input_priority.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include "vdi_input_priority.h"
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
constexpr Sint32 frameCode = 123;
|
||||
static SDL_Event frame() {
|
||||
SDL_Event e{}; e.type = SDL_USEREVENT; e.user.code = frameCode; return e;
|
||||
}
|
||||
static SDL_Event input(Uint32 type, Uint32 window = 1) {
|
||||
SDL_Event e{}; e.type = type; e.key.windowID = window; return e;
|
||||
}
|
||||
static void push(SDL_Event e) { assert(SDL_PushEvent(&e) == 1); }
|
||||
static SDL_Event pop() {
|
||||
SDL_Event e{};
|
||||
assert(SDL_PeepEvents(&e,1,SDL_GETEVENT,SDL_FIRSTEVENT,SDL_LASTEVENT)==1);
|
||||
return e;
|
||||
}
|
||||
int main() {
|
||||
assert(SDL_Init(SDL_INIT_EVENTS)==0);
|
||||
SDL_Event out{};
|
||||
VdiInputPriority disabled(false, frameCode);
|
||||
push(input(SDL_MOUSEMOTION));
|
||||
assert(!disabled.deferFrame(frame()) && !disabled.takeDeferred(out,1));
|
||||
assert(pop().type == SDL_MOUSEMOTION);
|
||||
|
||||
// Only a contiguous input prefix can pass a frame. No focus/quit/decoder
|
||||
// barrier may be skipped, even if input is waiting further down the queue.
|
||||
for (Uint32 barrier : {Uint32(SDL_WINDOWEVENT),Uint32(SDL_QUIT),
|
||||
Uint32(SDL_USEREVENT),Uint32(SDL_RENDER_DEVICE_RESET),
|
||||
Uint32(SDL_CONTROLLERDEVICEADDED)}) {
|
||||
VdiInputPriority scheduler(true, frameCode);
|
||||
push(input(SDL_MOUSEBUTTONDOWN)); push(input(SDL_MOUSEBUTTONUP));
|
||||
push(input(barrier)); push(input(SDL_KEYDOWN));
|
||||
assert(scheduler.deferFrame(frame()));
|
||||
assert(scheduler.takeDeferred(out,1) && out.type==SDL_MOUSEBUTTONDOWN);
|
||||
assert(scheduler.takeDeferred(out,1) && out.type==SDL_MOUSEBUTTONUP);
|
||||
assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT && out.user.code==frameCode);
|
||||
assert(!scheduler.takeDeferred(out,1));
|
||||
assert(pop().type==barrier && pop().type==SDL_KEYDOWN);
|
||||
assert(scheduler.prioritized()==2);
|
||||
}
|
||||
// Preserve all input order, including keyboard releases and drag edges.
|
||||
{
|
||||
VdiInputPriority scheduler(true,frameCode);
|
||||
for (Uint32 t : {Uint32(SDL_KEYDOWN),Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONDOWN),
|
||||
Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONUP),Uint32(SDL_KEYUP)}) push(input(t));
|
||||
assert(scheduler.deferFrame(frame()));
|
||||
for (Uint32 t : {Uint32(SDL_KEYDOWN),Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONDOWN),
|
||||
Uint32(SDL_MOUSEMOTION),Uint32(SDL_MOUSEBUTTONUP),Uint32(SDL_KEYUP)})
|
||||
assert(scheduler.takeDeferred(out,1) && out.type==t);
|
||||
assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT);
|
||||
}
|
||||
for (bool synthetic : {false,true}) {
|
||||
VdiInputPriority scheduler(true,frameCode);
|
||||
auto e=input(SDL_MOUSEMOTION,synthetic?1:2);
|
||||
if(synthetic) e.motion.which=SDL_TOUCH_MOUSEID;
|
||||
push(e); assert(scheduler.deferFrame(frame()));
|
||||
assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT);
|
||||
assert(pop().type==SDL_MOUSEMOTION);
|
||||
}
|
||||
// A high-rate input device cannot starve video.
|
||||
{
|
||||
VdiInputPriority scheduler(true,frameCode);
|
||||
for(int i=0;i<1000;++i) push(input(SDL_MOUSEWHEEL));
|
||||
assert(scheduler.deferFrame(frame()));
|
||||
unsigned n=0;
|
||||
while(scheduler.takeDeferred(out,1) && out.type!=SDL_USEREVENT) ++n;
|
||||
assert(n<=32 && n>0 && out.type==SDL_USEREVENT);
|
||||
SDL_FlushEvents(SDL_FIRSTEVENT,SDL_LASTEVENT);
|
||||
}
|
||||
{
|
||||
VdiInputPriority scheduler(true,frameCode);
|
||||
push(input(SDL_MOUSEBUTTONUP));
|
||||
assert(scheduler.deferFrame(frame())); SDL_Delay(4);
|
||||
assert(scheduler.takeDeferred(out,1) && out.type==SDL_USEREVENT);
|
||||
assert(pop().type==SDL_MOUSEBUTTONUP);
|
||||
}
|
||||
// Instrumentation never consumes events or changes cursor visibility.
|
||||
VdiInputTiming timing(true);
|
||||
auto e=input(SDL_MOUSEMOTION); e.common.timestamp=SDL_GetTicks();
|
||||
timing.observe(e,1); auto start=timing.startRender(); timing.endRender(start);
|
||||
timing.report(0);
|
||||
SDL_Quit();
|
||||
std::puts("PASS: input FIFO, focus/quit/reset/window barriers, disabled mode, device/window isolation, count/time bounds");
|
||||
}
|
||||
75
terminal/moonlight/tests/test_latency.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include <SDL.h>
|
||||
#include <cstdio>
|
||||
#include "vdi_mouse_batch.h"
|
||||
#include "vdi_latest_frame.h"
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
|
||||
static SDL_Event motion(int x, Uint32 which = 1)
|
||||
{
|
||||
SDL_Event event{};
|
||||
event.type = SDL_MOUSEMOTION;
|
||||
event.motion.which = which;
|
||||
event.motion.windowID = 1;
|
||||
event.motion.x = x;
|
||||
event.motion.y = 100;
|
||||
event.motion.xrel = 1;
|
||||
return event;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
assert(SDL_Init(SDL_INIT_EVENTS) == 0);
|
||||
for (Uint32 boundary : {Uint32(SDL_MOUSEBUTTONDOWN), Uint32(SDL_MOUSEBUTTONUP),
|
||||
Uint32(SDL_KEYDOWN), Uint32(SDL_USEREVENT)}) {
|
||||
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
||||
SDL_Event first = motion(10), adjacent = motion(20), later = motion(90), barrier{};
|
||||
barrier.type = boundary;
|
||||
assert(SDL_PushEvent(&adjacent) == 1);
|
||||
assert(SDL_PushEvent(&barrier) == 1);
|
||||
assert(SDL_PushEvent(&later) == 1);
|
||||
vdiBatchMouseMotion(first.motion);
|
||||
assert(first.motion.x == 20 && first.motion.xrel == 2);
|
||||
SDL_Event next;
|
||||
assert(SDL_PeepEvents(&next, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) == 1);
|
||||
assert(next.type == boundary);
|
||||
assert(SDL_PeepEvents(&next, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) == 1);
|
||||
assert(next.motion.x == 90);
|
||||
}
|
||||
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
||||
SDL_Event first = motion(0);
|
||||
for (int i = 1; i <= 200; ++i) {
|
||||
SDL_Event next = motion(i);
|
||||
assert(SDL_PushEvent(&next) == 1);
|
||||
}
|
||||
vdiBatchMouseMotion(first.motion);
|
||||
assert(first.motion.x == 64); // Work per dispatch is bounded.
|
||||
assert(SDL_PeepEvents(nullptr, 0, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) == 136);
|
||||
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
||||
first = motion(10);
|
||||
SDL_Event synthetic = motion(99, SDL_TOUCH_MOUSEID);
|
||||
assert(SDL_PushEvent(&synthetic) == 1);
|
||||
vdiBatchMouseMotion(first.motion);
|
||||
assert(first.motion.x == 10);
|
||||
|
||||
AVFrame* presented = av_frame_alloc();
|
||||
assert(presented);
|
||||
presented->buf[0] = av_buffer_alloc(16);
|
||||
assert(presented->buf[0]);
|
||||
QQueue<AVFrame*> queue;
|
||||
assert(vdiDiscardQueuedFrames(queue) == 0);
|
||||
for (int i = 0; i < 200; ++i) {
|
||||
unsigned dropped = vdiDiscardQueuedFrames(queue);
|
||||
assert(dropped == (i == 0 ? 0u : 1u));
|
||||
AVFrame* frame = av_frame_alloc();
|
||||
assert(frame);
|
||||
frame->pts = i;
|
||||
queue.enqueue(frame);
|
||||
assert(queue.size() == 1 && queue.head()->pts == i);
|
||||
assert(av_buffer_get_ref_count(presented->buf[0]) == 1);
|
||||
}
|
||||
assert(vdiDiscardQueuedFrames(queue) == 1);
|
||||
av_frame_free(&presented);
|
||||
SDL_Quit();
|
||||
std::puts("PASS: SDL event boundaries, bounded motion work, latest decoded frame ownership");
|
||||
}
|
||||
74
tools/bench-mouse-stream.sh
Normal file
@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
# Temporary benchmark stream only. Refuses to replace an existing user stream.
|
||||
# Run after launching the scoped Windows input benchmark, with VDD mode matched.
|
||||
set -euo pipefail
|
||||
task_root="${VDI_RKMPP_BUILD_ROOT:-$HOME/vdi-build/rkmpp-experiment}"
|
||||
label="${1:?label required}"
|
||||
fps="${2:?FPS required}"
|
||||
priority="${3:-0}"
|
||||
[[ "$label" =~ ^[a-zA-Z0-9-]+$ ]] || exit 2
|
||||
[[ "$fps" = 30 || "$fps" = 60 ]] || exit 2
|
||||
[[ "$priority" = 0 || "$priority" = 1 ]] || exit 2
|
||||
exec 9>"$task_root/mouse-bench.lock"
|
||||
flock -n 9 || { echo 'Another benchmark is active'; exit 1; }
|
||||
if pgrep -f '^/home/armbian/vdi-build/rkmpp-experiment/build/moonlight/app/moonlight.* stream ' >/dev/null; then
|
||||
echo 'A stream is already active; exit it normally before benchmarking' >&2
|
||||
exit 1
|
||||
fi
|
||||
export DISPLAY=:0 XAUTHORITY="$HOME/.Xauthority"
|
||||
export LD_LIBRARY_PATH="$task_root/runtime/lib:$task_root/deps/usr/lib/aarch64-linux-gnu"
|
||||
export QML2_IMPORT_PATH="$task_root/deps/usr/lib/aarch64-linux-gnu/qt5/qml"
|
||||
export QT_PLUGIN_PATH="$task_root/deps/usr/lib/aarch64-linux-gnu/qt5/plugins"
|
||||
export H264_DECODER_HINT=h264_rkmpp HEVC_DECODER_HINT=hevc_rkmpp
|
||||
export VDI_LATEST_FRAME=1 VDI_INPUT_TIMING=1 VDI_INPUT_PRIORITY="$priority"
|
||||
export GL_IS_SLOW=0 SDL_RENDER_DRIVER=opengles2 SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR=1
|
||||
client="${VDI_RKMPP_CLIENT:-$task_root/build/moonlight/app/moonlight}"
|
||||
mkdir -p "$task_root/mouse-bench"
|
||||
log="$task_root/mouse-bench/$label.log"
|
||||
test ! -e "$log" || { echo 'Label already used; preserve existing evidence'; exit 1; }
|
||||
child=""
|
||||
cleanup() {
|
||||
if [ -n "$child" ] && kill -0 "$child" 2>/dev/null; then
|
||||
kill -TERM "$child" 2>/dev/null || true
|
||||
for ((j=0;j<5;j++)); do
|
||||
kill -0 "$child" 2>/dev/null || break
|
||||
sleep 1
|
||||
done
|
||||
kill -KILL "$child" 2>/dev/null || true
|
||||
wait "$child" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
trap 'exit 130' INT
|
||||
trap 'exit 143' TERM
|
||||
"$client" stream 192.168.1.70 Desktop --resolution 2560x1440 --fps "$fps" \
|
||||
--bitrate 30000 --display-mode fullscreen --video-codec H.264 \
|
||||
--video-decoder hardware --absolute-mouse --keep-awake --no-vsync \
|
||||
--no-frame-pacing --audio-on-host > "$log" 2>&1 &
|
||||
child=$!
|
||||
ready=0
|
||||
for ((i=0;i<35;i++)); do
|
||||
if grep -q 'egl_overlay.frag' "$log"; then ready=1; break; fi
|
||||
kill -0 "$child" || { tail -20 "$log"; exit 1; }
|
||||
sleep 1
|
||||
done
|
||||
test "$ready" = 1 || { echo 'No video readiness'; exit 1; }
|
||||
echo "Ready: $label; injecting motion"
|
||||
python3 "$task_root/mouse-bench/inject-mouse-sweep.py"
|
||||
python3 "$task_root/mouse-bench/inject-input-burst.py"
|
||||
sleep 12
|
||||
# Do not send the exit chord into an unrelated foreground application.
|
||||
focus_pid=$(xdotool getwindowfocus getwindowpid 2>/dev/null || true)
|
||||
if [ "$focus_pid" != "$child" ]; then
|
||||
echo 'Stream lost foreground; terminate only benchmark child' >&2
|
||||
exit 1
|
||||
fi
|
||||
xdotool key ctrl+alt+shift+q
|
||||
for ((i=0;i<15;i++)); do
|
||||
kill -0 "$child" 2>/dev/null || break
|
||||
sleep 1
|
||||
done
|
||||
kill -0 "$child" 2>/dev/null && { echo 'Stream exit timed out'; exit 1; }
|
||||
wait "$child"
|
||||
child=""
|
||||
grep -E 'VDI input|VDI main-thread|frame rate|Host processing|Frames dropped|Average .*time|Average network|queue delay' "$log"
|
||||
166
tools/build-rkmpp-client.sh
Normal file
@ -0,0 +1,166 @@
|
||||
#!/bin/bash
|
||||
# Run on the ARM64 terminal. All sources, libraries and output stay in TASK_ROOT.
|
||||
# No apt install, system library replacement, desktop restart or sudo is needed.
|
||||
set -euo pipefail
|
||||
TASK_ROOT="${VDI_RKMPP_BUILD_ROOT:-$HOME/vdi-build/rkmpp-experiment}"
|
||||
SDK="$TASK_ROOT/deps/usr"
|
||||
PREFIX="$TASK_ROOT/runtime"
|
||||
JOBS="${VDI_BUILD_JOBS:-2}"
|
||||
mkdir -p "$TASK_ROOT"/{src,debs,build} "$PREFIX"
|
||||
|
||||
clone_source() {
|
||||
local name="$1" ref="$2" url="$3"
|
||||
if [ ! -d "$TASK_ROOT/src/$name/.git" ]; then
|
||||
git clone --depth=1 --branch "$ref" "$url" "$TASK_ROOT/src/$name"
|
||||
fi
|
||||
test "$(git -C "$TASK_ROOT/src/$name" rev-parse HEAD)" = "$4" || {
|
||||
echo "Unexpected $name source revision; inspect before building" >&2; exit 1;
|
||||
}
|
||||
}
|
||||
clone_source mpp develop https://github.com/rockchip-linux/mpp.git 7916c3cc000fefc0bdf96636b7d54fe174724f44
|
||||
clone_source ffmpeg 6.1 https://github.com/nyanmisaka/ffmpeg-rockchip.git 797387de1c9caa9170100d7217ee093d1897f750
|
||||
clone_source moonlight v6.2.0 https://github.com/moonlight-stream/moonlight-qt.git de2467e433821664cdd2224aad8c89a625be1ad9
|
||||
git -C "$TASK_ROOT/src/moonlight" submodule update --init --recursive --depth=1
|
||||
|
||||
# Versioned VDI interaction patches. Explicit directory supports copying this
|
||||
# builder to the box without the rest of the repository. Refuse unknown drift.
|
||||
PATCH_DIR="${VDI_MOONLIGHT_PATCH_DIR:-$(cd "$(dirname "$0")/../terminal/moonlight/patches" && pwd)}"
|
||||
apply_vdi_patch() {
|
||||
local source="$1" patch="$2"
|
||||
test -r "$patch" || { echo "Missing VDI patch: $patch" >&2; exit 1; }
|
||||
if git -C "$source" apply --reverse --check "$patch" 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
git -C "$source" apply --check "$patch"
|
||||
git -C "$source" apply "$patch"
|
||||
}
|
||||
apply_vdi_patch "$TASK_ROOT/src/moonlight" "$PATCH_DIR/0001-vdi-input-and-latest-frame.patch"
|
||||
apply_vdi_patch "$TASK_ROOT/src/moonlight/moonlight-common-c/moonlight-common-c" \
|
||||
"$PATCH_DIR/0002-vdi-absolute-click-barrier.patch"
|
||||
apply_vdi_patch "$TASK_ROOT/src/moonlight" "$PATCH_DIR/0003-vdi-input-priority.patch"
|
||||
|
||||
# Moonlight 6.2.0 uses std::optional in drm.h but relies on a transitive
|
||||
# include from Qt 6. Our Qt 5 build needs the standard header explicitly.
|
||||
export VDI_MOONLIGHT_SOURCE="$TASK_ROOT/src/moonlight"
|
||||
python3 - <<'PY'
|
||||
import os
|
||||
from pathlib import Path
|
||||
header = Path(os.environ['VDI_MOONLIGHT_SOURCE']) / 'app/streaming/video/ffmpeg-renderers/drm.h'
|
||||
text = header.read_text()
|
||||
if '#include <optional>' not in text:
|
||||
assert '#include <set>' in text
|
||||
header.write_text(text.replace('#include <set>', '#include <optional>\n#include <set>', 1))
|
||||
PY
|
||||
|
||||
# Download only the required headers and private runtime libraries from the
|
||||
# configured distribution repository. apt does not install or upgrade anything.
|
||||
cd "$TASK_ROOT/debs"
|
||||
apt-get download libdrm-dev libopus-dev libsdl2-dev libsdl2-2.0-0 \
|
||||
libsdl2-ttf-dev libsdl2-ttf-2.0-0 libudev-dev libxkbcommon-dev \
|
||||
libegl-dev libgles-dev libgles1 libgbm-dev libwayland-dev libwayland-bin wayland-protocols \
|
||||
qtdeclarative5-dev qtdeclarative5-dev-tools qt5-qmltooling-plugins \
|
||||
qtquickcontrols2-5-dev libqt5quickcontrols2-5 libqt5quicktemplates2-5 \
|
||||
libqt5svg5-dev libqt5svg5 libqt5qmlworkerscript5 libqt5quickparticles5 \
|
||||
libqt5quickshapes5 libqt5quicktest5 libx264-dev \
|
||||
qml-module-qtquick2 qml-module-qtquick-window2 qml-module-qtquick-layouts \
|
||||
qml-module-qtqml-models2 qml-module-qtquick-controls2 qml-module-qtquick-templates2 \
|
||||
libharfbuzz-dev libfreetype-dev libpng-dev zlib1g-dev libbrotli-dev \
|
||||
libglib2.0-dev libgraphite2-dev libffi-dev
|
||||
for package in ./*.deb; do dpkg-deb -x "$package" "$TASK_ROOT/deps"; done
|
||||
|
||||
# Relocate pkg-config prefixes, preserving the system /usr and its libraries.
|
||||
export VDI_PRIVATE_SDK="$SDK"
|
||||
python3 - <<'PY'
|
||||
import os
|
||||
from pathlib import Path
|
||||
sdk = Path(os.environ['VDI_PRIVATE_SDK'])
|
||||
for pc in sdk.rglob('*.pc'):
|
||||
text = pc.read_text()
|
||||
if str(sdk) not in text:
|
||||
pc.write_text(text.replace('/usr', str(sdk)))
|
||||
for pri in sdk.rglob('qt_lib_*.pri'):
|
||||
pri.write_text(pri.read_text().replace('$$QT_MODULE_LIB_BASE', str(sdk / 'lib/aarch64-linux-gnu'))
|
||||
.replace('$$QT_MODULE_INCLUDE_BASE', str(sdk / 'include/aarch64-linux-gnu/qt5'))
|
||||
.replace('$$QT_MODULE_BIN_BASE', str(sdk / 'lib/qt5/bin')))
|
||||
# A -dev symlink can target a different distro patch version than is installed.
|
||||
# Link to the existing matching SONAME; never replace the system runtime.
|
||||
for link in (sdk / 'lib/aarch64-linux-gnu').glob('*.so'):
|
||||
if link.is_symlink() and not link.exists():
|
||||
target = Path(os.readlink(link)).name
|
||||
if '.so.' not in target:
|
||||
continue
|
||||
soname = target.split('.so.')[0] + '.so.' + target.split('.so.')[1].split('.')[0]
|
||||
system_lib = Path('/lib/aarch64-linux-gnu') / soname
|
||||
if system_lib.exists():
|
||||
link.unlink()
|
||||
link.symlink_to(system_lib)
|
||||
PY
|
||||
export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$SDK/lib/aarch64-linux-gnu/pkgconfig:$SDK/share/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
|
||||
export LD_LIBRARY_PATH="$PREFIX/lib:$SDK/lib/aarch64-linux-gnu${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
export QMAKEPATH="$SDK/lib/aarch64-linux-gnu/qt5"
|
||||
export QML2_IMPORT_PATH="$SDK/lib/aarch64-linux-gnu/qt5/qml"
|
||||
export CPLUS_INCLUDE_PATH="$SDK/include/aarch64-linux-gnu:$SDK/include${CPLUS_INCLUDE_PATH:+:$CPLUS_INCLUDE_PATH}"
|
||||
export C_INCLUDE_PATH="$SDK/include/aarch64-linux-gnu:$SDK/include${C_INCLUDE_PATH:+:$C_INCLUDE_PATH}"
|
||||
|
||||
if [ "${VDI_BUILD_STAGE:-all}" != moonlight ]; then
|
||||
echo '=== build MPP ==='
|
||||
cmake -S "$TASK_ROOT/src/mpp" -B "$TASK_ROOT/build/mpp" \
|
||||
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$PREFIX" \
|
||||
-DRKPLATFORM=ON -DHAVE_DRM=ON -DBUILD_SHARED_LIBS=ON -DBUILD_TEST=OFF
|
||||
cmake --build "$TASK_ROOT/build/mpp" -j "$JOBS"
|
||||
cmake --install "$TASK_ROOT/build/mpp"
|
||||
|
||||
echo '=== build FFmpeg with RKMPP ==='
|
||||
mkdir -p "$TASK_ROOT/build/ffmpeg"
|
||||
cd "$TASK_ROOT/build/ffmpeg"
|
||||
"$TASK_ROOT/src/ffmpeg/configure" --prefix="$PREFIX" \
|
||||
--enable-gpl --enable-version3 --enable-shared --disable-static \
|
||||
--enable-libdrm --enable-rkmpp --disable-rkrga --enable-libx264 \
|
||||
--disable-doc --disable-debug --disable-autodetect --disable-network \
|
||||
--disable-everything --enable-avcodec --enable-avformat --enable-avfilter \
|
||||
--enable-swscale --enable-swresample --enable-ffmpeg --enable-ffprobe \
|
||||
--enable-decoder=h264,hevc,h264_rkmpp,hevc_rkmpp,rawvideo,wrapped_avframe \
|
||||
--enable-parser=h264,hevc --enable-demuxer=h264,hevc \
|
||||
--enable-muxer=h264,null,rawvideo --enable-protocol=file \
|
||||
--enable-encoder=libx264,wrapped_avframe,rawvideo --enable-indev=lavfi \
|
||||
--enable-filter=testsrc2,null,format,hwdownload,scale \
|
||||
--extra-cflags="-I$PREFIX/include -I$SDK/include" \
|
||||
--extra-ldflags="-L$PREFIX/lib -L$SDK/lib/aarch64-linux-gnu -Wl,-rpath,$PREFIX/lib -Wl,-rpath,$SDK/lib/aarch64-linux-gnu"
|
||||
make -j "$JOBS"
|
||||
make install
|
||||
"$PREFIX/bin/ffmpeg" -hide_banner -decoders | grep rkmpp
|
||||
fi
|
||||
|
||||
echo '=== build Moonlight ==='
|
||||
mkdir -p "$TASK_ROOT/build/moonlight"
|
||||
cd "$TASK_ROOT/build/moonlight"
|
||||
qmake "$TASK_ROOT/src/moonlight/moonlight-qt.pro" \
|
||||
CONFIG+=release CONFIG+=recheck CONFIG+=disable-libva CONFIG+=disable-libvdpau \
|
||||
CONFIG+=disable-libplacebo CONFIG+=disable-discord \
|
||||
"QMAKE_LIBDIR+=$SDK/lib/aarch64-linux-gnu" \
|
||||
"QMAKE_LIBDIR+=$PREFIX/lib" \
|
||||
"QMAKE_RPATHDIR+=$SDK/lib/aarch64-linux-gnu" \
|
||||
"QMAKE_RPATHDIR+=$PREFIX/lib" \
|
||||
"QMAKE_INCDIR+=$SDK/include/aarch64-linux-gnu/qt5" \
|
||||
"QMAKE_INCDIR+=$SDK/include/aarch64-linux-gnu" \
|
||||
"QMAKE_INCDIR+=$SDK/include"
|
||||
make qmake_all
|
||||
if ! grep -q -- '-DHAVE_EGL' app/Makefile.Release; then
|
||||
echo 'EGL renderer missing; refusing to build a client without the DRM PRIME display path' >&2
|
||||
exit 1
|
||||
fi
|
||||
# qmake/make does not invalidate old objects when feature defines change.
|
||||
# In particular a stale ffmpeg.o can silently omit EGL despite a successful
|
||||
# configure check. Clean the app whenever its compiler/link flags change.
|
||||
flags_hash="$(grep -E '^(DEFINES|INCPATH|LIBS|CXXFLAGS)[[:space:]]*=' app/Makefile.Release | sha256sum | cut -d ' ' -f 1)"
|
||||
if [ "$(cat .vdi-build-flags.sha256 2>/dev/null || true)" != "$flags_hash" ]; then
|
||||
make -C app -f Makefile.Release clean
|
||||
printf '%s\n' "$flags_hash" > .vdi-build-flags.sha256
|
||||
fi
|
||||
make -j "$JOBS"
|
||||
echo '=== complete; experimental binary only, production unchanged ==='
|
||||
echo "$TASK_ROOT/build/moonlight/app/moonlight"
|
||||
git -C "$TASK_ROOT/src/mpp" rev-parse HEAD
|
||||
git -C "$TASK_ROOT/src/ffmpeg" rev-parse HEAD
|
||||
git -C "$TASK_ROOT/src/moonlight" rev-parse HEAD
|
||||
sha256sum "$TASK_ROOT"/debs/*.deb > "$TASK_ROOT/dependency-sha256.txt"
|
||||
62
tools/deploy_display_guard.sh
Normal file
@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
# Install only X11 display recovery; keep the kiosk/Moonlight session running.
|
||||
set -euo pipefail
|
||||
|
||||
BOX="${VDI_BOX:-armbian@192.168.1.188}"
|
||||
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
SRC="$REPO/terminal/kiosk-shell"
|
||||
STAGE=$(ssh -o BatchMode=yes -o ConnectTimeout=8 "$BOX" 'mktemp -d /tmp/vdi-display-deploy.XXXXXX')
|
||||
scp -q "$SRC/scripts/vdi-display-guard" "$SRC/scripts/vdi-kiosk-start" \
|
||||
"$SRC/etc/vdi-display-guard.service" "$BOX:$STAGE/"
|
||||
ssh "$BOX" bash -s -- "$STAGE" <<'REMOTE'
|
||||
set -euo pipefail
|
||||
stage=$1
|
||||
backup="$HOME/vdi-terminal/backups/display-guard-$(date +%Y%m%d-%H%M%S)"
|
||||
mkdir -p "$backup" "$HOME/vdi-terminal/bin" "$HOME/.config/systemd/user"
|
||||
for file in "$HOME/vdi-terminal/bin/vdi-kiosk-start" \
|
||||
"$HOME/vdi-terminal/bin/vdi-display-guard" \
|
||||
"$HOME/.config/systemd/user/vdi-display-guard.service"; do
|
||||
test ! -f "$file" || cp -p "$file" "$backup/"
|
||||
done
|
||||
sed -i 's/\r$//' "$stage/"*
|
||||
python3 -c 'import ast, sys; ast.parse(open(sys.argv[1]).read())' "$stage/vdi-display-guard"
|
||||
sh -n "$stage/vdi-kiosk-start"
|
||||
install -m 0755 "$stage/vdi-display-guard" "$stage/vdi-kiosk-start" "$HOME/vdi-terminal/bin/"
|
||||
install -m 0644 "$stage/vdi-display-guard.service" "$HOME/.config/systemd/user/"
|
||||
|
||||
# Correct only this monitor's known stale layout; preserve all other layouts.
|
||||
python3 - "$backup" <<'PY'
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
path = Path.home() / '.config/monitors.xml'
|
||||
if path.exists():
|
||||
tree = ET.parse(path)
|
||||
changed = False
|
||||
for output in tree.findall('.//output'):
|
||||
if (output.get('name') == 'HDMI-1'
|
||||
and output.findtext('vendor') == 'GWR'
|
||||
and output.findtext('product') == '0x2708'
|
||||
and output.findtext('width') == '1920'
|
||||
and output.findtext('height') == '1440'
|
||||
and output.findtext('rate') == '75'):
|
||||
for name, value in [('width', '2560'), ('height', '1440'), ('rate', '60')]:
|
||||
output.find(name).text = value
|
||||
changed = True
|
||||
if changed:
|
||||
shutil.copy2(path, Path(sys.argv[1]) / 'monitors.xml')
|
||||
temp = path.with_name('monitors.xml.vdi-new')
|
||||
tree.write(temp, encoding='utf-8', xml_declaration=True)
|
||||
temp.replace(path)
|
||||
print('Updated known stale MATE layout to 2560x1440@60')
|
||||
PY
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable vdi-display-guard.service
|
||||
systemctl --user restart vdi-display-guard.service
|
||||
systemctl --user is-active vdi-display-guard.service
|
||||
echo "Backup: $backup"
|
||||
# Only remove the three files uploaded by this deployment.
|
||||
rm -- "$stage/vdi-display-guard" "$stage/vdi-kiosk-start" "$stage/vdi-display-guard.service"
|
||||
rmdir -- "$stage"
|
||||
REMOTE
|
||||
@ -15,21 +15,30 @@ echo "==> 检查盒子连通性"
|
||||
ssh -o ConnectTimeout=8 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'echo "box ok: $(hostname)"'
|
||||
|
||||
echo "==> 同步源码到盒子"
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'rm -rf ~/vdi-build/repo/kiosk-shell/src ~/vdi-build/repo/kiosk-shell/tests && mkdir -p ~/vdi-build/repo/kiosk-shell/src ~/vdi-build/repo/kiosk-shell/tests'
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'rm -rf ~/vdi-build/repo/kiosk-shell/src ~/vdi-build/repo/kiosk-shell/tests && mkdir -p ~/vdi-build/repo/kiosk-shell/src ~/vdi-build/repo/kiosk-shell/tests ~/vdi-build/repo/kiosk-shell/scripts'
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC/CMakeLists.txt" "$BOX":~/vdi-build/repo/kiosk-shell/
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC"/src/*.cpp "$SRC"/src/*.h "$BOX":~/vdi-build/repo/kiosk-shell/src/
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC"/tests/*.cpp "$BOX":~/vdi-build/repo/kiosk-shell/tests/
|
||||
scp -q "$SRC/tests/test_display_guard.py" "$BOX":~/vdi-build/repo/kiosk-shell/tests/
|
||||
scp -q "$SRC/scripts/vdi-display-guard" "$BOX":~/vdi-build/repo/kiosk-shell/scripts/
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC/scripts/vdi-moonlight" "$SRC/scripts/vdi-kiosk-start" "$BOX":~/vdi-terminal/bin/
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC/scripts/vdi-moonlight-rkmpp" "$BOX":~/vdi-terminal/bin/
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'sed -i "s/\r$//" ~/vdi-terminal/bin/vdi-moonlight-rkmpp; chmod +x ~/vdi-terminal/bin/vdi-moonlight-rkmpp'
|
||||
scp -q "$SRC/etc/70-vdi-rockchip-video.rules" "$BOX":/tmp/70-vdi-rockchip-video.rules
|
||||
ssh "$BOX" 'sed -i "s/\r$//" /tmp/70-vdi-rockchip-video.rules; sudo -n install -m 0644 /tmp/70-vdi-rockchip-video.rules /etc/udev/rules.d/70-vdi-rockchip-video.rules && sudo -n udevadm control --reload-rules && for device in /dev/mpp_service /dev/rga /dev/dma_heap/*; do test ! -e "$device" || { sudo -n chgrp video "$device" && sudo -n chmod 0660 "$device"; } || exit 1; done'
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC/etc/moonlight.conf" "$BOX":/tmp/vdi-moonlight.conf
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'mkdir -p ~/.config/vdi-terminal; test -f ~/.config/vdi-terminal/moonlight.conf || cp /tmp/vdi-moonlight.conf ~/.config/vdi-terminal/moonlight.conf; rm -f /tmp/vdi-moonlight.conf'
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC/vdi-kiosk.desktop" "$BOX":~/.config/autostart/vdi-kiosk.desktop
|
||||
scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$SRC/vdi-moonlight.desktop" "$BOX":~/.config/autostart/vdi-moonlight.desktop
|
||||
|
||||
echo "==> 安装 HDMI 热插拔恢复服务"
|
||||
bash "$REPO/tools/deploy_display_guard.sh"
|
||||
|
||||
echo "==> 在盒子上编译"
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'sed -i "s/\r$//" ~/vdi-build/repo/kiosk-shell/src/*.cpp ~/vdi-build/repo/kiosk-shell/src/*.h ~/vdi-build/repo/kiosk-shell/tests/*.cpp ~/vdi-terminal/bin/vdi-moonlight ~/vdi-terminal/bin/vdi-kiosk-start; chmod +x ~/vdi-terminal/bin/vdi-moonlight ~/vdi-terminal/bin/vdi-kiosk-start; cd ~/vdi-build/repo/kiosk-shell && (cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON > /tmp/cmake.log 2>&1 || (tail -30 /tmp/cmake.log; exit 1)) && cmake --build build && QT_QPA_PLATFORM=offscreen ctest --test-dir build --output-on-failure'
|
||||
|
||||
echo "==> 安装二进制"
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'monitor_pids=$(pgrep -f "^/home/armbian/vdi-terminal/bin/vdi-kiosk-monitor -- " 2>/dev/null || true); test -z "$monitor_pids" || kill $monitor_pids 2>/dev/null || true; pair_pids=$(pgrep -f "^bash -c tail -f .*(pin|pair)_fifo" 2>/dev/null || true); test -z "$pair_pids" || kill $pair_pids 2>/dev/null || true; tail_pids=$(pgrep -f "^tail -f .*(pin|pair)_fifo" 2>/dev/null || true); test -z "$tail_pids" || kill $tail_pids 2>/dev/null || true; rm -f ~/pair_fifo /tmp/pin_fifo; for name in vdi-moonlight moonlight-qt kiosk-shell; do pids=$(pidof "$name" 2>/dev/null || true); test -z "$pids" || kill $pids 2>/dev/null || true; done; for i in $(seq 1 40); do pgrep -f "^/home/armbian/vdi-terminal/bin/vdi-kiosk-monitor -- " >/dev/null 2>&1 || break; sleep 0.2; done; monitor_pids=$(pgrep -f "^/home/armbian/vdi-terminal/bin/vdi-kiosk-monitor -- " 2>/dev/null || true); test -z "$monitor_pids" || kill -9 $monitor_pids 2>/dev/null || true; cp ~/vdi-build/repo/kiosk-shell/build/kiosk-shell ~/vdi-terminal/bin/kiosk-shell && cp ~/vdi-build/repo/kiosk-shell/build/vdi-kiosk-monitor ~/vdi-terminal/bin/vdi-kiosk-monitor && chmod +x ~/vdi-terminal/bin/kiosk-shell ~/vdi-terminal/bin/vdi-kiosk-monitor && ls -la ~/vdi-terminal/bin/'
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'monitor_pids=$(pgrep -f "^/home/armbian/vdi-terminal/bin/vdi-kiosk-monitor -- " 2>/dev/null || true); test -z "$monitor_pids" || kill $monitor_pids 2>/dev/null || true; pair_pids=$(pgrep -f "^bash -c tail -f .*(pin|pair)_fifo" 2>/dev/null || true); test -z "$pair_pids" || kill $pair_pids 2>/dev/null || true; tail_pids=$(pgrep -f "^tail -f .*(pin|pair)_fifo" 2>/dev/null || true); test -z "$tail_pids" || kill $tail_pids 2>/dev/null || true; rm -f ~/pair_fifo /tmp/pin_fifo; for name in vdi-moonlight moonlight-qt moonlight kiosk-shell; do pids=$(pidof "$name" 2>/dev/null || true); test -z "$pids" || kill $pids 2>/dev/null || true; done; for i in $(seq 1 40); do pgrep -f "^/home/armbian/vdi-terminal/bin/vdi-kiosk-monitor -- " >/dev/null 2>&1 || break; sleep 0.2; done; monitor_pids=$(pgrep -f "^/home/armbian/vdi-terminal/bin/vdi-kiosk-monitor -- " 2>/dev/null || true); test -z "$monitor_pids" || kill -9 $monitor_pids 2>/dev/null || true; cp ~/vdi-build/repo/kiosk-shell/build/kiosk-shell ~/vdi-terminal/bin/kiosk-shell && cp ~/vdi-build/repo/kiosk-shell/build/vdi-kiosk-monitor ~/vdi-terminal/bin/vdi-kiosk-monitor && chmod +x ~/vdi-terminal/bin/kiosk-shell ~/vdi-terminal/bin/vdi-kiosk-monitor && ls -la ~/vdi-terminal/bin/'
|
||||
|
||||
echo "==> 收敛自启项(只保留 kiosk-shell 一条链)"
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BOX" 'mkdir -p ~/.config/autostart; rm -f ~/.config/autostart/vdi-kiosk.desktop.bak; sed -i "s/^Hidden=.*/Hidden=true/;s/^X-GNOME-Autostart-enabled=.*/X-GNOME-Autostart-enabled=false/" ~/.config/autostart/vdi-moonlight.desktop 2>/dev/null || true; grep -H . ~/.config/autostart/*.desktop'
|
||||
|
||||
54
tools/generate-h264-sample.c
Normal file
@ -0,0 +1,54 @@
|
||||
// Generate a deterministic 1440p H.264 clip without any display/capture dependency.
|
||||
// Link against the isolated FFmpeg libavcodec/libavutil built for the terminal.
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/opt.h>
|
||||
|
||||
static int write_packets(AVCodecContext *encoder, AVPacket *packet, FILE *output) {
|
||||
int result;
|
||||
while ((result = avcodec_receive_packet(encoder, packet)) == 0) {
|
||||
if (fwrite(packet->data, 1, packet->size, output) != (size_t)packet->size) return -1;
|
||||
av_packet_unref(packet);
|
||||
}
|
||||
return result == AVERROR(EAGAIN) || result == AVERROR_EOF ? 0 : result;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2) return 2;
|
||||
const AVCodec *codec = avcodec_find_encoder_by_name("libx264");
|
||||
AVCodecContext *encoder = avcodec_alloc_context3(codec);
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
AVPacket *packet = av_packet_alloc();
|
||||
FILE *output = fopen(argv[1], "wb");
|
||||
if (!codec || !encoder || !frame || !packet || !output) return 1;
|
||||
encoder->width = frame->width = 2560;
|
||||
encoder->height = frame->height = 1440;
|
||||
encoder->pix_fmt = frame->format = AV_PIX_FMT_YUV420P;
|
||||
encoder->time_base = (AVRational){1, 30};
|
||||
encoder->framerate = (AVRational){30, 1};
|
||||
encoder->max_b_frames = 0;
|
||||
encoder->thread_count = 2;
|
||||
av_opt_set(encoder->priv_data, "preset", "ultrafast", 0);
|
||||
av_opt_set(encoder->priv_data, "tune", "zerolatency", 0);
|
||||
if (avcodec_open2(encoder, codec, NULL) < 0 || av_frame_get_buffer(frame, 32) < 0) return 1;
|
||||
for (int i = 0; i < 60; i++) {
|
||||
if (av_frame_make_writable(frame) < 0) return 1;
|
||||
for (int y = 0; y < frame->height; y++) {
|
||||
memset(frame->data[0] + y * frame->linesize[0], 32 + (y + i * 4) % 190, frame->width);
|
||||
}
|
||||
for (int plane = 1; plane < 3; plane++) {
|
||||
for (int y = 0; y < frame->height / 2; y++) {
|
||||
memset(frame->data[plane] + y * frame->linesize[plane], 128, frame->width / 2);
|
||||
}
|
||||
}
|
||||
frame->pts = i;
|
||||
if (avcodec_send_frame(encoder, frame) < 0 || write_packets(encoder, packet, output) < 0) return 1;
|
||||
}
|
||||
if (avcodec_send_frame(encoder, NULL) < 0 || write_packets(encoder, packet, output) < 0) return 1;
|
||||
if (fclose(output) != 0) return 1;
|
||||
av_packet_free(&packet);
|
||||
av_frame_free(&frame);
|
||||
avcodec_free_context(&encoder);
|
||||
return 0;
|
||||
}
|
||||
26
tools/inject-input-burst.py
Normal file
@ -0,0 +1,26 @@
|
||||
"""X11 test only: inject 32 alternating left/right clicks into the bench window."""
|
||||
import ctypes
|
||||
|
||||
x11 = ctypes.CDLL("libX11.so.6")
|
||||
xtest = ctypes.CDLL("libXtst.so.6")
|
||||
x11.XOpenDisplay.argtypes = [ctypes.c_char_p]
|
||||
x11.XOpenDisplay.restype = ctypes.c_void_p
|
||||
x11.XFlush.argtypes = [ctypes.c_void_p]
|
||||
x11.XCloseDisplay.argtypes = [ctypes.c_void_p]
|
||||
xtest.XTestFakeMotionEvent.argtypes = [ctypes.c_void_p, ctypes.c_int,
|
||||
ctypes.c_int, ctypes.c_int, ctypes.c_ulong]
|
||||
xtest.XTestFakeButtonEvent.argtypes = [ctypes.c_void_p, ctypes.c_uint,
|
||||
ctypes.c_int, ctypes.c_ulong]
|
||||
display = x11.XOpenDisplay(None)
|
||||
if not display:
|
||||
raise RuntimeError("X11 unavailable")
|
||||
try:
|
||||
for index in range(32):
|
||||
x = 640 if index % 2 == 0 else 1920
|
||||
assert xtest.XTestFakeMotionEvent(display, -1, x, 600, 0)
|
||||
assert xtest.XTestFakeButtonEvent(display, 1, 1, 0)
|
||||
assert xtest.XTestFakeButtonEvent(display, 1, 0, 0)
|
||||
x11.XFlush(display)
|
||||
finally:
|
||||
x11.XCloseDisplay(display)
|
||||
print("Injected 32 clicks, expected L,R alternating; final pointer on R")
|
||||
31
tools/inject-mouse-sweep.py
Normal file
@ -0,0 +1,31 @@
|
||||
"""X11 benchmark only: 20 seconds of 125 Hz motion, no buttons or keys."""
|
||||
import ctypes
|
||||
import math
|
||||
import time
|
||||
|
||||
x11 = ctypes.CDLL("libX11.so.6")
|
||||
xtest = ctypes.CDLL("libXtst.so.6")
|
||||
x11.XOpenDisplay.argtypes = [ctypes.c_char_p]
|
||||
x11.XOpenDisplay.restype = ctypes.c_void_p
|
||||
x11.XFlush.argtypes = [ctypes.c_void_p]
|
||||
x11.XCloseDisplay.argtypes = [ctypes.c_void_p]
|
||||
xtest.XTestFakeMotionEvent.argtypes = [ctypes.c_void_p, ctypes.c_int,
|
||||
ctypes.c_int, ctypes.c_int, ctypes.c_ulong]
|
||||
display = x11.XOpenDisplay(None)
|
||||
if not display:
|
||||
raise RuntimeError("X11 unavailable")
|
||||
start = time.monotonic()
|
||||
count = 0
|
||||
try:
|
||||
while time.monotonic() - start < 20:
|
||||
elapsed = time.monotonic() - start
|
||||
x = round(1280 + 1000 * math.sin(elapsed * 4))
|
||||
y = round(720 + 450 * math.cos(elapsed * 3))
|
||||
if not xtest.XTestFakeMotionEvent(display, -1, x, y, 0):
|
||||
raise RuntimeError("Motion injection failed")
|
||||
x11.XFlush(display)
|
||||
count += 1
|
||||
time.sleep(max(0, start + count / 125 - time.monotonic()))
|
||||
finally:
|
||||
x11.XCloseDisplay(display)
|
||||
print(f"Injected {count} motion events in {time.monotonic()-start:.2f}s")
|
||||
85
tools/input-latency-bench.ps1
Normal file
@ -0,0 +1,85 @@
|
||||
# Temporary interactive test window; exits after ten minutes. No system settings.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$benchDir = 'C:\ProgramData\VDI\input-bench-20261103'
|
||||
New-Item -ItemType Directory -Force $benchDir | Out-Null
|
||||
Set-Content -LiteralPath "$benchDir\pid.txt" -Value $PID
|
||||
Add-Type -ReferencedAssemblies System.Windows.Forms,System.Drawing -TypeDefinition @'
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
public class VDIInputBenchForm : Form {
|
||||
[DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
|
||||
[DllImport("winmm.dll")] public static extern uint timeBeginPeriod(uint period);
|
||||
[DllImport("winmm.dll")] public static extern uint timeEndPeriod(uint period);
|
||||
readonly Stopwatch watch = Stopwatch.StartNew();
|
||||
readonly Timer timer = new Timer();
|
||||
readonly string folder;
|
||||
int paints, clicks;
|
||||
long lastReport;
|
||||
long lastFrameIndex = -1;
|
||||
public VDIInputBenchForm(string path) {
|
||||
folder = path;
|
||||
Text = "VDI Input Latency Bench";
|
||||
FormBorderStyle = FormBorderStyle.None;
|
||||
Bounds = Screen.PrimaryScreen.Bounds;
|
||||
TopMost = true;
|
||||
DoubleBuffered = true;
|
||||
File.WriteAllText(Path.Combine(folder,"clicks.csv"), "ms,x,y,target\n");
|
||||
// A WinForms 16ms timer can quantize to ~31ms at the default timer
|
||||
// resolution and accidentally cap the *source* at 32FPS. Pace by an
|
||||
// absolute monotonic frame index, not accumulated timer ticks.
|
||||
timer.Interval = 1;
|
||||
timer.Tick += delegate {
|
||||
if(watch.Elapsed.TotalMinutes >= 10) { Close(); return; }
|
||||
long frameIndex = watch.ElapsedTicks * 60 / Stopwatch.Frequency;
|
||||
if(frameIndex != lastFrameIndex) { lastFrameIndex = frameIndex; Invalidate(); }
|
||||
};
|
||||
timer.Start();
|
||||
}
|
||||
protected override void OnMouseDown(MouseEventArgs e) {
|
||||
base.OnMouseDown(e);
|
||||
string target = e.X < Width/2 ? "L" : "R";
|
||||
File.AppendAllText(Path.Combine(folder,"clicks.csv"),
|
||||
watch.ElapsedMilliseconds+","+e.X+","+e.Y+","+target+"\n");
|
||||
++clicks;
|
||||
Invalidate();
|
||||
}
|
||||
protected override void OnPaint(PaintEventArgs e) {
|
||||
base.OnPaint(e);
|
||||
long ms = watch.ElapsedMilliseconds;
|
||||
e.Graphics.Clear(Color.FromArgb(16,24,39));
|
||||
using(Brush left = new SolidBrush(Color.FromArgb(35,85,130)))
|
||||
using(Brush right = new SolidBrush(Color.FromArgb(50,115,90))) {
|
||||
e.Graphics.FillRectangle(left,50,180,Width/2-100,Height-260);
|
||||
e.Graphics.FillRectangle(right,Width/2+50,180,Width/2-100,Height-260);
|
||||
}
|
||||
int x = (int)((ms*0.6)%(Width+100))-100;
|
||||
e.Graphics.FillRectangle(Brushes.Gold,x,0,60,Height);
|
||||
using(Font font = new Font("Consolas",24)) {
|
||||
e.Graphics.DrawString("VDI test: moving bars + ordered clicks | "+clicks+" clicks | "+ms+" ms",
|
||||
font,Brushes.White,70,40);
|
||||
e.Graphics.DrawString("LEFT",font,Brushes.White,Width/4-50,Height/2);
|
||||
e.Graphics.DrawString("RIGHT",font,Brushes.White,Width*3/4-50,Height/2);
|
||||
}
|
||||
++paints;
|
||||
if(ms-lastReport>=1000) {
|
||||
File.WriteAllText(Path.Combine(folder,"status.txt"),
|
||||
"width="+Width+" height="+Height+" paints="+paints+" elapsed_ms="+ms+" clicks="+clicks);
|
||||
lastReport=ms;
|
||||
}
|
||||
}
|
||||
protected override void OnFormClosed(FormClosedEventArgs e) {
|
||||
timer.Stop(); timer.Dispose(); base.OnFormClosed(e);
|
||||
}
|
||||
}
|
||||
'@
|
||||
[VDIInputBenchForm]::SetProcessDPIAware() | Out-Null
|
||||
$timerResult=[VDIInputBenchForm]::timeBeginPeriod(1)
|
||||
try {
|
||||
[System.Windows.Forms.Application]::Run((New-Object VDIInputBenchForm($benchDir)))
|
||||
} finally {
|
||||
if($timerResult -eq 0) { [VDIInputBenchForm]::timeEndPeriod(1) | Out-Null }
|
||||
}
|
||||
67
tools/probe-nvidia-d3d.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace VdiDiagnostics {
|
||||
public class AdapterResult {
|
||||
public string Name;
|
||||
public uint VendorId;
|
||||
public int DeviceResult;
|
||||
}
|
||||
|
||||
// Enumerate the actual DXGI adapters and create a D3D11 device on each NVIDIA
|
||||
// adapter. A WMI/PnP model name alone does not prove that D3D is operational.
|
||||
public static class D3DProbe {
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
private struct AdapterDesc {
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Description;
|
||||
public uint VendorId, DeviceId, SubSysId, Revision;
|
||||
public UIntPtr DedicatedVideoMemory, DedicatedSystemMemory, SharedSystemMemory;
|
||||
public long AdapterLuid;
|
||||
}
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
private delegate int EnumAdapters(IntPtr factory, uint index, out IntPtr adapter);
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
private delegate int GetDesc(IntPtr adapter, out AdapterDesc desc);
|
||||
[DllImport("dxgi.dll")]
|
||||
private static extern int CreateDXGIFactory1(ref Guid iid, out IntPtr factory);
|
||||
[DllImport("d3d11.dll")]
|
||||
private static extern int D3D11CreateDevice(IntPtr adapter, uint driverType,
|
||||
IntPtr software, uint flags, IntPtr levels, uint levelCount, uint sdkVersion,
|
||||
out IntPtr device, out uint featureLevel, out IntPtr context);
|
||||
|
||||
public static AdapterResult[] Check() {
|
||||
var results = new List<AdapterResult>();
|
||||
var iid = new Guid("770aae78-f26f-4dba-a829-253c83d1b387");
|
||||
IntPtr factory;
|
||||
Marshal.ThrowExceptionForHR(CreateDXGIFactory1(ref iid, out factory));
|
||||
try {
|
||||
var table = Marshal.ReadIntPtr(factory);
|
||||
var enumerate = (EnumAdapters)Marshal.GetDelegateForFunctionPointer(
|
||||
Marshal.ReadIntPtr(table, 7 * IntPtr.Size), typeof(EnumAdapters));
|
||||
for (uint i = 0; i < 32; i++) {
|
||||
IntPtr adapter;
|
||||
int hr = enumerate(factory, i, out adapter);
|
||||
if (hr == unchecked((int)0x887A0002)) break;
|
||||
Marshal.ThrowExceptionForHR(hr);
|
||||
try {
|
||||
var descMethod = (GetDesc)Marshal.GetDelegateForFunctionPointer(
|
||||
Marshal.ReadIntPtr(Marshal.ReadIntPtr(adapter), 8 * IntPtr.Size), typeof(GetDesc));
|
||||
AdapterDesc desc;
|
||||
Marshal.ThrowExceptionForHR(descMethod(adapter, out desc));
|
||||
if (desc.VendorId != 0x10de) continue;
|
||||
IntPtr device, context;
|
||||
uint level;
|
||||
hr = D3D11CreateDevice(adapter, 0, IntPtr.Zero, 0, IntPtr.Zero,
|
||||
0, 7, out device, out level, out context);
|
||||
if (context != IntPtr.Zero) Marshal.Release(context);
|
||||
if (device != IntPtr.Zero) Marshal.Release(device);
|
||||
results.Add(new AdapterResult { Name = desc.Description,
|
||||
VendorId = desc.VendorId, DeviceResult = hr });
|
||||
} finally { Marshal.Release(adapter); }
|
||||
}
|
||||
} finally { Marshal.Release(factory); }
|
||||
return results.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
55
tools/run-input-latency-bench.py
Normal file
@ -0,0 +1,55 @@
|
||||
"""Start/status/stop only the temporary VDI input benchmark through VM100's agent."""
|
||||
import argparse
|
||||
import base64
|
||||
from pathlib import Path
|
||||
import runpy
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("action", choices=["start", "status", "stop"])
|
||||
args = parser.parse_args()
|
||||
tools_dir = Path(__file__).resolve().parent
|
||||
term = runpy.run_path(str(tools_dir / "pve_term_exec.py"))
|
||||
vm = runpy.run_path(str(tools_dir / "pve_vm.py"))
|
||||
ticket, csrf = term["login"]()
|
||||
state = vm["api"]("/api2/json/nodes/starhe/qemu/100/status/current", ticket=ticket)
|
||||
if state.get("status") != "running":
|
||||
sys.exit("VM100 is not running; no benchmark task changed")
|
||||
folder = r"C:\ProgramData\VDI\input-bench-20261103"
|
||||
prefix = "$ErrorActionPreference='Stop'; $folder='" + folder + "'; "
|
||||
if args.action == "start":
|
||||
encoded = base64.b64encode((tools_dir / "input-latency-bench.ps1").read_bytes()).decode()
|
||||
command = prefix + r"""
|
||||
New-Item -ItemType Directory -Force $folder | Out-Null
|
||||
if (Get-ScheduledTask -TaskName VDIInputLatencyBench -ErrorAction SilentlyContinue) { throw 'Benchmark task already exists; stop it first' }
|
||||
[IO.File]::WriteAllBytes("$folder\bench.ps1",[Convert]::FromBase64String('""" + encoded + r"""'))
|
||||
$action=New-ScheduledTaskAction -Execute powershell.exe -Argument "-NoProfile -ExecutionPolicy Bypass -STA -WindowStyle Hidden -File $folder\bench.ps1"
|
||||
$principal=New-ScheduledTaskPrincipal -UserId test -LogonType Interactive -RunLevel Limited
|
||||
$settings=New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 10)
|
||||
Register-ScheduledTask -TaskName VDIInputLatencyBench -Action $action -Principal $principal -Settings $settings | Out-Null
|
||||
Start-ScheduledTask -TaskName VDIInputLatencyBench
|
||||
'Benchmark launched'
|
||||
"""
|
||||
elif args.action == "status":
|
||||
command = prefix + r"""
|
||||
Get-Content "$folder\status.txt" -ErrorAction SilentlyContinue
|
||||
Get-Content "$folder\clicks.csv" -ErrorAction SilentlyContinue
|
||||
Get-ScheduledTaskInfo -TaskName VDIInputLatencyBench | Select-Object LastTaskResult | ConvertTo-Json -Compress
|
||||
"""
|
||||
else:
|
||||
command = prefix + r"""
|
||||
Stop-ScheduledTask -TaskName VDIInputLatencyBench -ErrorAction SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName VDIInputLatencyBench -Confirm:$false -ErrorAction SilentlyContinue
|
||||
if (Test-Path "$folder\pid.txt") {
|
||||
$benchPid=[int](Get-Content "$folder\pid.txt")
|
||||
$process=Get-CimInstance Win32_Process -Filter "ProcessId=$benchPid"
|
||||
if ($process.CommandLine -like '*input-bench-20261103*') { Stop-Process -Id $benchPid -ErrorAction SilentlyContinue }
|
||||
}
|
||||
'Benchmark stopped; other applications untouched'
|
||||
"""
|
||||
out, error = vm["agent"](ticket, csrf, ["powershell.exe", "-NoProfile", "-Command", command])
|
||||
print(out)
|
||||
if error:
|
||||
print(error, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
61
tools/run-mouse-display-probe.py
Normal file
@ -0,0 +1,61 @@
|
||||
"""Run the scoped VDD mode probe in VM100's already logged-in user session."""
|
||||
import argparse
|
||||
import base64
|
||||
from pathlib import Path
|
||||
import runpy
|
||||
import sys
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("action", choices=["Query", "List", "Apply", "Restore"])
|
||||
parser.add_argument("--hz", type=int, default=60)
|
||||
args = parser.parse_args()
|
||||
if not 24 <= args.hz <= 240:
|
||||
parser.error("--hz must be in 24..240")
|
||||
root = Path(__file__).resolve().parent
|
||||
term = runpy.run_path(str(root / "pve_term_exec.py"))
|
||||
vm = runpy.run_path(str(root / "pve_vm.py"))
|
||||
ticket, csrf = term["login"]()
|
||||
state = vm["api"]("/api2/json/nodes/starhe/qemu/100/status/current", ticket=ticket)
|
||||
if state.get("status") != "running":
|
||||
sys.exit("VM100 is not running; no task or display configuration changed")
|
||||
payload = base64.b64encode((root / "set-vdi-display-mode.ps1").read_bytes()).decode()
|
||||
command = r"""
|
||||
$ErrorActionPreference='Stop'
|
||||
$folder='C:\ProgramData\VDI\mouse-optimization'
|
||||
$task='VDIMouseDisplayProbe'
|
||||
if(Get-ScheduledTask -TaskName $task -ErrorAction SilentlyContinue) { throw 'Probe task already exists' }
|
||||
$user=(Get-CimInstance Win32_ComputerSystem).UserName
|
||||
if(-not $user) { throw 'No interactive user' }
|
||||
New-Item -ItemType Directory -Force $folder | Out-Null
|
||||
$acl=Get-Acl -LiteralPath $folder
|
||||
$rule=New-Object Security.AccessControl.FileSystemAccessRule($user,'Modify','ContainerInherit,ObjectInherit','None','Allow')
|
||||
$acl.SetAccessRule($rule)
|
||||
Set-Acl -LiteralPath $folder -AclObject $acl
|
||||
[IO.File]::WriteAllBytes("$folder\mode.ps1",[Convert]::FromBase64String('__VDI_PAYLOAD__'))
|
||||
$run="try { & '$folder\mode.ps1' -Action __VDI_ACTION__ -RefreshRate __VDI_HZ__ | Out-File -Encoding utf8 -Width 300 '$folder\mode-result.txt' } catch { `$_ | Out-String | Out-File -Encoding utf8 -Width 300 '$folder\mode-result.txt'; exit 1 }"
|
||||
$encoded=[Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($run))
|
||||
$action=New-ScheduledTaskAction -Execute powershell.exe -Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -EncodedCommand $encoded"
|
||||
$principal=New-ScheduledTaskPrincipal -UserId $user -LogonType Interactive -RunLevel Limited
|
||||
$settings=New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 1)
|
||||
Register-ScheduledTask -TaskName $task -Action $action -Principal $principal -Settings $settings | Out-Null
|
||||
try {
|
||||
Start-ScheduledTask -TaskName $task
|
||||
Start-Sleep -Seconds 2
|
||||
for($i=0;$i -lt 20;$i++) {
|
||||
if((Get-ScheduledTask -TaskName $task).State -ne 'Running') { break }
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
if((Get-ScheduledTask -TaskName $task).State -eq 'Running') { throw 'Probe timed out' }
|
||||
Get-Content "$folder\mode-result.txt"
|
||||
'task_result='+(Get-ScheduledTaskInfo -TaskName $task).LastTaskResult
|
||||
} finally {
|
||||
Stop-ScheduledTask -TaskName $task -ErrorAction SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName $task -Confirm:$false
|
||||
}
|
||||
""".replace("__VDI_ACTION__", args.action).replace("__VDI_HZ__", str(args.hz)).replace("__VDI_PAYLOAD__", payload)
|
||||
out, error = vm["agent"](ticket, csrf, ["powershell.exe", "-NoProfile", "-Command", command])
|
||||
print(out)
|
||||
if error or "task_result=0" not in out:
|
||||
print(error, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
52
tools/set-desktop-responsiveness.ps1
Normal file
@ -0,0 +1,52 @@
|
||||
param([switch]$Restore)
|
||||
# Run in the logged-in desktop user session, not the Guest Agent's Session 0.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$directory = Join-Path $env:LOCALAPPDATA 'VDI'
|
||||
New-Item -ItemType Directory -Force $directory | Out-Null
|
||||
$backup = Join-Path $directory 'desktop-responsiveness-before-20261103.json'
|
||||
Add-Type @'
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class VDIVisualResponse {
|
||||
[StructLayout(LayoutKind.Sequential)] struct Animation { public uint size; public int enabled; }
|
||||
[DllImport("user32.dll", EntryPoint="SystemParametersInfoW", SetLastError=true)]
|
||||
static extern bool SpiAnimation(uint action, uint size, ref Animation data, uint flags);
|
||||
[DllImport("user32.dll", EntryPoint="SystemParametersInfoW", SetLastError=true)]
|
||||
static extern bool SpiGet(uint action, uint unused, out uint value, uint flags);
|
||||
[DllImport("user32.dll", EntryPoint="SystemParametersInfoW", SetLastError=true)]
|
||||
static extern bool SpiSet(uint action, uint value, IntPtr unused, uint flags);
|
||||
static void Check(bool result) { if(!result) throw new Win32Exception(Marshal.GetLastWin32Error()); }
|
||||
public static int AnimationEnabled() {
|
||||
Animation data = new Animation { size=8 };
|
||||
Check(SpiAnimation(0x0048,8,ref data,0)); return data.enabled;
|
||||
}
|
||||
public static uint MenuDelay() { uint value; Check(SpiGet(0x006A,0,out value,0)); return value; }
|
||||
public static void Set(int animation, uint delay) {
|
||||
Animation data = new Animation { size=8, enabled=animation };
|
||||
Check(SpiAnimation(0x0049,8,ref data,3));
|
||||
Check(SpiSet(0x006B,delay,IntPtr.Zero,3));
|
||||
}
|
||||
}
|
||||
'@
|
||||
$before = @{ animation=[VDIVisualResponse]::AnimationEnabled(); menuDelay=[VDIVisualResponse]::MenuDelay() }
|
||||
if ($Restore) {
|
||||
$target = Get-Content -LiteralPath $backup -Raw | ConvertFrom-Json
|
||||
} else {
|
||||
if (-not (Test-Path -LiteralPath $backup)) {
|
||||
$before | ConvertTo-Json | Set-Content -LiteralPath $backup -Encoding UTF8
|
||||
}
|
||||
$target = @{ animation=0; menuDelay=100 }
|
||||
}
|
||||
try {
|
||||
[VDIVisualResponse]::Set([int]$target.animation,[uint32]$target.menuDelay)
|
||||
$after = @{ animation=[VDIVisualResponse]::AnimationEnabled(); menuDelay=[VDIVisualResponse]::MenuDelay() }
|
||||
if ($after.animation -ne $target.animation -or $after.menuDelay -ne $target.menuDelay) {
|
||||
throw 'Desktop preferences were not retained'
|
||||
}
|
||||
@{ before=$before; after=$after; backup=$backup; restored=[bool]$Restore } |
|
||||
ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $directory 'desktop-responsiveness-result.json') -Encoding UTF8
|
||||
} catch {
|
||||
[VDIVisualResponse]::Set([int]$before.animation,[uint32]$before.menuDelay)
|
||||
throw
|
||||
}
|
||||
111
tools/set-vdi-display-mode.ps1
Normal file
@ -0,0 +1,111 @@
|
||||
param(
|
||||
[ValidateSet('Query', 'List', 'Apply', 'Restore')][string]$Action = 'Query',
|
||||
[ValidateRange(640, 7680)][int]$Width = 2560,
|
||||
[ValidateRange(480, 4320)][int]$Height = 1440,
|
||||
[ValidateRange(24, 240)][int]$RefreshRate = 60,
|
||||
[string]$BackupPath = 'C:\ProgramData\VDI\mouse-optimization\display-before.json'
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
# Run in the logged-in desktop session. Apply is temporary (no registry update).
|
||||
# Never assumes DISPLAY1, and refuses ambiguous active virtual displays.
|
||||
Add-Type -TypeDefinition @'
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
public static class VdiModeProbe {
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct Device {
|
||||
public int cb;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string Name;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Description;
|
||||
public int Flags;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Id;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string Key;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct Mode {
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string name;
|
||||
public short spec, driver, size, extra;
|
||||
public int fields, x, y, orientation, fixedOutput;
|
||||
public short color, duplex, yres, tt, collate;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string form;
|
||||
public short logPixels;
|
||||
public int bpp, width, height, flags, hz, icmMethod, icmIntent, media, dither,
|
||||
reserved1, reserved2, panWidth, panHeight;
|
||||
}
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
static extern bool EnumDisplayDevices(string name, uint index, ref Device dev, uint flags);
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
static extern bool EnumDisplaySettings(string name, int index, ref Mode mode);
|
||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||
static extern int ChangeDisplaySettingsEx(string name, ref Mode mode, IntPtr window, uint flags, IntPtr param);
|
||||
public static string Find() {
|
||||
string found = null;
|
||||
for (uint i = 0; ; i++) {
|
||||
var d = new Device(); d.cb = Marshal.SizeOf(typeof(Device));
|
||||
if (!EnumDisplayDevices(null, i, ref d, 0)) return found;
|
||||
if ((d.Flags & 1) == 0 || d.Description.IndexOf("Virtual Display Driver", StringComparison.OrdinalIgnoreCase) < 0) continue;
|
||||
if (found != null) throw new InvalidOperationException("Multiple active virtual displays; select manually");
|
||||
found = d.Name;
|
||||
}
|
||||
}
|
||||
public static Mode Current(string name) {
|
||||
var m = new Mode(); m.size = (short)Marshal.SizeOf(typeof(Mode));
|
||||
if (!EnumDisplaySettings(name, -1, ref m)) throw new InvalidOperationException("Cannot query mode");
|
||||
return m;
|
||||
}
|
||||
public static Mode[] List(string name) {
|
||||
var modes = new List<Mode>();
|
||||
for(int i=0; ; ++i) {
|
||||
var m = new Mode(); m.size = (short)Marshal.SizeOf(typeof(Mode));
|
||||
if (!EnumDisplaySettings(name, i, ref m)) return modes.ToArray();
|
||||
modes.Add(m);
|
||||
}
|
||||
}
|
||||
public static void Apply(string name, int w, int h, int hz, int bpp) {
|
||||
foreach(var m0 in List(name)) {
|
||||
var m = m0;
|
||||
if(m.width != w || m.height != h || m.hz != hz || m.bpp != bpp) continue;
|
||||
m.fields = 0x80000 | 0x100000 | 0x400000 | 0x40000;
|
||||
int result = ChangeDisplaySettingsEx(name, ref m, IntPtr.Zero, 2, IntPtr.Zero);
|
||||
if(result != 0) throw new InvalidOperationException("Mode test failed: " + result);
|
||||
result = ChangeDisplaySettingsEx(name, ref m, IntPtr.Zero, 0, IntPtr.Zero);
|
||||
if(result != 0) throw new InvalidOperationException("Mode apply failed: " + result);
|
||||
var actual = Current(name);
|
||||
if(actual.width != w || actual.height != h || actual.hz != hz || actual.bpp != bpp)
|
||||
throw new InvalidOperationException("Mode read-back mismatch");
|
||||
return;
|
||||
}
|
||||
throw new InvalidOperationException("Requested mode not advertised");
|
||||
}
|
||||
}
|
||||
'@
|
||||
$device = [VdiModeProbe]::Find()
|
||||
if (-not $device) { throw 'No active Virtual Display Driver in this session' }
|
||||
$current = [VdiModeProbe]::Current($device)
|
||||
if ($Action -eq 'List') {
|
||||
[VdiModeProbe]::List($device) | Where-Object { $_.width -eq $Width -and $_.height -eq $Height } |
|
||||
Select-Object width,height,hz,bpp | ConvertTo-Json -Compress
|
||||
exit 0
|
||||
}
|
||||
if ($Action -eq 'Apply') {
|
||||
if (-not (Test-Path -LiteralPath $BackupPath)) {
|
||||
New-Item -ItemType Directory -Force (Split-Path $BackupPath) | Out-Null
|
||||
@{device=$device; width=$current.width; height=$current.height; hz=$current.hz; bpp=$current.bpp} |
|
||||
ConvertTo-Json | Set-Content -LiteralPath $BackupPath
|
||||
}
|
||||
try {
|
||||
[VdiModeProbe]::Apply($device,$Width,$Height,$RefreshRate,$current.bpp)
|
||||
} catch {
|
||||
[VdiModeProbe]::Apply($device,$current.width,$current.height,$current.hz,$current.bpp)
|
||||
throw
|
||||
}
|
||||
}
|
||||
if ($Action -eq 'Restore') {
|
||||
$before = Get-Content -LiteralPath $BackupPath -Raw | ConvertFrom-Json
|
||||
if ($before.device -ne $device) { throw 'Display identity changed; inspect before restoring' }
|
||||
[VdiModeProbe]::Apply($device,$before.width,$before.height,$before.hz,$before.bpp)
|
||||
}
|
||||
$current = [VdiModeProbe]::Current($device)
|
||||
@{device=$device; width=$current.width; height=$current.height; hz=$current.hz; bpp=$current.bpp; action=$Action} |
|
||||
ConvertTo-Json -Compress
|
||||
39
tools/stream-motion-test.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>VDI stream motion test</title>
|
||||
<style>
|
||||
html, body { margin: 0; overflow: hidden; background: #101827; color: white; font: 24px monospace; }
|
||||
canvas { display: block; width: 100vw; height: 100vh; }
|
||||
#stats { position: fixed; right: 24px; top: 20px; background: #000c; padding: 12px; }
|
||||
</style>
|
||||
<canvas id="scene"></canvas><div id="stats"></div>
|
||||
<script>
|
||||
// Deterministic moving bars + checkerboard: creates continuous desktop damage.
|
||||
// Read the source RAF rate separately from the Moonlight stream/render rate.
|
||||
const canvas = document.getElementById('scene');
|
||||
const context = canvas.getContext('2d', { alpha: false });
|
||||
const stats = document.getElementById('stats');
|
||||
let count = 0, last = performance.now(), sourceFps = 0;
|
||||
function render(now) {
|
||||
if (canvas.width !== innerWidth || canvas.height !== innerHeight) {
|
||||
canvas.width = innerWidth; canvas.height = innerHeight;
|
||||
}
|
||||
const width = canvas.width, height = canvas.height;
|
||||
context.fillStyle = '#101827'; context.fillRect(0, 0, width, height);
|
||||
const offset = Math.floor(now * 0.12) % 128;
|
||||
for (let y = height / 2; y < height; y += 128) {
|
||||
for (let x = -128; x < width; x += 128) {
|
||||
context.fillStyle = (Math.round((x + 128) / 128) + Math.floor(y / 128)) % 2 ? '#28517a' : '#132c46';
|
||||
context.fillRect(x + offset, y, 126, 126);
|
||||
}
|
||||
}
|
||||
const x = (now * 0.6) % (width + 100) - 100;
|
||||
context.fillStyle = '#ffcf40'; context.fillRect(x, 0, 80, height);
|
||||
context.fillStyle = '#ffffff'; context.fillRect(width - x, 0, 8, height);
|
||||
count++;
|
||||
if (now - last >= 1000) { sourceFps = count * 1000 / (now - last); count = 0; last = now; }
|
||||
stats.textContent = `${width}x${height} | source RAF ${sourceFps.toFixed(1)} FPS | ${Math.floor(now)} ms`;
|
||||
requestAnimationFrame(render);
|
||||
}
|
||||
requestAnimationFrame(render);
|
||||
</script>
|
||||
31
tools/test-moonlight-latency.sh
Normal file
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
# Run against the actual patched source and private runtime on the ARM64 box.
|
||||
set -euo pipefail
|
||||
b="${VDI_RKMPP_BUILD_ROOT:-$HOME/vdi-build/rkmpp-experiment}"
|
||||
sdk="$b/deps/usr"
|
||||
export LD_LIBRARY_PATH="$b/runtime/lib:$sdk/lib/aarch64-linux-gnu${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
export PKG_CONFIG_PATH="$b/runtime/lib/pkgconfig:$sdk/lib/aarch64-linux-gnu/pkgconfig:$sdk/share/pkgconfig"
|
||||
export CPLUS_INCLUDE_PATH="$sdk/include/aarch64-linux-gnu:$sdk/include"
|
||||
export C_INCLUDE_PATH="$sdk/include/aarch64-linux-gnu:$sdk/include"
|
||||
sanitize=()
|
||||
if [ "${VDI_TEST_SANITIZE:-0}" = 1 ]; then
|
||||
sanitize=(-fsanitize=address -g)
|
||||
fi
|
||||
g++ "${sanitize[@]}" -std=c++17 -fPIC -UNDEBUG "$b/latency-tests/test_latency.cpp" \
|
||||
-I"$b/src/moonlight/app/streaming/input" \
|
||||
-I"$b/src/moonlight/app/streaming/video/ffmpeg-renderers/pacer" \
|
||||
-I"$b/runtime/include" $(pkg-config --cflags --libs Qt5Core sdl2) \
|
||||
-L"$b/runtime/lib" -lavutil -o "$b/latency-tests/test_latency"
|
||||
"$b/latency-tests/test_latency"
|
||||
|
||||
g++ "${sanitize[@]}" -std=c++17 -fPIC -UNDEBUG "$b/latency-tests/test_input_priority.cpp" \
|
||||
-I"$b/src/moonlight/app/streaming/input" $(pkg-config --cflags --libs sdl2) \
|
||||
-o "$b/latency-tests/test_input_priority"
|
||||
"$b/latency-tests/test_input_priority"
|
||||
gcc "${sanitize[@]}" -std=gnu11 -ffunction-sections -fdata-sections -Wl,--gc-sections -UNDEBUG \
|
||||
-I"$b/src/moonlight/moonlight-common-c/moonlight-common-c/src" \
|
||||
-I"$b/src/moonlight/moonlight-common-c/moonlight-common-c/enet/include" \
|
||||
"$b/latency-tests/test_absolute_input.c" \
|
||||
"$b/build/moonlight/moonlight-common-c/libmoonlight-common-c.a" \
|
||||
-lpthread -lcrypto -o "$b/latency-tests/test_absolute_input"
|
||||
"$b/latency-tests/test_absolute_input"
|
||||
105
tools/validate-sunshine-nvenc.ps1
Normal file
@ -0,0 +1,105 @@
|
||||
param(
|
||||
[string]$SunshineLogPath = "",
|
||||
[int]$MaxLogAgeMinutes = 30
|
||||
)
|
||||
|
||||
# 只读验收脚本:不重启 VM、设备、VFIO 或 Sunshine,不修改任何配置。
|
||||
# 退出码 0 才表示当前状态满足“可继续做串流性能验收”的前置条件。
|
||||
$ErrorActionPreference = "Stop"
|
||||
$ok = $true
|
||||
|
||||
function Report([string]$Name, [bool]$Passed, [string]$Detail) {
|
||||
$state = if ($Passed) { "PASS" } else { "FAIL" }
|
||||
Write-Output ("[{0}] {1}: {2}" -f $state, $Name, $Detail)
|
||||
}
|
||||
|
||||
$nvidiaCommand = Get-Command nvidia-smi -ErrorAction SilentlyContinue
|
||||
if ($null -eq $nvidiaCommand) {
|
||||
Report "nvidia-smi" $false "命令不存在"
|
||||
$ok = $false
|
||||
} else {
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$gpuText = & $nvidiaCommand.Source --query-gpu=name,driver_version,pstate --format=csv,noheader 2>&1
|
||||
$queryExitCode = $LASTEXITCODE
|
||||
$ErrorActionPreference = 'Stop'
|
||||
if ($queryExitCode -ne 0 -or [string]::IsNullOrWhiteSpace(($gpuText -join ""))) {
|
||||
Report "nvidia-smi" $false (($gpuText -join " ").Trim())
|
||||
$ok = $false
|
||||
} else {
|
||||
Report "nvidia-smi" $true (($gpuText -join " ").Trim())
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$displayAdapters = @(Get-CimInstance Win32_VideoController |
|
||||
Where-Object { $_.Name -match "NVIDIA|GeForce|Quadro|Tesla" })
|
||||
$healthy = @($displayAdapters | Where-Object { $_.ConfigManagerErrorCode -eq 0 }).Count -gt 0
|
||||
Report "NVIDIA PnP" $healthy (($displayAdapters | ForEach-Object { "$($_.Name): code=$($_.ConfigManagerErrorCode)" }) -join "; ")
|
||||
$ok = $ok -and $healthy
|
||||
if (-not ('VdiDiagnostics.D3DProbe' -as [type])) {
|
||||
Add-Type -Path (Join-Path $PSScriptRoot 'probe-nvidia-d3d.cs')
|
||||
}
|
||||
$dxgi = @([VdiDiagnostics.D3DProbe]::Check())
|
||||
$healthy = @($dxgi | Where-Object { $_.DeviceResult -eq 0 }).Count -gt 0
|
||||
$detail = if ($dxgi.Count) { ($dxgi | ForEach-Object { '{0}: HRESULT=0x{1:X8}' -f $_.Name,$_.DeviceResult }) -join '; ' } else { 'DXGI did not enumerate an NVIDIA adapter' }
|
||||
Report "NVIDIA DXGI + D3D11" $healthy $detail
|
||||
$ok = $ok -and $healthy
|
||||
} catch {
|
||||
Report "NVIDIA DXGI + D3D11" $false $_.Exception.Message
|
||||
$ok = $false
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($SunshineLogPath)) {
|
||||
$candidates = @(
|
||||
"C:\Program Files\Sunshine\config\sunshine.log",
|
||||
"C:\ProgramData\Sunshine\config\sunshine.log"
|
||||
)
|
||||
$SunshineLogPath = $candidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($SunshineLogPath) -or -not (Test-Path -LiteralPath $SunshineLogPath)) {
|
||||
Report "Sunshine encoder" $false "找不到 sunshine.log;不能证明实际使用 h264_nvenc"
|
||||
$ok = $false
|
||||
} else {
|
||||
# Encoder discovery/probing can mention both NVENC and x264. Inspect only
|
||||
# the most recent actual creation, with a timestamp, never the entire history.
|
||||
$pattern = '\[(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+)\].*Creating encoder \[(?<encoder>[^\]]+)\]'
|
||||
$matches = [regex]::Matches((Get-Content -LiteralPath $SunshineLogPath -Raw), $pattern)
|
||||
$healthy = $false
|
||||
$detail = '没有实际编码器创建记录;请连接Moonlight并播放测试动画'
|
||||
if ($matches.Count -gt 0) {
|
||||
$entry = $matches[$matches.Count - 1]
|
||||
$encoder = $entry.Groups['encoder'].Value
|
||||
$createdAt = [datetime]::Parse($entry.Groups['time'].Value, [Globalization.CultureInfo]::InvariantCulture)
|
||||
$ageMinutes = ((Get-Date) - $createdAt).TotalMinutes
|
||||
$healthy = $encoder -eq 'h264_nvenc' -and $ageMinutes -ge 0 -and $ageMinutes -le $MaxLogAgeMinutes
|
||||
$detail = '{0}, created {1}, age {2:N1} min' -f $encoder,$createdAt,$ageMinutes
|
||||
}
|
||||
Report "Sunshine active encoder" $healthy $detail
|
||||
$ok = $ok -and $healthy
|
||||
}
|
||||
|
||||
if ($nvidiaCommand) {
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$activity = & $nvidiaCommand.Source --query-gpu=encoder.stats.sessionCount,utilization.encoder --format=csv,noheader,nounits 2>&1
|
||||
$queryExitCode = $LASTEXITCODE
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$healthy = $false
|
||||
if ($queryExitCode -eq 0) {
|
||||
foreach ($row in $activity) {
|
||||
if ([string]$row -match '^\s*(\d+),\s*(\d+)\s*$') {
|
||||
if ([int]$Matches[1] -gt 0 -and [int]$Matches[2] -gt 0) { $healthy = $true }
|
||||
}
|
||||
}
|
||||
}
|
||||
Report "NVENC session/utilization" $healthy ($activity -join '; ')
|
||||
$ok = $ok -and $healthy
|
||||
}
|
||||
|
||||
if ($ok) {
|
||||
Write-Output "GPU/NVENC 前置验收通过:可以继续做 Moonlight 帧率与延迟测试。"
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Output "GPU/NVENC 前置验收失败:不要把当前状态作为硬编码性能结果。"
|
||||
exit 1
|
||||