目录

OHScrcpy:OpenHarmony 6.1 / RoboPi 迁移版

本版本基于 ScreenMagic/xpbdp 的截图投屏实现,面向厂家配套的 RoboPi OpenHarmony 6.1 源码。设备端调用 DisplayManager 截图,使用 libjpeg-turbo 编码,通过 HDC 转发到 Python / PyQt6 客户端;输入继续使用设备上的 uinput。

已完成 RoboPi arm64 目标编译,当前产物为支持 --headless 的 headless-v1。用户板卡已验证 1280×720 无屏截图;手动重启桌面和系统界面进程后,桌面与系统栏窗口尺寸恢复,上滑命令解锁成功。启动器已接入针对 0×0 窗口故障的自动恢复,30 项电脑端测试通过;Linux 主机已实测 720×1280 竖屏下单独恢复 SystemUI,并通过真实视频流核对完整画面。自动恢复流程的板卡冷启动验证及客户端完整交互仍待完成,不能沿用原版 DAYU200 / OH 4.0.2 的帧率结论。

编译设备端

在含完整 OH 6.1 源码的编译主机上执行:

python3 tools/integrate_ohos.py /path/to/openharmony-6.1-robopi
cd /path/to/openharmony-6.1-robopi
bash build.sh --product-name robopi --ccache --build-target scrcpyoh_server --ninja-args=-j8

集成脚本将四个文件复制到 foundation/window/window_manager/scrcpyoh/,并在 window_manager/bundle.json 的 base_group 中注册目标。它保留该配置的原有格式和其他源码改动,可以在修改服务端后再次执行。

目标产物是:

out/robopi/window/window_manager/scrcpyoh_server

把新产物复制到本项目的 dist/scrcpyoh_server,启动器默认使用这里的文件。这是子目标构建,不会自动重新生成并刷入完整系统镜像。服务器环境中的临时目录、缓存和工具配置应沿用该源码树已经验证的构建环境。

仓库根目录保留的 scrcpyoh_server、scrcpyoh_server_virtual 是上游旧版二进制,不适用于本次 6.1 迁移;启动器不使用它们。server/src/ohscrcpy_virtual.cpp 也仍为上游参考实现,没有接入新目标。

运行客户端

电脑上安装 Python 3.9 或更新版本、HDC,并安装依赖:

python3 -m pip install -r requirements.txt
bash launch.sh --device <HDC设备标识>

Windows 使用:

python -m pip install -r requirements.txt
launch.bat --device <HDC设备标识>

只有一个 HDC 目标时可以省略设备参数。多设备环境必须选择设备,图像转发和所有输入使用同一标识。HDC 环境变量或 --hdc 可以指定工具路径;PYTHON 环境变量可以指定启动器使用的 Python。

启动器发送 dist/scrcpyoh_server,从 HDC shell 启动,并保留 /data/local/tmp/scrcpyoh_server.log。它只清理本次创建的转发和进程。若该目标上已有 scrcpyoh_server,启动器保留现有进程;可以直接连接已运行的服务:

python3 client/main.py --device <HDC设备标识> --host 127.0.0.1 --port 8000

运行参数可以调整:

bash launch.sh --device <HDC设备标识> --max-size 1280 --fps 15 --quality 75

--max-size 是传输图像长边上限,按屏幕纵横比缩放;--fps 是截图循环的速率上限,不是保证达到的帧率。服务器保留系统截图权限检查,并要求开发者模式,只监听设备回环地址。

如果板卡连接在另一台主机,HDC 和图像端口都要能从客户端到达。--hdc-server <地址:端口> 对应 HDC 的 -s 参数;--host 指定客户端连接画面流的地址。远端 HDC 创建的转发监听在 HDC 服务主机上,因此跨主机使用还需要已有的 SSH 转发等连接方式。工具不会修改 HDC 服务监听配置,也不会重启共享 HDC 服务。

当前工作区的主机分工是:本机维护项目,r743 编译,gitserver 连接板卡。不要把本机 localhost:8000 误当成 gitserver 上的同名端口。

仅接 USB 的无屏模式

若未接 HDMI,且 hidumper -s DisplayManagerService -a '-s -a' 输出 total screen num: 0,使用新增的无屏模式:

python client/launch.py --device <HDC设备标识> --headless 1280x720

1280x720 是要创建的桌面分辨率,--max-size 仍只控制传输图像的长边。需要本次更新后的 client/launch.py 和 dist/scrcpyoh_server;旧产物没有 --headless 参数。新版设备端的 --version 输出包含 headless-v1。

Windows 可以继续使用已经配置好的虚拟环境。在项目目录中执行:

.venv\Scripts\python.exe client\launch.py --headless 1280x720

只有一个 HDC 目标时自动选择;有多个目标时追加 --device <HDC设备标识>。启动器会把新版二进制发送到板卡,不需要手工复制到设备,也不需要为这个子目标重新烧录整套镜像。

无屏模式在没有任何屏幕时创建名为 xpbdp-headless 的虚拟屏,再调用 OH 6.1 的 SetVirtualScreenAsDefault 建立默认显示。服务端维持图像输出缓冲区的接收和释放,截图仍通过原来的系统截图接口及权限检查。如果已有有效默认显示,则继续使用它,不改变其分辨率。普通启动不会自动创建虚拟屏。

有些无屏启动的板卡会留下尺寸为 0×0 的桌面和系统栏。可能只显示壁纸,也可能桌面和应用已恢复,但顶部状态栏、底部导航栏仍然缺失。后者在开发板原始截图中也会出现,看起来像上下画面被裁剪。

启动器在创建或重接 xpbdp 虚拟屏后检查窗口列表。当桌面、状态栏、导航栏的窗口记录都存在,且两条系统栏均为 0×0 时,恢复 SystemUI;如果桌面也为 0×0,再同时恢复 Launcher。随后等待被恢复的窗口全部具有有效尺寸,包括底部导航栏。这个检查限定在当前 HDC 目标的 xpbdp 虚拟显示上;桌面尺寸正常时保留原 Launcher 进程,单条系统栏为 0×0 不触发恢复。

恢复后可能出现正常锁屏页,显示时间、电量和“上滑解锁”。在客户端按住鼠标从画面下方向上拖动后松开即可尝试解锁;若出现密码页,按系统要求正常认证。启动器保留锁屏机制。对 1280×720 的显示,也可以手动验证上滑输入:

hdc -t DEVICE_ID shell uinput -T -m 640 620 640 160 500

这版系统不允许销毁已设为默认屏的虚拟屏,因此它会保留到板卡重启。关闭客户端会停止本次服务端并释放输出连接;下次启动会重新连接到已有虚拟屏。要更换无屏桌面分辨率,先重启板卡,再使用新的 --headless WIDTHxHEIGHT 参数启动。启动器不会自行重启板卡。

源码接口和编译结果不能替代实际桌面验证。后续还需要在用户笔记本连接的板卡上确认新启动器的冷启动自动恢复,以及客户端点击、滑动和键盘输入。若出现黑屏、仅壁纸或截图失败,请保留以下输出(将 DEVICE_ID 换成实际标识):

hdc -t DEVICE_ID shell cat /data/local/tmp/scrcpyoh_server.log
hdc -t DEVICE_ID shell "hidumper -s DisplayManagerService -a '-s -a'"
hdc -t DEVICE_ID shell "hidumper -s DisplayManagerService -a '-d -a'"
hdc -t DEVICE_ID shell "hidumper -s WindowManagerService -a '-a'"
hdc -t DEVICE_ID shell snapshot_display -f /data/local/tmp/xpbdp-headless-check.jpeg

日志中的 Headless display ready 仅表示默认显示对象存在;First screenshot captured 仅表示取得了 PixelMap。只有实际看到桌面并验证输入,才能确认无屏投屏可用。

操作范围

  • 鼠标在画面内点击映射为一次触摸点击;按下后移动、释放,映射为一次完整滑动。坐标根据本帧的实际屏幕尺寸和居中留白计算。
  • 滚轮映射为上下滑动;字母、数字、空格、回车、退格、方向键及常用修饰键通过 uinput 发送。完整输入法、中文输入、持续按住拖动和多点触控尚未实现。
  • 窗口缩放只改变电脑端显示大小;图像按实际显示区域等比例缩放、居中留白。窗口或状态栏改变显示区域时会立即重新缩放最近一帧,不需要等待下一帧。服务器按每帧读取的默认显示尺寸截图,尺寸或方向变化时取消尚未提交的手势。
  • 断连会在客户端显示原因,并停止新的输入。服务端允许新客户端重新连接;电脑端关闭窗口后重新启动连接。

当前只支持默认显示;未接 HDMI 且没有源显示时,需要显式启用上述无屏模式。

如果窗口完整可见,但桌面内容仍被裁剪,请保持投屏运行,另开终端取得设备原始截图:

hdc -t DEVICE_ID shell snapshot_display -f /data/local/tmp/xpbdp-original.jpeg
hdc -t DEVICE_ID file recv /data/local/tmp/xpbdp-original.jpeg ./xpbdp-original.jpeg

将 DEVICE_ID 替换为实际设备标识,把原始截图与客户端窗口截图对比。如果设备原图也缺少桌面内容,需要检查设备窗口布局和虚拟屏配置;如果原图完整而客户端缺失,再检查服务端处理和客户端显示。日志中的显示尺寸与传输尺寸一致,不足以证明桌面内容完整。单独降低 --max-size 只会缩小传输图像,不能恢复已经裁掉的内容。

帧协议

新服务端与客户端必须配套使用,旧版客户端不兼容。每帧为 36 字节头部,随后是 JPEG。头部格式为 Python struct.Struct("!4sIQIIIII"),整数使用网络字节序:

字段 字节数 含义
magic 4 ASCII OHS1
jpeg_size 4 后续 JPEG 长度
display_id 8 默认显示 ID
source_width、source_height 各 4 当前显示坐标尺寸
image_width、image_height 各 4 JPEG 图像尺寸
rotation 4 OH 显示旋转枚举值

图像保留当前显示方向,客户端不再额外旋转。接收端收齐头部和帧体后才解码;发送端处理短写和断连。

本地检查

QT_QPA_PLATFORM=offscreen python3 -m unittest discover -s tests -v

这些检查覆盖真实本地 socket 的分片 JPEG、断连、Qt 图像解码、坐标映射、窗口事件和 HDC 参数。它们使用模拟输入执行器,不操作板卡,也不能替代板上验收。

原项目和演示材料仍保留在 Git 历史与仓库附件中。上游作者致谢的基础项目为 cleefun/ohscrcpy。

关于
90.0 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号