记
开发日志
← 返回日志

把 mpv 装进身体里:NovaPlayer 的 libmpv 内置长征

NovaPlayer
文章摘要

跟随窗模式毛病不断,决定把播放内核编进应用。三版分诊包、真机全黑、最后出画的那一格,病灶不在解码,而在窗口是谁管的。

约 3 分钟 · 1037 字 · 5 节 · 标签 NovaPlayer
  1. 起点:跟随窗的账算不下去了
  2. 真机第一课:全绿,但是全黑
  3. 分诊:把两个变量拆开
  4. 决定性的一格:原生窗口托管
  5. 定版

起点:跟随窗的账算不下去了

NovaPlayer 原本的播放方式是「跟随窗」:一个独立的 mpv 进程开个窗口,实时贴合主窗口的播放区。能用,但毛病是结构性的:点击被视频窗吞掉、窗口几何一对不齐就露馅、全屏要两边商量。学同类产品的做法——把 libmpv 编进应用、画面渲染进自有视图——成了迟早要走的一步。

先做独立实验台验证:Electron 进程内经 koffi 直调 libmpv 的 C API。在沙箱里同链路一次出画,模块自测 15/15 全过(seek、倍速、音量精确回读,轨道、外挂字幕、截图、结束归因一应俱全)。当时以为稳了。

真机第一课:全绿,但是全黑

实验包到用户真机(Intel 核显、125% DPI)上,三个渲染模式全黑:有声音、有进度、丢帧 0,播放管线每一项指标都正常,唯独没有画面。对照事实是:同一台机器上,独立运行的 mpv.exe 能正常出画。硬解、软解、渲染后端逐个换掉,黑依旧。

这说明病灶不在解码链路,而在「画面最后停在哪块窗口表面上」。

分诊:把两个变量拆开

第二版实验包把问题拆成正交的两维:横轴是渲染模式(gpu-next / gpu / Vulkan / OpenGL),纵轴是窗口安排(子窗嵌入 / 独立顶层窗 / 关掉 flip 呈现)。逐格点测、逐格留日志。顺路还抓出实验台自己的两个 bug:koffi 的类型定义在切换模式时重复注册会直接崩;Vulkan 后端起不来是因为这版构建里上下文名字叫 winvk,不叫 vulkan——选项写错了一个词,整格就从没真正测过。

决定性的一格:原生窗口托管

第三版只测三格,其中 E 格是新思路:不用 Electron 的窗口装画面,改由主进程自己建一个原生 Win32 窗口,把窗口句柄直接喂给 libmpv。

出画了。 测试彩条清晰、25fps、丢帧 0/0。

病灶至此定案:不是解码、不是驱动、不是渲染后端——是 Chromium 管理的窗口表面承载不了这条渲染路径。实验台其余所有组合皆黑,唯独绕开它就通。

定版

生产架构就此定为:Electron 外框 + 原生视频视图 + 透明覆盖层 UI。起播时「先黑一会儿再出画」的小毛病,用「首帧到达才亮出窗口」收尾。libmpv 的 DLL 本体 121MB,实验包 161,077,945 B——体积是这条路线明码标价的代价。

1.12 正式版按这套架构装配。但长征结束不等于太平——正式版的贴合问题,是下一篇的事。

本篇目录