欢迎加入开源鸿蒙PC社区

欢迎加入开源鸿蒙PC社区:https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
如有项目源码,可上传至 AtomGit 仓库,并在博文内附上仓库链接。

鸿蒙PC桌面端适配 SDL2 2.32.10:把 OHAudio 和 NativeWindow 真正接到测试里

适配目标

SDL2 很容易给人一种“只要 SDL_Init 返回 0 就适配完成”的错觉。对 HarmonyOS PC 桌面端来说,版本输出只能证明头文件和库能被找到,不能证明音频设备、窗口、EGL 上下文或渲染器真的工作。SDL2 2.32.10 的本次适配围绕两个明确目标展开:使用 OHAudio 输出音频,使用 NativeWindow 加 EGL/GLES2 创建并呈现窗口,同时保留 dummy/offscreen 后端供上游可移植测试使用。

源码来自 SDL 官方 2.32.10 release,归档 SHA-256 写入 Conan 配方。适配配方、16 个边界补丁和消费者测试位于 AtomGit 仓库 中。文章中的代码托管品牌统一写作 AtomGit;实际使用时应先核对配方版本和当前提交,不要把 2.30.x 的旧配置当成 2.32.10 的能力证明。

CMake 配置和平台后端

构建时打开 SDL_OHAUDIO=ON、SDL_NATIVEWINDOW=ON、SDL_OPENGLES=ON,并启用 SDL 自带测试。OHAudio 回调不能等待生产者数据,否则设备音频线程会被锁住;启动操作放在后端互斥锁之外,停止和释放只有在成功 drain 活跃回调后才释放存储。这个生命周期约束比“能链接到 ohaudio”更重要。

NativeWindow 后端要求应用在同一进程中先得到 ArkUI surface,再把 surface ID、宽度和高度传给 SDL。普通的 SDL_CreateWindow 仍然是入口,随后通过 opengles2 renderer 上传一张四颜色纹理、读回像素并调用 SDL_RenderPresent。后端只负责原生输出,不声称已经提供键盘、鼠标或触摸事件集成;输入能力应由上层应用单独验证。

SDL 的通用 Unix EGL loader 默认查找带版本号的桌面库名,例如 libGLESv2.so.2。API 20 的 HarmonyOS PC provider 暴露的是无版本 SONAME libGLESv2.so 和 libEGL.so,因此 NativeWindow 路径选择无版本加载契约。GLES 函数先从当前 EGL context 使用 eglGetProcAddress 解析,再回退到通用 loader,避免在版本不透明时误选 ABI 同名桩函数。

一个可直接运行的核心消费者

下面的 C 程序不创建窗口和音频设备,适合先在鸿蒙PC桌面端确认 SDL2 包的版本、计时器、CPU 查询和内存接口。它是“基础 ABI smoke”,不能替代后面的原生音频和视频测试。

#include <SDL2/SDL.h>
#include <stdio.h>

int main(void) {
    SDL_version compiled;
    SDL_version linked;
    unsigned char *memory;
    SDL_VERSION(&compiled);
    SDL_GetVersion(&linked);

    if (compiled.major != 2 || compiled.minor != 32 || compiled.patch != 10)
        return 1;
    if (linked.major != compiled.major || linked.minor != compiled.minor ||
        linked.patch != compiled.patch)
        return 2;
    if (SDL_Init(0) != 0) {
        fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
        return 3;
    }

    Uint64 before = SDL_GetPerformanceCounter();
    SDL_Delay(2);
    Uint64 after = SDL_GetPerformanceCounter();
    if (after < before || SDL_GetCPUCount() <= 0) {
        SDL_Quit();
        return 4;
    }

    memory = (unsigned char *)SDL_malloc(32);
    if (memory == NULL) {
        SDL_Quit();
        return 5;
    }
    SDL_memset(memory, 0x5a, 32);
    if (memory[0] != 0x5a || memory[31] != 0x5a) {
        SDL_free(memory);
        SDL_Quit();
        return 6;
    }
    SDL_free(memory);

    SDL_Quit();
    puts("SDL2_CORE_PASS version=2.32.10");
    return 0;
}

将程序保存为 test_core.c,用下面的 CMake 文件通过包导出的目标链接:

cmake_minimum_required(VERSION 3.15)
project(sdl2_core_consumer LANGUAGES C)

find_package(SDL2 CONFIG REQUIRED)
add_executable(sdl2_core test_core.c)
target_link_libraries(sdl2_core PRIVATE
    SDL2::SDL2
    SDL2::SDL2main
    SDL2::SDL2test
)

从空目录开始时,可用下面的最小 conanfile.py 声明同一版本依赖:

from conan import ConanFile


class SDL2Consumer(ConanFile):
    settings = "os", "arch", "compiler", "build_type"
    generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv"

    def requirements(self):
        self.requires("sdl2/2.32.10")

在该目录执行以下命令。确认生成的 build/conan_toolchain.cmake 存在后再配置 CMake;缺失的依赖应先按版本补齐,不能用本地源码回退掩盖闭包问题:

OHOS_PROFILE=ohos-aarch64  # replace with an existing OHOS/AArch64 profile
conan install . -pr:h="$OHOS_PROFILE" -pr:b=default --output-folder=build --build=never
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
cmake --build build --parallel 2

在有 ArkUI surface 的应用进程中,再设置 SDL_VIDEODRIVER=nativewindow 及 SDL_HINT_NATIVEWINDOW_SURFACE_ID、SDL_HINT_NATIVEWINDOW_WIDTH、SDL_HINT_NATIVEWINDOW_HEIGHT,调用 SDL_Init(SDL_INIT_VIDEO)、SDL_CreateWindow 和 SDL_CreateRenderer。surface ID 必须来自当前应用,而不是随便填一个整数;没有 surface 时应把结果记录为前置能力缺失,而不是把 dummy renderer 当成原生窗口通过。

测试分母不能拼接

SDL2 上游清单的逻辑分母是 315。归档的目标事务执行了 4 个原生消费者:核心 API、无效 surface 负例、OHAudio 回调/帧进度和 NativeWindow/opengles2 纹理读回,结果为 4/4 PASS。该事务的 upstream 字段明确是 0/0 NOT_RUN;另一个不可变 predecessor 才提供 315/315 的上游证明。两者不能相加、改名或写成当前一次运行的 319/319。

测试日志还会记录 core_pass、invalid_pass、audio_pass 和 video_pass 标记。视频快照字段为 NOT_REQUIRED,它只是观察策略,不是四个消费者的隐藏分母。读报告时应同时看运行 ID、版本、后端名称和清理状态:目标进程清零、任务根释放成功,才能结束一次设备事务。

构建与运行建议

使用 Conan 生成的 CMake toolchain 编译时,先确认 OHAudio、NativeWindow、EGL 和 GLESv2 provider 的完整闭包,再进行 package test。静态元数据应传播 ohaudio、native_window、EGL、GLESv2、m 和 pthread;共享包的私有 DT_NEEDED 也要通过目标设备的 loader 验证。Windows 交叉编译和 API 20 unsigned HAP 只能证明构建接线,不能代替真实设备上的音频回调或呈现结果。

新手适配教程:环境、过程、结论与 FAQ

环境:先把多媒体闭包准备齐

构建机需要 Conan 2、CMake、Ninja、Python 和 HarmonyOS SDK,host profile 明确设置 os=OHOS、arch=armv8、Clang 和 sysroot。目标应用还必须能提供 ArkUI surface,并能访问 OHAudio、NativeWindow、EGL、GLESv2 provider。SDL2 的高难点在于这些接口分别属于不同子系统:库能链接不代表音频回调会产生帧,也不代表渲染器拿到了真实 surface。开始前应核对依赖已经发布,避免 --build=missing 把问题藏在另一套本地编译结果里。

过程:从低风险 smoke 逐级走到原生后端

  1. 先运行核心消费者,确认版本、计时器、CPU 查询和内存 API;这一步只验证 ABI,不宣称窗口或音频可用。
  2. 再运行无效 surface 负例,确认错误输入能被拒绝且进程不崩溃。
  3. 启动 OHAudio 消费者,核对回调次数、帧计数、非零采样和关闭阶段;不能用等待或固定字符串伪造“有声音”。
  4. 在同一应用进程取得 ArkUI surface,把真实 ID、宽高传给 NativeWindow 后端,检查 EGL context、纹理上传、present 和像素读回。
  5. 汇总四个消费者、上游清单和设备日志,再采集保留鸿蒙PC任务栏的全屏截图。每一项都要绑定版本、后端名称和运行 ID。

结论:用分层结果证明高难适配

SDL2_CORE_PASS 只证明基础 ABI;SDL2_NATIVE_AUDIO_PASS 与 SDL2_NATIVE_VIDEO_PASS 才分别证明两个平台后端真的被调用。4/4 是消费者分母,315/315 是另一套上游清单,不能相加为 319/319。高难性来自“跨音频、窗口、EGL/GLES 和 ArkUI surface 的同进程协作”,以及必须对真实回调和呈现结果做语义验证。没有 surface 或只有 unsigned HAP 时,只能报告前置条件不足,不能把 dummy 后端写成真机通过。

FAQ

Q:SDL_Init(0) 返回 0,为什么仍不能创建窗口? A:它没有初始化视频和音频子系统,属于基础 smoke。Q:surface ID 能否手工填整数? A:不能,必须来自当前 ArkUI 窗口;错误 ID 只能用于负例。Q:驱动名称显示 ohaudio 但没有帧怎么办? A:检查回调生命周期、权限、流状态和关闭顺序,不能只看驱动字符串。Q:为什么截图必须保留桌面? A:桌面元素证明运行环境是鸿蒙PC,终态标记证明对应消费者确实完成,两者缺一都不足以支撑高难适配结论。

运行截图

以下图片来自同一台 HUAWEI MateBook Pro(HAD-W32)的 HarmonyOS 6.1.0.117 图形会话。先单独运行核心 ABI 消费者,17 条断言通过且返回码为 0:

SDL2 2.32.10 核心 ABI 消费者在鸿蒙PC通过 17 项断言

再运行 OHAudio 原生后端。图中不仅有 12 条断言,还记录 17 次回调、16320 帧、32640 个非零采样以及 driver=ohaudio,避免把驱动名称本身冒充音频工作证明。

SDL2 2.32.10 OHAudio 原生后端在鸿蒙PC完成回调与帧验证

NativeWindow 图片记录 14 个无效 surface 元组被正确拒绝,并在同一画面明确写出有效呈现仍需要当前 ArkUI 窗口提供的 surface tuple:

SDL2 2.32.10 NativeWindow 在鸿蒙PC完成无效 surface 边界验证

最后一张是三个消费者的同屏汇总,画面保留鸿蒙PC设置页、HiShell 窗口和任务栏。

SDL2 2.32.10 三项消费者在鸿蒙PC同屏运行汇总

这组截图把核心 ABI、真实音频回调和窗口参数负例分开。因此,这里没有把 14 个参数拒绝负例说成真实画面呈现,也没有用 --version 冒充音视频后端验证;这正是多媒体库结果必须分层陈述的原因。

结语

SDL2 2.32.10 的鸿蒙PC桌面端适配重点是把“后端存在”推进到“后端被真实调用”:OHAudio 要看到回调和帧进度,NativeWindow 要看到同进程 surface、EGL context、纹理读回和 present。基础 smoke、上游 315 项证明和当前 4 个原生消费者必须分层记录。只有这样,后续接入游戏或桌面应用时,才不会因为一个成功的版本命令而误判整条多媒体链路。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐