Files
curios/docs/research/harmony-realtime-stream.md
T
render 3ce918564d feat(harmony): stream screens over HDC without a companion app
Replace per-frame file capture with the unchanged official Hypium agent, bounded JPEG decoding, independent control RPC and scoped session cleanup. Remove the HAP build and account-signing experiment. All 85 automated checks pass; moving-screen performance and integrated phone input remain unverified because the USB device went offline. Keep published 0.3.2 artifacts unchanged.
2026-09-10 16:07:11 +08:00

162 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Harmony Connector 实时视频流调研
> 历史方案记录:本文的 H.264/HAP 实验已停止,实验源码和账号签名流程已移除。当前采用无需用户开发者账号的[官方 Hypium/HDC 路线](harmony-hdc-only-screen.md),状态及验证命令见[持续投屏开发验证](../harmony-realtime-development.md)。下文的早期“无安装”失败仅涉及自编未签名原件,不能推导为必须安装 HAP。
调研日期:2026-09-10。承接 [投屏与控制调研](harmony-screen-control.md),本篇只核查替换逐张截图链路所需的公开 API、进程授权和构建条件。文献研究与本机集成验证分别记录;尚未验证真机 H.264 视频性能。
## 结论与实现顺序
真正的视频流应为 **AVScreenCapture → VideoEncoder 输入 Surface → H.264 输出回调 → 持续 socket → 主机解码**。公开 C API 足以表达这个管线,包含系统录屏授权、帧率控制和编码输出;HDC 只负责连接和转发。`OH_ENCODED_STREAM` 虽然存在于枚举,但当前文档明确尚不支持,不能只修改枚举便取得 H.264。[采集数据类型](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/reference/apis-media-kit/capi-native-avscreen-capture-base-h.md)、[Surface 视频编码](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/media/avcodec/video-encoding.md)
最小验证先尝试无音频、限时停止的普通 shell 原生程序。**没有查到“C API 必须有 UIAbilityContext”的限制;也没有官方文档保证商业手机允许 shell 进程完成录屏授权。** 这必须由实际返回码、系统弹窗和首个可解码帧判定,不能把“未验证”写成“必须安装 HAP”。公开接口不接受 UIAbilityContext;OpenHarmony 媒体服务会自行启动授权窗口。本次集成测试在程序执行阶段已遇到权限拒绝,详见下文,尚未到达 API 授权阶段。[公共 C API](https://github.com/openharmony/multimedia_player_framework/blob/91ee2a20fb294d0d05e8c48d0c0cc96af68f43e6/interfaces/kits/c/native_avscreen_capture.h)、[授权窗口调用](https://github.com/openharmony/multimedia_player_framework/blob/91ee2a20fb294d0d05e8c48d0c0cc96af68f43e6/services/services/screen_capture/server/screen_capture_server.cpp#L2174)
UITest addon 的公开源码扩展仍仅提供连续 JPEG,没有 H.264 入口。可以验证其长连接 JPEG 是否明显改善当前每帧启动截图命令和下载文件的开销,但不得称为 H.264 视频通道。[扩展 ABI](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/extension_c_api.h)、[采集分派](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/extension_executor.cpp#L305)
## 本地 SDK 核查
本机下载的官方 `commandline-tools-mac-arm64-26.0.0.821.zip` 包含以下公共文件,研究直接读取 ZIP 中的头文件核查声明,不依赖论坛示例:
```text
command-line-tools/sdk/default/openharmony/native/sysroot/usr/include/
multimedia/player_framework/native_avscreen_capture.h
multimedia/player_framework/native_avscreen_capture_base.h
multimedia/player_framework/native_avcodec_videoencoder.h
multimedia/player_framework/native_avcodec_base.h
multimedia/player_framework/native_avformat.h
multimedia/player_framework/native_avbuffer.h
multimedia/player_framework/native_avbuffer_info.h
```
头文件及 aarch64 stub 库存在,只证明可以编译和链接,不证明目标手机提供全部 API 或允许该进程采集。应优先使用满足管线的较早公开 API,通过实际返回值检查能力;不能仅因 SDK 是 26.0.0 就要求手机同版本。
| 能力 | 公共接口 | 起始 API |
| --- | --- | --- |
| 创建、初始化、停止、释放 | `OH_AVScreenCapture_Create/Init/StopScreenCapture/Release` | 10 |
| 状态、错误事件 | `OH_AVScreenCapture_SetStateCallback/SetErrorCallback` | 12 |
| 向编码器 Surface 采集 | `OH_AVScreenCapture_StartScreenCaptureWithSurface` | 12 |
| 限制采集帧率 | `OH_AVScreenCapture_SetMaxVideoFrameRate`,启动后调用,最高 60 | 14 |
| 编码器输出 buffer 回调 | `OH_VideoEncoder_RegisterCallback`、`OH_AVCodecCallback` | 11 |
| 编码器输入 Surface | `OH_VideoEncoder_GetSurface` | 9 |
| 编码 B 帧开关 | `OH_MD_KEY_VIDEO_ENCODER_ENABLE_B_FRAME`,默认关闭 | 20 |
| 手机、平板可选屏幕 Picker | `OH_AVScreenCapture_StrategyForPickerPopUp` | 23 |
以上声明可对照 [采集 API](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/reference/apis-media-kit/capi-native-avscreen-capture-h.md)、[视频编码器 API](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/reference/apis-avcodec-kit/capi-native-avcodec-videoencoder-h.md)、[华为 Picker 条件](https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/using-avscreencapture-for-file-with-window)。普通录屏授权弹窗与 API 23 的屏幕/窗口选择器是两项能力;不能以设备没有后者判断无法授权录屏。
## 授权:先验证 shell,不绕过系统授权
本地 SDK 的 `SetStateCallback` 声明要求在启动前注册;说明录屏开始前由系统请求用户同意,实际启动成功回调 `OH_SCREEN_CAPTURE_STATE_STARTED`,拒绝回调 `OH_SCREEN_CAPTURE_STATE_CANCELED`。即便 `StartScreenCaptureWithSurface` 返回成功,也只能表示启动请求被接受,必须继续等待状态和编码数据。[状态回调 API](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/reference/apis-media-kit/capi-native-avscreen-capture-h.md#oh_avscreencapture_setstatecallback)
OpenHarmony 当前源码调用链提供了可检验的依据:
1. `ScreenCaptureImpl::StartScreenCaptureWithSurface` 在 `ORIGINAL_STREAM` 模式内部启用隐私授权,再进入服务端。无需调用内部的 `SetPrivacyAuthorityEnabled`,它不是本地公共 C 头文件中的接口。[客户端实现](https://github.com/openharmony/multimedia_player_framework/blob/91ee2a20fb294d0d05e8c48d0c0cc96af68f43e6/frameworks/native/screen_capture/screen_capture_impl.cpp#L397)
2. 服务端从 IPC 取得真实 UID、PID、token,并根据 UID 查询应用包名。普通 UID 进入用户授权逻辑;启用授权时请求系统窗口,未启用授权时才检查 `CAPTURE_SCREEN`。不是要求应用预先拥有免弹窗权限。[调用者与权限](https://github.com/openharmony/multimedia_player_framework/blob/91ee2a20fb294d0d05e8c48d0c0cc96af68f43e6/services/services/screen_capture/server/screen_capture_server.cpp#L1288)
3. 授权请求带 `sessionId`、`callerUid`、`appLabel`,由媒体服务连接系统扩展组件,调用传入的应用 token 为 `nullptr`。已核查的链路未见必须是 HAP token 的检查。[窗口参数](https://github.com/openharmony/multimedia_player_framework/blob/91ee2a20fb294d0d05e8c48d0c0cc96af68f43e6/services/services/screen_capture/server/screen_capture_server.cpp#L2058)
因此 shell 程序在 API 形态上可尝试,**商业固件能否为 shell UID 建立授权弹窗、通知和实际采集仍未知**。最小验证应记录 create/init/configure/getSurface/start 的逐步返回、状态回调、编码输出数量,以及停止结果;设置有限等待与退出。遇到权限拒绝即停止,不使用 root、系统签名、权限白名单或调用系统内部免授权接口补救。
若 shell 路径失败,可把同一 C++ 管线放入普通 HAP 的 native 模块,从手机页面按钮发起。这样调用者具有正常包名和应用生命周期,符合官方示例的应用使用方式,但仍需真机验收,不能从源码推导所有商业设备必然成功。[华为取流实践](https://developer.huawei.com/consumer/cn/doc/doccenter-dev-faq/faqs-media-46)
## 最小采集与编码契约
以下是本项目组装的流程,不是已运行的完整示例。每个返回值均需检查;回调中的停止和释放应派发到管理线程,避免同步销毁回调所属对象。
```text
encoder = OH_VideoEncoder_CreateByMime(OH_AVCODEC_MIMETYPE_VIDEO_AVC)
OH_VideoEncoder_RegisterCallback(encoder, callbacks, session)
format = OH_AVFormat_Create()
设置目标宽高、RGBA surface 输入、帧率、CBR、码率、GOP
OH_VideoEncoder_Configure(encoder, format)
OH_VideoEncoder_GetSurface(encoder, &window)
OH_VideoEncoder_Prepare(encoder)
OH_VideoEncoder_Start(encoder)
capture = OH_AVScreenCapture_Create()
OH_AVScreenCapture_SetStateCallback(capture, onState, session)
OH_AVScreenCapture_SetErrorCallback(capture, onError, session)
config = 全部初始化为零
config.captureMode = OH_CAPTURE_HOME_SCREEN
config.dataType = OH_ORIGINAL_STREAM
config.videoInfo.videoCapInfo.videoSource = OH_VIDEO_SOURCE_SURFACE_RGBA
config.videoInfo.videoCapInfo.videoFrameWidth/Height = 目标宽高
OH_AVScreenCapture_SetMicrophoneEnabled(capture, false)
OH_AVScreenCapture_Init(capture, config)
OH_AVScreenCapture_StartScreenCaptureWithSurface(capture, window)
等待 onState(STARTED),再 OH_AVScreenCapture_SetMaxVideoFrameRate(capture, 30)
```
Surface 模式无需 `OnNeedInputBuffer` 填充像素,无需每帧 PNG 文件和截图下载。Surface 来自编码器并必须在 `Configure` 之后、`Prepare` 之前获取;窗口生命周期由应用管理。音频采集采样率及通道数同时为零表示忽略音频,首版明确关闭麦克风,不索取麦克风权限。[Surface 编码流程](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/media/avcodec/video-encoding.md)、[无音频条件](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/reference/apis-media-kit/capi-avscreencapture-oh-audiocaptureinfo.md)
输出回调为 `onNewOutputBuffer(OH_AVCodec*, uint32_t index, OH_AVBuffer*, void*)`。通过 `OH_AVBuffer_GetBufferAttr/GetAddr/GetCapacity` 检查 offset、size、PTS、flags;复制合法范围的数据后尽快 `OH_VideoEncoder_FreeOutputBuffer(encoder,index)`。参数集、同步帧和普通帧按原始顺序传输,不能随便丢弃依赖帧;遇到积压丢弃到下一关键帧并请求 IDR。`OH_AVCodecBufferAttr.pts` 是微秒,不能与网络到达时间混为端到端时延。[编码数据读取](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/media/avcodec/video-encoding.md)、[buffer 属性](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/reference/apis-avcodec-kit/capi-core-oh-avcodecbufferattr.md)
推荐链接公共库 `libnative_avscreen_capture.so`、`libnative_media_venc.so`、`libnative_media_codecbase.so`、`libnative_media_core.so`、`libnative_window.so`。由实际使用符号补充 native buffer 依赖;不复制设备私有库或 DevEco 私有 agent。[采集依赖](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/media/media/avscreencapture-c-basic-process.md)、[编码依赖](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/media/avcodec/video-encoding-configuration-typical-scenarios.md)
停止顺序应先停止采集输入,通知编码器 EOS 并有界等待,释放采集和编码器、销毁 NativeWindow,再关闭 socket 和本会话转发;拒绝、错误、断线也走相同可重入清理路径。不同旋转尺寸先更新主机几何信息,暂停旧坐标输入,再重建需要变更尺寸的编码器。
## 低延迟配置与实际指标
官方把短距投屏列为低时延编码场景,推荐 CBR、根据目标分辨率/帧率设码率,并支持运行期通过 `OH_MD_KEY_REQUEST_I_FRAME` 请求 IDR。这里建议先从最长边 1280、30 fps、H.264、CBR 4 Mbps、1 秒 GOP 开始测量;这些数值是原型起点,不是官方对该手机的性能保证。[典型场景编码配置](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/media/avcodec/video-encoding-configuration-typical-scenarios.md)
`OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY` 名字易产生误解:公共 SDK 将其定义为**视频解码**配置,本研究未确认它对编码器有效。编码 B 帧默认关闭,应保留此行为以避免显示顺序重排。API 26 新增的 CBRHQ 应先通过编码能力查询,不能直接强制较旧设备使用。[编解码参数声明](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/reference/apis-avcodec-kit/capi-native-avcodec-base-h.md)
工程上应将采集、编码回调和 socket 发送分开:发送线程使用有界队列、超时与取消;不能在编码回调等待网络。主机也需要持续解码并只渲染最新可用画面,避免 30 fps 视频经慢速 JSON/base64 轮询再次积压。指标分别记录编码帧率、收到帧率、呈现帧率、码率、排队时长、首帧时间;没有时钟同步或可视运动实验时,不把采集耗时称为端到端延迟。
## UITest 扩展:可优化的 JPEG 路线
当前锁定的 OpenHarmony UITest 提交与上一轮一致:`b04e30c40cf266c9abfbd52933e43a0456eb99a2`。
- `startCapture("copyScreen", callback, options)` 读取 `scale`、`displayId`,内部将 screenshot PixelMap 转为 JPEG。`scale` 对外检查严格 `0 < scale < 1`。
- `screen_copy.cpp` 使用独立截图和编码线程,以最近帧替换前帧,只在图像变化时回调。源码中的 50 ms sleep 用于熄屏轮询,**不是运行态固定 20 fps 上限**。
- 回调参数是临时 `Text`,执行完立即 `free(data)`,异步发送必须先复制;不能缓存裸指针。
- `LowLevelFunctions` 没有获取原始 PixelMap、编码器 Surface 或 H.264 的函数。额外直接调用 AVScreenCapture 属于独立的公共 API 路线,不是 UITest 已提供 H.264。
[JPEG 实现](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/screen_copy.cpp)、[回调生命周期](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/extension_executor.cpp#L305)、[ABI](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/extension_c_api.h)
## 若需伴随 HAP:最小应用职责
ArkTS 仅负责正常应用入口、开始/停止共享、授权状态和后台任务;C++ 负责采集、编码及 loopback TCP。录屏授权不赋予任意输入注入权,控制继续复用已授权 HDC 的 UITest。若使用 socket,应用声明普通 `ohos.permission.INTERNET`;仅监听 loopback,并要求本会话随机 token。不要为了投屏申请系统的免授权采集或输入注入权限。
持续录屏退后台需要合法长时任务,否则应用可能挂起。官方任务类型表将 `AUDIO_RECORDING`/`audioRecording` 对应录音、录屏退后台,声明 `ohos.permission.KEEP_BACKGROUND_RUNNING` 并在共享期间保持可见通知,停止时结束任务;`taskKeeping` 在手机上有额外受限权限条件,不适合作为默认捷径。[长时任务规范](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/task-management/continuous-task.md)、[华为取流与后台说明](https://developer.huawei.com/consumer/cn/doc/doccenter-dev-faq/faqs-media-46)
真机 HAP 安装必须签名。调试 profile 绑定包名、证书和允许调试的设备;DevEco Studio 自动签名或 AGC 手动签名均有官方流程。下载 Command Line Tools 和网页登录本身没有生成可安装的签名 HAP;不得用系统样例证书假装适用于商业手机。需要 HAP 时先完成可构建源代码,再配置有效调试签名并进行真机授权测试。[自动签名](https://developer.huawei.com/consumer/cn/doc/HarmonyOS-Guides/ide-signing-auto)、[手动签名](https://developer.huawei.com/consumer/cn/doc/doccenter-deveco-studio/ide-signing-manual)
### 官方 CLI 自动签名路径
华为官网推荐 `@deveco/deveco-cli@stable`,1.3.0 版本新增自动调试签名;本次查询 npm stable 标签为 `1.3.0-stable`。可以在隔离的工具目录安装,使用 Node 22 及以上,配置 `DEVECO_CLI_CLT_PATH` 为完整解压的 Command Line Tools 根目录。只解压 HDC 与 native SDK 不构成该 CLI 所需完整工具链。[官网工具入口](https://developer.huawei.com/consumer/cn/deveco-studio)、[1.3.0 版本说明](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-deveco-cli-releasenote)、[官方 npm 包](https://www.npmjs.com/package/@deveco/deveco-cli)
官方包 README 给出的流程如下;本轮已尝试签名,结果见集成记录:
```text
devecocli auth status
devecocli auth login # 未登录时打开浏览器授权
devecocli create --app-name HarmonyConnector --bundle-name <本项目包名> --project-path <工程目录>
# 在完成代码的工程目录:
devecocli signature generate --product default
devecocli build --modules entry --build-mode debug
```
`signature generate` 生成 p12、csr、p7b、cer 并写工程 `build-profile.json5`。默认使用用户自身团队;需要团队时指定已查询的 team-id,不虚构;已有签名无需加 `--force`。CLI 登录目前不支持海外账户。它的脚手架只提供 Empty Ability,native 模块仍需项目自行配置。[官方 CLI 文档](https://www.npmjs.com/package/@deveco/deveco-cli)
## 本次集成验证的已知边界
同一任务的真机执行方报告:原链路连续 3 帧耗时约 696、803、802 ms,约为 1.3 fps;此为采集周期,不是端到端时延。使用公共 NDK 编译的 `aarch64-linux-ohos` 采集原型被传到本会话独有的 `/data/local/tmp/` 路径并设置执行权限,直接启动返回 `Permission denied`。HDC 自身退出状态为 0,不代表设备端命令成功。程序未执行任何采集 API,未显示授权弹窗,因此本次证据只定位到执行权限边界,不能证明 AVScreenCapture 被拒绝。
UITest addon 未进入 `OnInit`。随后读取设备日志确认:MUSL-LDSO 报 `Xpm check failed`、`errno for mmap is:13`,UiTestKit_Addon 的 `dlopen` 返回 `Permission denied`。这将本次失败定位到临时未签名模块的加载校验,不能解释为 ABI 不兼容;没有尝试关闭或绕过 XPM。临时程序、模块和手机上的本会话文件均已清理。
华为公开 LLDB 调试矩阵将 user 镜像、SELinux 开启场景的支持范围列为签名 debug HAP;并区分其与 root 镜像上的普通可执行文件调试。它与上述限制相符,但不能仅凭该文档判定具体拒绝来自 SELinux、代码签名还是其他策略。当时选择了普通应用签名实验;该路线随后已停止,当前改用官方分发且无需用户签名的 Hypium 代理。[华为 Native 调试条件](https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/debug-lldb)
## 最小验收
1. 普通 shell 程序是否能创建采集和编码器、显示系统授权;分别验证同意、拒绝和超时。
2. 取得 H.264 参数集和关键帧,并在 Mac 成功解码连续变化画面。
3. 验证屏幕旋转、锁屏、隐私画面、断线和用户主动停止,保留系统遮挡行为。
4. 持续运行时记录呈现帧率与排队增长;同时验证输入后画面及时变化。
5. 会话结束不再采集、不再注入输入;清理本会话的临时程序/文件和端口转发。
公开源码和 SDK 只能支撑上述实现契约,不能替代 Pura 70 Ultra 的实际授权、解码与延迟验收。
## 伴随应用构建进展
集成方已创建普通手机应用 `ink.render.trove.harmonyconnector`,实现系统授权的 Surface 采集、H.264 编码、带会话校验的 loopback TCP 和停止收尾。官方 CLI 已成功构建 ArkTS 与 arm64-v8a native 模块并生成未签名 HAP。独立 Mac 接收器的 8 项测试通过,其中生成的 20 帧视频经过真实 H.264 解码全部返回。
最初签名预检被账号认证状态阻塞;用户认证并刷新官方授权后,曾成功生成正常调试签名、构建并安装 HAP,收到首个 H.264 帧。接收器在第一帧统计时发生除零错误,故没有取得持续帧率或端到端延迟结果。随后按用户要求停止 HAP 路线,实验源码已从主分支移除;历史实现保留于提交 `ca382e6`。当前无需账号的实现和验证状态见[开发验证说明](../harmony-realtime-development.md)。