本文主要介绍 Octans Windows 客户端为何不能直接复用服务端 full FFmpeg,而要单独维护一条受控 LGPL libmpv 播放 runtime:许可证边界、动态链接与 source offer / SBOM 口径、本地播放配置,以及客户端能力如何上报给服务端做 DirectPlay / HLS 规划。讨论的是可 supersede 的工程取舍,不是法律意见,也不是已全量上线的发布承诺。
媒体库产品里,「服务端转码工具链」和「闭源桌面客户端内嵌播放器」常被混成同一句话:反正都是 FFmpeg / mpv 生态。一旦客户端要闭源分发、本地 DirectPlay、硬件解码和 HDR tone mapping,这两条线就必须拆开。下面以 Octans Windows 客户端规划为主线,把分工、合规与能力上报写成可公开复用的工程口径。
问题:同一产品,两类 runtime
服务端播放子系统面对的是:
媒体事实扫描
→ DirectPlay / DirectStream / Transcode 规划
→ HLS 切片、字幕抽取 / 烧录
→ VAAPI / OpenCL / 其他 Linux 硬解与 tone mapping
→ capability helper 给 Planner 的运行时事实
这条链需要编码器、服务端 patch、容器化部署和「能把任意不兼容样本压成浏览器能播的 HLS」。历史路径往往走向 GPL full 构建:可启用 GPL 编码器与大量服务端专用能力。
Windows 闭源客户端面对的是另一类问题:
窗口 / 输入 / 安装更新
→ 加载内嵌播放内核
→ 本地 demux / 解码 / 字幕 / 音频
→ D3D11 等路径上的渲染与 tone mapping
→ 把本机策略与设备事实上报服务端
→ 按 plan 执行 DirectPlay 或降级 HLS
客户端要的是 播放型 runtime,不是把服务端 Docker 里那套 full 二进制拷进安装包。两条线可以共享工程经验(版本钉扎、分层验证、manifest、能力探测),但产物、许可证 flavor 与验收样本必须分开。
为何不能把服务端 full 塞进闭源客户端
闭源商用场景下,可接受与不可接受的边界可以收敛成:
可接受:
LGPL 动态链接
许可证声明 / About 文案
exact source package + patches + configure / Meson 选项
SBOM、checksum、可替换 / relink 所需的分发机制
不可接受:
默认 GPL mpv / libmpv 链进闭源主程序
GPL FFmpeg full 构建链进闭源主程序
libx264 / libx265 等 GPL-only 依赖进入客户端 runtime
--enable-gpl / --enable-nonfree
因此「首选 libmpv」的准确表述必须是:首选受控 LGPL 构建的 libmpv,不是任意社区预编译 mpv-*.dll,也不是服务端 full 产物的改名复用。
服务端 full 线继续承担:
- 服务端 HLS 转码与字幕处理
- Linux / Docker 上的 VAAPI、OpenCL 等路径
- GPL 编码器与服务端 patch 行为
- 服务端 capability 探测与 Planner 输入
客户端 LGPL 线则明确 不包含:
- 以服务端 HLS segment 行为为主目标
- 把 GPL 软件编码器当默认依赖
- 把服务端 full 二进制当客户端内嵌依赖
H.264 / HEVC 播放依赖内建解码器与硬件解码路径,不依赖 libx264 / libx265 编码器。客户端为「能播」去启用服务端那套 GPL 编码器,是典型的边界混淆。
主线形态:动态链接的受控 LGPL libmpv
宿主与后端抽象
Windows 产品侧常见宿主形态是:原生 Host(窗口、输入、安装、日志)+ UI shell(管理面可复用 Web,播放面走 native)+ 播放后端抽象。播放后端建议至少能区分:
| 后端 | 定位 |
|---|---|
受控 LGPL libmpv | 最终主线候选:能力与体验上限高,但必须过 license / 构建 / 样本 gate |
外部 mpv 进程 + IPC | 早期验证或高级 fallback:进程边界更保守,产品完整度(OSD、全屏、状态同步)较弱 |
| libVLC 等 | 合规或工程风险兜底,不宜先于受控 libmpv 当高规格主内核 |
| Media Foundation | 简单格式与系统对照 fallback,覆盖不了高规格 MKV / ASS / PGS / TrueHD 等主场景 |
主程序只通过抽象层下发 play / pause / seek / 选轨 / 预设,不直接散落调用 C API,也不把「完整 mpv 配置生态」暴露成任意脚本入口。
动态链接与搜索路径
推荐分发形态是 动态链接,而不是把 FFmpeg、libplacebo、libass 等全部静态塞进闭源主程序:
Host 可执行文件
libmpv / mpv 共享库
avcodec / avformat / avutil / swscale / swresample 等 FFmpeg 共享库
libplacebo、libass 及字幕相关依赖
licenses / sources / build 证据包
runtime-manifest(版本、hash、许可证 flavor、关键 feature)
启动早期应固定 DLL 搜索路径,避免从系统 PATH 误加载另一套 mpv 或 FFmpeg。运行时要能报告自身 manifest:mpv / FFmpeg / libplacebo / libass 版本、GPU backend 倾向、许可证 flavor。加载失败、license gate 未过、DLL 损坏,应能在产品层区分,而不是只给一个「打不开」。
构建门禁(公开口径)
mpv 默认许可证取向偏 GPL;只有构建时显式关闭 GPL 模式,且最终未链接 GPL-only 依赖,才适合作为 LGPLv2.1-or-later 嵌入路线。-Dgpl=false 与 -Dlibmpv=true 是必要条件,不是充分条件——最终还要审计 FFmpeg 与其他依赖。
FFmpeg 侧公开硬约束:
禁止 --enable-gpl
禁止 --enable-nonfree
禁止把 GPL-only 外部库编进客户端主线
优先 shared 库分发
保留 configure 行、补丁、源码包与构建日志证据
发布前至少用验证构建中的 CLI 做 license 冒烟(正式安装包可不分发这些 CLI,但 CI 应保留日志):
ffmpeg -L → 不得呈现 GPL / nonfree 构建状态
ffmpeg -buildconf → 不得出现 --enable-gpl / --enable-nonfree 等禁项
mpv 侧 → Meson 选项含 LGPL 模式,且依赖 FFmpeg 为 LGPL 构建
第三方预编译 Windows libmpv 包适合 行为对照,不适合作为长期正式分发基线:构建参数、补丁、依赖 DLL 与源码对应关系很难完整纳入产品发布流程。
Source offer、SBOM 与分发证据
LGPL 动态链接不是「只要链上 shared 库就完事」。工程上更稳妥的是把 可审计证据 当成 runtime 发布的一部分,而不是事后补文档:
licenses/ 各组件许可证与 third-party notices
sources/ 对应源码包、依赖源、patches
build/ configure / Meson 选项、manifest、changes、sha256
sbom 机器可读组件清单(如 SPDX)
runtime-manifest 运行时可读的版本与 feature 描述
About / EULA / 安装包说明应能指向:使用了哪些 LGPL 组件、如何获取对应源码与构建配置、用户替换 / relink 相关机制如何满足。本文不展开具体法务文案;闭源商用分发前仍需由合规负责人复核目标市场与 EULA 表述。
维护成本上,建议把 source bundle、SBOM、checksum 和 license package 并进 runtime 发布流水线,避免发版时手工拼证据。客户端安装包可以内嵌 runtime,也可以按需下载 runtime;无论哪种,license notice 与 source offer 策略都要和更新通道一致,不能「二进制热更了、源码包还停在上一个 tag」。
播放能力:Windows baseline,不复制 Linux 服务端
默认路径
Windows 客户端本地 tone mapping 不应照搬服务端「解码 → FFmpeg filter tone map → 再编码 → HLS」模型。客户端模型更接近:
demux / decode
→ gpu-next + libplacebo 渲染管线
→ shader / compute 上的 tone mapping 与色域处理
→ 显示器 / 系统合成器
兼容性与驱动覆盖的起点建议:
vo gpu-next
gpu-api d3d11
hwdec auto-safe / d3d11va(策略可配置)
ao wasapi
字幕 libass + 位图字幕路径
NVIDIA 上 nvdec、Vulkan 等可作为 High Quality 候选,用设备矩阵验证后再进入预设,不宜第一版就与 D3D11 baseline 并列为等价主线。Intel / AMD 在 Windows 客户端同样优先 D3D11VA,而不是把 Linux 服务端 VAAPI / OpenCL 方案硬搬过来。客户端与服务端 不应强行统一硬件 API。
能力承诺要分层
公开与产品文案建议分层,避免把验证项写成已交付:
| 层级 | 示例口径 |
|---|---|
| 正式目标(验证通过后) | HDR10 → SDR 本地 tone mapping;D3D11 + d3d11va baseline;ASS / PGS 本地路径;WASAPI PCM 与受控 passthrough |
| 候选 / 矩阵项 | HLG 本地 tone mapping;DV Profile 5 的 fallback / tone mapping(BL 路线) |
| 不承诺 | 完整 Dolby Vision 原生输出、电视进入 DV mode、DV P7 FEL 完整增强层、把 PCM 解码说成 Atmos / DTS:X 对象音频直通 |
Atmos / DTS:X:本地软件解码到 PCM 通常 不会 让 AVR 继续识别对象音频格式;家庭影院意义上的 bitstream 需用户显式开启 HDMI / SPDIF passthrough,且默认应对普通用户关闭。
预设而不是裸露全部 mpv 选项
产品设置宜分普通 / 高级两层。普通层用「质量与性能预设、硬解偏好、HDR 策略、字幕策略、音频 PCM / 直通、是否自动降级」表达 policy;高级层再映射到 hwdec、vo、tone-mapping、hdr-compute-peak、audio-spdif 等。正式版应暴露受控参数,而不是完整 mpv 脚本 / 插件生态。
预设示例方向:
| 预设 | 意图 |
|---|---|
| 平衡 | 默认:auto-safe 硬解、gpu-next + D3D11、默认 HDR 策略、PCM |
| 高质量 / HTPC | 更积极的 tone mapping 与渲染质量;可选 nvdec / Vulkan 候选 |
| 高性能 | 减少 peak compute / 额外 shader,优先负载 |
| 安全兼容 | 播放失败后的本地重试:关硬解、关 passthrough / exclusive、保守 tone mapping |
用户配置表达的是偏好,不是能力证明。hwdec=d3d11va 只说明用户允许或希望走 D3D11VA,不代表该机对该码流一定硬解成功。
能力上报:给 Planner 事实,不给广告布尔
Windows 原生没有等价于 Web MediaCapabilities.decodingInfo() 的统一高层 API。Media Foundation / D3D11 查询只能说明系统栈 可能 支持某类硬解,不能等价于 libmpv 链路保证。命名上应避免 guaranteedHardwareDecodeSupport 一类误导字段,改为 deviceHints + confidence: hint。
更现实的首版主线不是「安装后跑全量真实样片 probe」——样片版权、包体、覆盖率与维护成本对个人主线过高——而是:
用户播放配置(policy)
+ runtime 静态能力(manifest / smoke)
+ Windows 设备 hint(OS / GPU / driver / HDR / 音频 endpoint)
+ 服务端媒体文件事实
+ 版本化硬件 rule pack(known-good / known-bad / hint)
+ 真实播放 observation(成功 / 失败)
→ 服务端播放规划(confidence + fallback)
建议把上报拆成多块,而不是一个巨大的 capabilities: true/false:
declaredPlaybackPolicy 用户策略与预设
runtimeDescriptor runtimeId、hash、mpv API 版本、manifest feature
deviceHints GPU adapter、d3d11 可用性、HDR 显示状态等
observationsSummary 本机已知成功 / 失败计数与时间
服务端仍是最终 Planner:生成 DirectPlay + HttpFile、DirectStream + Hls、Transcode + Hls 等 plan,并附带 confidence、riskReasons、clientOverrides 与 fallbacks。DirectPlay 宜拆成 preferred / risky / blocked,而不是单一 supported=true。
失败降级建议先本地安全配置重试,再容器 / 协议降级,最后才全量视频转码:
DirectPlay + 当前配置
→ DirectPlay + 安全配置(hwdec=no、关 peak / passthrough / exclusive 等)
→ DirectStream + HLS
→ Transcode + HLS
→ Unsupported / 明确提示
音频失败优先切回 PCM / 关闭 exclusive,而不是立刻重压整条视频。Tone mapping 相关失败同理:先减 shader / peak / 换保守曲线,再 HLS。
播放 attempt 上报应结构化:stage(runtime-load、demux、hwdec-init、first-frame-timeout 等)、媒体签名(容器 / 编码 / HDR / 字幕类型,不是完整本地路径)、环境签名(runtime hash、GPU vendor/device/driver、关键预设)。隐私上最小化:不上传 token、完整日志原文与本地绝对路径。
硬件 rule pack 适合记录真实踩坑与少量高置信 hint,不适合做成全量 GPU 百科;未命中规则时默认宽松尝试,但必须带 fallback。
OSD 与播放内核:边界分开
业界 Windows 桌面媒体客户端常见目标形态是:native 高规格播放内核 + 自有透明 OSD,而不是用 HTML5 <video> 扛 4K HDR remux。取证级对照也支持「mpv 系内核 + 自有 Web / UI OSD 叠层」可行,但具体合成路径(HWND 嵌入、render API、合成器叠层)必须单独验收。
工程优先级建议写死:
- 本地播放正确(含 HDR / HLG / DV fallback 样本矩阵)
- 可用硬解路径
- 再谈 OSD 合成与 Web overlay
不要为了「尽快叠上 Web OSD」把默认输出从较成熟的 gpu-next + D3D11 + d3d11va 换成未经验证的跨 API 合成链,导致播放正确性被合成路径绑架。管理 UI 用 WebView2 还是 WinUI,与 LGPL runtime 合规无关;换壳时不得回退 source offer 与动态链接边界。OSD 细节见同系列 Windows UI 路线文,本文只强调 播放正确性优先于 overlay 形态。
验收:多层 gate,而不是「能打开文件」
能力枚举不等于真实链路可用。建议至少分:
| Gate | 要点 |
|---|---|
| License | FFmpeg / mpv 构建选项与依赖无 GPL / nonfree 污染;证据包完整 |
| Runtime | 固定路径加载成功;mpv client API 可初始化;manifest 可读;错误可分类 |
| Playback | H.264 / HEVC / AV1、HDR10、字幕、音频样本矩阵;记录实际 hwdec / vo / tone mapping |
| Device | Intel / AMD / NVIDIA 与 HDR on/off、AVR passthrough 等按矩阵抽样 |
| HTPC | 全屏、多显示器、遥控器 / 媒体键、睡眠唤醒、刷新率策略 |
记录项至少包括:输入色彩与容器、实际硬解与 GPU API、tone mapping 算法、掉帧与主观观感。DV / HLG 等在样本与设备未齐前,只写候选结论。
对同类产品的启示
- 服务端 full 与客户端 LGPL 是两条产物线,不是同一个 zip 的两种安装路径。
- 动态链接 + 证据包 比「口头 LGPL」更接近可发版状态;SBOM 与 source offer 应进 CI。
- Windows 播放 baseline 用 D3D11 系,服务端 Linux 硬解方案不要硬统一。
- 用户设置是 policy,runtime manifest 是静态事实,device 查询是 hint,真实播放是 observation;Planner 消费的是组合,不是单一布尔。
- 能力广告跟证据走:HDR10 tone mapping、DV fallback、passthrough 分层表述,避免把验证项写成认证输出。
- OSD / UI 壳与播放内核验收解耦,优先级写进文档,避免实现阶段被短期 demo 带偏。
注意事项
- 本文是公开向的架构与合规工程口径,不是法律意见,也不承诺具体版本列车或设备白名单。
- 版本钉扎(例如某代 mpv / FFmpeg / libplacebo)会随上游与设备矩阵调整;对外以「受控 LGPL 构建 + 可审计 manifest」表述,不必绑定内部 tag 名。
- 内网 URL、设备序列号、私有仓库路径与精确私有 digest 不应出现在公开文;发布校验在私有 runbook 维护。
- 未过 license / 样本 gate 前,受控 libmpv 只能写成主线候选,不能写成已全量可分发事实。
相关阅读
同系列还可对照:
- Windows 媒体客户端 UI 路线:WebView2 复用、WinUI 3 候选与当前主线:Host / Web shell 与播放 OSD 边界,与 runtime 合规正交。
- Octans Android 播放内核演进:从 libmpv 单内核到双内核实验:另一端 LGPL libmpv 治理与能力边界。
- 媒体库 FFmpeg 工具链:从 Jellyfin 构建到自维护 runtime:服务端 full 工具链安装、探测与验证,与本文客户端线对照。
来源
本文综合改写自 Octans 项目中关于 Windows 客户端播放器内核与 LGPL runtime 选型、Windows libmpv LGPL 构建与版本策略,以及本地播放配置与客户端能力上报的研究材料;OSD 边界参考了公开形态对照中「native 播放 + 自有 OSD」的结论边界。表述已通用化与脱敏,不绑定内部仓库路径、主机名与未发布版本号。