vdi-cloud/docs/freerdp3-embedding-notes.md
宋一鸣 24529b80b0 功能:接入 FreeRDP 3 内嵌客户端与远程桌面
变更详情:feat(kiosk-shell): FreeRDP 3 内嵌客户端跑通,登录页可进入远程桌面

- 按方案 3.2/3.3 节以 libfreerdp3 API 内嵌,不拉起外部进程
- gdi_init 移到 PostConnect(提前调用会段错误)
- 去掉 ContextSize 扩展 rdpContext,改用 freerdp* 注册表 + gfx->custom
- NLA 认证传空字符串而非 nullptr,修复 SEC_E_NO_CREDENTIALS
- 补充 FreeRDP3 内嵌实现笔记文档
2026-10-23 18:57:05 +08:00

3.4 KiB
Raw Blame History

FreeRDP 3 内嵌客户端实现笔记(Ubuntu 24.04 / freerdp3-dev 3.32.1)

对应《VDI 云桌面软件开发方案》3.2 / 3.3 节:以 libfreerdp3 API 内嵌(非拉起外部进程)。 记录时间:2026-10-23,实测于 RK3528 盒子(Armbian / Ubuntu Noble / aarch64)

1. API 结构(与 FreeRDP 2.x 差异很大)

用途 FreeRDP 3 写法
创建实例 freerdp* instance = freerdp_new();
建立上下文 freerdp_context_new_ex(instance, settings)
上下文 instance->context(rdpContext*,公开结构体)
事件回调 instance->PostConnect / instance->PostDisconnect / instance->AuthenticateEx
更新回调 instance->context->update->BitmapUpdate / ->EndPaint
GDI gdi_init(instance, PIXEL_FORMAT_BGRX32)
取帧 context->gdi->primary_buffer + context->gdi->stride

设置项键名(与 2.x 不同): FreeRDP_ServerHostname / FreeRDP_Username / FreeRDP_Password / FreeRDP_Domain / FreeRDP_DesktopWidth / FreeRDP_DesktopHeight / FreeRDP_ColorDepth / FreeRDP_Fullscreen / FreeRDP_IgnoreCertificate / FreeRDP_GfxProgressive / FreeRDP_GfxH264 / FreeRDP_GfxAVC444 …

2. 三个必须踩过才知道的坑

坑一:gdi_init 必须在 PostConnect 里调用

在 freerdp_context_new_ex() 之后立刻调用 gdi_init() 会 SIGSEGV (gdi_init_ex 段错误)。官方 x11 客户端(client/X11/xf_client.c 的 xf_post_connect) 把 gdi_init 放在 PostConnect 回调内,因为 GDI 依赖连接协商后的桌面尺寸与颜色格式。

坑二:不能用 instance->ContextSize 扩展 rdpContext

常见做法是把自定义指针塞进扩展的 rdpContext,但 gdi_init_ex() 会按 ContextSize 重新分配 context 缓冲区,扩展字段随即失效 → 段错误。 改用静态注册表按 freerdp* 记录会话对象;GFX 通道回调则用官方的 RdpgfxClientContext.custom 字段。

坑三:NLA 认证必须传空字符串而非 nullptr

Windows 端启用 NLA(CredSSP)时,认证回调里把密码置为 nullptr 会导致 SEC_E_NO_CREDENTIALS [0x8009030e]。必须传 strdup("")。 认证回调签名: BOOL (*pAuthenticateEx)(freerdp*, char** username, char** password, char** domain, rdp_auth_reason)

3. /gfx 语法(命令行与设置项的对应)

FreeRDP 3.32.1 的 /gfx 不接受单个管道名,必须是 | 分隔的能力组合:

/gfx:progressive|RFX|AVC420|AVC444     ← 可解析
/gfx:AVC420                              ← parsing failed [-1000]
/gfx:AVC444                              ← parsing failed [-1000]

API 侧对应 FreeRDP_GfxProgressive / FreeRDP_GfxH264 / FreeRDP_GfxAVC444 等布尔项。

4. 像素格式

PIXEL_FORMAT_BGRX32 的内存布局是 B,G,R,X 四字节/像素。 QImage 没有对应格式,输出前需手动做 BGR→RGB 转换。 注意 PIXEL_FORMAT_* 是计算宏 FREERDP_PIXEL_FORMAT(...),不能硬编码数值。

5. 后续演进(对应 freerdp-rk 分支)

当前实现是 CPU 侧 GDI 缓冲 → Qt 绘制。开发方案 3.3 节要求改为:

FreeRDP3 解复用(gfx 通道) → GStreamer h264parse → mppvideodec(VPU硬解, zero-copy DMABuf)
→ waylandsink(DRM plane)

盒子已具备 /dev/mpp_service(VPU)与 /dev/rga,但缺 mppvideodec GStreamer 插件 (Ubuntu 官方源没有,需 Rockchip BSP / Armbian 额外源或自研)。