本文主要说明自托管媒体库(以 Octans 一类播放子系统为例)在协商 DirectPlay / DirectStream / Transcode 时,为何「能解码」不等于「能正确显示」:动态范围与色彩管线应作为独立事实进入 Planner,DirectStream 的视频 copy 不能自动修 HDR,tone mapping 属于完整转码,以及 Dolby Vision 为何必须按 profile / fallback 保守处理。
扫描阶段能标出「HDR10」「DV P8.1」很有价值,但播放侧真正危险的是另一类错误:API 成功、播放器起播、用户也能看到画面,颜色却已经错了——发灰、发淡、高光炸、暗部糊,或 Dolby Vision Profile 5 在不支持的链路上出现绿紫异常。根因通常不是容器或 H.264 认不出来,而是决策只看了:
container + videoCodec + audioCodec
却漏掉了动态范围、传递函数、色彩原色、位深、HDR 元数据与 DV profile。下面把问题收敛成媒体服务器可用的概念管线,而不是 HDR 标准百科。
四层兼容,不是一层「能不能播」
播放兼容性至少应拆成:
1. 容器兼容
2. 视频 / 音频解码兼容
3. 动态范围与色彩管线兼容
4. 字幕与输出策略兼容
前两层决定「有没有声画」;第三层决定「声画是否按制作意图落在正确的亮度与色域上」。Web 场景尤其容易踩坑:浏览器可能解码 10-bit HEVC / H.264 HDR,但显示器、OS、浏览器与 canPlayType() 并不能保证整条显示链路按 HDR 正确映射。
工程上一句话:
能解出帧 ≠ 客户端能正确呈现该 dynamicRange / color pipeline
≠ 服务端可以安全 remux / copy 该视频流
色彩事实模型:先拆三组,再谈策略
标题里的「色彩管线」是播放决策用的统称,不等于媒体字段里的 colorRange = limited / full。服务端在扫描、补强探针或播放协商阶段,至少应建立三组事实:
| 组别 | 典型字段 | 回答什么 |
|---|---|---|
| 动态范围 | dynamicRange、hdrMetadataType、dolbyVisionProfile、fallback 标志 | SDR / HDR10 / HLG / DV 等是什么形态 |
| 色彩管线 | colorPrimaries、transferFunction、matrixCoefficients | BT.709 / BT.2020、PQ / HLG 等怎么解释像素 |
| 采样与量化 | pixelFormat、bitDepth、colorRange | 8/10-bit、yuv420p 等如何采样 |
字段名表达方向即可,不必绑定某一版本 API。方向性枚举例如:
| 字段 | 示例值 |
|---|---|
dynamicRange | Sdr、Hdr10、Hdr10Plus、Hlg、DolbyVision、Unknown |
transferFunction | bt709、smpte2084(PQ)、arib-std-b67(HLG) |
colorPrimaries | bt709、bt2020 |
dolbyVisionProfile | 5、7、8.1、8.2 等(展示与结构化字段应拆开) |
| fallback | hasHdr10Fallback、hasSdrFallback |
这些事实从哪来、如何保守分类、何时二次探针,属于扫描与轨事实层,见 媒体库轨识别与动态范围 与 MediaInfo / ffprobe 分工。本文只消费结果:Planner 必须看见它们,而不能只看见 codec 字符串。
客户端侧不能只靠 canPlayType
Web 能力探测建议组合多信号,而不是单一 MIME 断言:
| 来源 | 作用边界 |
|---|---|
HTMLMediaElement.canPlayType() | 低层 MIME / codec 辅助,不能单独证明 HDR 显示正确 |
MediaCapabilities.decodingInfo() | 解码平滑度与功耗相关信号 |
CSS dynamic-range 等 | 粗判 UA / 输出设备是否宣称高动态范围 |
| 用户设置 | 允许关闭 HDR 直放、强制 SDR tone mapping |
| 服务端策略 | 未知 HDR / DV 默认不直放 |
| 可选真实短片探针 | 用样片验证,而不是只信 API 字符串 |
在能力未验证前,未知按不支持处理比「能播就直放」更安全。
三条播放路径各自能改什么
| 路径 | 典型动作 | 对动态范围 / 色彩 |
|---|---|---|
| DirectPlay | 原文件 HTTP 直出 | 不改视频内容;要求客户端整条链路兼容 |
| DirectStream | 视频 copy,容器 / 音频可调,常出 HLS | 不改视频动态范围;copy 前必须证明色彩仍安全 |
| Transcode | 重解 / 滤镜 / 重编 | 可做 HDR→SDR tone mapping 与色域转换 |
DirectPlay:条件要从三字段扩成五条件
不宜再只写:
containerSupported && videoCodecSupported && audioCodecSupported
更稳的门禁是:
containerSupported
&& videoCodecSupported
&& audioCodecSupported
&& dynamicRangeSupported
&& colorPipelineSupported
对当前以 Web SDR 为主 的媒体库主线,执行规则宜保守:
SDR
→ 继续按容器 / codec / 音频判断是否 DirectPlay
HDR / HLG / Dolby Vision
→ 不因「浏览器或许能解」就 DirectPlay
→ 无 tone mapping 能力时返回 RequiresToneMapping / UnsupportedDynamicRange
后续若开放 HDR 直放,应单独具备:客户端能力探针、显示链路确认、用户偏好、服务端策略与真实样例矩阵——而不是把 canPlayType('video/mp4; codecs=...') 当成色彩验收。
DirectStream:copy 解决不了 HDR 到 SDR
若第二层只是:
视频 copy +(音频 copy 或转 AAC)+ 容器进 HLS
则源视频的动态范围与色彩信息原样保留在视频流里。它能修的是容器、交付方式或音频兼容性,不能自动完成:
HDR / DV / BT.2020 / PQ / HLG → SDR / BT.709
因此:
- 客户端不支持源 HDR / DV 形态时,应进入
Transcode + HLS + tone mapping; - tone mapping 尚未就绪时,应返回明确失败原因,而不是「降级成 DirectStream 碰运气」;
- 兼容性评估在视频 codec 之外,必须再判 dynamic range / color pipeline 是否可安全 copy。
Transcode:tone mapping 是视频处理,不是 remux
只要需要重算画面亮度与色域,就属于完整转码,占用视频处理资源,不应塞进 DirectStream。
概念管线:
源:HDR / DV / BT.2020 / PQ / HLG
→ 解码
→ tone mapping(动态范围落到 SDR)
→ 色彩转换(如 BT.2020 → BT.709)
→ 编码(如 H.264 + yuv420p + AAC)
→ HLS 交付
→ Web 播放器
普通转码阶段还应遵守:禁止把 HDR / DV 源静默当成 SDR 源硬编。没有 tone mapping 的「普通转码」会把错误色彩固化进输出。
硬件侧 VAAPI / OpenCL 如何选型、pure DOVI 与 HLG 如何分流,见 媒体库硬转码与 Tone Mapping。概念上软件侧常区分:
- 非 DOVI HDR:常见
zscale+tonemap一类路径(具体滤镜以运行时 FFmpeg 能力为准); - pure Dolby Vision(如 Profile 5):不能假装走「普通 HDR10 滤镜」;需要具备 DOVI reshaping /
tonemapx一类能力的构建,否则应明确ToneMappingUnavailable。
Web SDR 兜底输出基线
需要 tone mapping 时,面向浏览器的兜底输出宜固定,避免「只改编码器 tag、像素仍是 HDR 语义」:
| 输出项 | 建议值 |
|---|---|
dynamicRange | Sdr |
colorPrimaries / transfer / matrix | bt709 |
pixelFormat | yuv420p |
videoCodec / audioCodec | 如 h264 / aac(按客户端基线) |
delivery | Hls |
| 标记 | 如 toneMapping: HdrToSdr |
这是兼容兜底,不否定后续 HDR passthrough、HDR→HDR、HEVC/AV1 HLS 或 ABR。
决策矩阵(源 × 客户端 → 路径)
| 源媒体 | 客户端 / 显示 | 建议 |
|---|---|---|
| SDR + 兼容容器 / 视音频 | 普通 Web | DirectPlay |
| SDR + 视频可解、容器或音频不兼容 | 普通 Web | DirectStream(视频 copy 安全) |
| HDR10 / HLG + 明确支持对应 HDR 输出 | 已验证 | 后续可评估直放 / copy;当前 Web SDR 主线宜先保守 |
| HDR10 / HLG + 不支持或未知 | SDR 链路 | Transcode + tone mapping;无能力则明确失败 |
| HDR10+ | 不支持动态元数据 | 有可消费 HDR10 降级则按 HDR10;否则转码或不支持 |
| DV Profile 5(无兼容层) | 未明确支持该 profile | 不建议 DirectPlay;服务端 DV→SDR 或明确不支持 |
| DV Profile 7.x / 8.1 + HDR10 fallback | 支持 HDR10 或仅 SDR | 可按 fallback 决策;SDR 主线按 fallback 再 tone map |
| DV Profile 8.2 + SDR fallback | 可确认 fallback | 可按 SDR Web 基线处理 |
| DV profile / 能力未知 | 未知 | 不直放;UnsupportedDolbyVisionProfile 等 |
| 需要 tone map 但服务端无能力 | 任意 | ToneMappingUnavailable,禁止静默直放或假普通转码 |
Dolby Vision:不能只标「是 HDR」
DV 决策至少要看见:
profile / level
单层还是双层
是否有 HDR10 / HLG / SDR fallback
RPU / 元数据是否可被当前工具链消费
当前客户端是否真支持该 profile
默认原则:
除非明确确认客户端支持该 Dolby Vision profile,
否则不要把 DV 判成安全 DirectPlay。
有 HDR10 fallback 时可按 HDR10 路径决策;无 fallback 且客户端不明确支持时,只能 tone mapping 或返回明确错误。Profile 数字与 compatibility id、level 的展示语义不要混用(例如 P8.1 与 dvhe.08.06 不是同一套「小数」含义)——扫描侧的拆分原则见轨与动态范围文,播放侧只要求:结构化事实够用,且未知时宁可不直放。
PlayInfo 与失败原因要可观测
协商结果除了 method / delivery,建议同时暴露:
- 媒体侧:源
dynamicRange、primaries / transfer / matrix、bitDepth、DV profile、fallback; - 输出侧:目标 dynamicRange、是否 tone mapping、输出色彩基线。
失败时避免模糊的「不支持播放」,可区分例如:
| 原因方向 | 含义 |
|---|---|
UnsupportedDynamicRange | 客户端 / 策略不接受源动态范围 |
UnsupportedColorPrimaries / UnsupportedTransferFunction | 色彩管线不兼容 |
UnsupportedDolbyVisionProfile | 该 DV profile 不可安全直放 |
RequiresToneMapping | 需要服务端 tone map 才能正确显示 |
ToneMappingUnavailable | 需要 tone map 但运行时无此能力 |
DolbyVisionFallbackUnavailable | 无可用 fallback 且不能原生播 |
配置层方向性默认:未知 HDR / 未知 DV 不直放;Web 主线默认关闭「能力声称支持就 HDR 直放」;用户可强制 HDR→SDR;tone mapping 关闭时返回明确错误,而不是静默 copy。
最小验收样例(概念)
实现或回归时,至少覆盖:
| 样例 | 期望方向 |
|---|---|
| MP4 + H.264 + AAC + SDR | DirectPlay |
| 同封装 + HDR10,客户端 HDR 未知 | 转码 tone map 或明确不支持,不是盲目 DirectPlay |
| MKV + 可解视频 + HDR,仅需改容器 | 不应因 codec 可解就 DirectStream copy |
| DV Profile 5 | 不 DirectPlay;有 tonemap 能力则服务端 DV→SDR |
| DV + HDR10 fallback | 按 fallback 决策,而非一律当 pure DV 或一律当 SDR |
| 需要 tone map 但能力关闭 / 滤镜缺失 | ToneMappingUnavailable |
和相邻文章的边界
| 本文 | 不写什么 | 去哪看 |
|---|---|---|
| 播放协商中的动态范围 / 色彩门禁与路径归属 | 轨名启发式、stream index、分层探针细节 | 轨识别与动态范围 |
| 为何 copy ≠ tone map、SDR 输出基线 | VAAPI / OpenCL 命令模板与 GPU 矩阵 | 硬转码与 Tone Mapping |
| 事实从探测进入 Planner 的消费关系 | MediaInfo vs ffprobe 速度与字段面对比 | 探测选型 |
注意事项
- 本文是播放侧概念管线与决策口径,不是某一版本 API 契约,也不是 HDR 标准全书。
- 「浏览器解出画面」不能作为 DirectPlay 色彩验收通过的唯一证据。
- DirectStream 只解决 remux / 音频 / 交付,不解决 HDR→SDR。
- 无 tone mapping 时,宁可明确失败,也不要静默直放或把 HDR 当 SDR 硬转。
- Dolby Vision 必须带 profile / fallback 语义;未知即不直放。
- 内网样片路径、私有 FFmpeg 构建细节与对象存储位置不进入公开复现步骤。
相关阅读
同系列还可对照:
- 媒体库硬转码与 Tone Mapping:软件 / VAAPI / OpenCL 如何选型:服务端如何真正执行 HDR→SDR,以及硬件 / 软件分流。
- 媒体库轨识别与动态范围:stream index、语言标题与 HDR/DV 分层探针:扫描如何产出本文依赖的动态范围与 DV 事实。
- 媒体库探测选型:MediaInfo 与 ffprobe 该怎么分工:展示主源与播放补强如何为色彩字段供数。
来源
本文综合改写自 Octans 项目研究文档中关于播放动态范围与色彩管线的专题结论(DirectPlay / DirectStream / Transcode 边界、色彩事实模型、DV 保守原则、tone mapping 归属与 Web SDR 输出基线),并与播放能力决策、DirectPlay 色彩安全及转码运行时计划中的同步口径对齐。实现类名、内网样片与版本号已抽象为通用工程表述;具体能力以目标 FFmpeg runtime 与客户端复测为准。