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.
162 lines
20 KiB
Markdown
162 lines
20 KiB
Markdown
# 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)。
|