HDR 渲染
Hyperframes 可以在你的合成引用 HDR 视频或 HDR 静态图片时渲染为 HDR10 MP4(H.265 10-bit,BT.2020)。HDR 默认从你的媒体源自动检测,当不存在时回退到 SDR。
ℹ️ Note
默认情况下,Hyperframes 探测你的媒体并在存在 HDR 源时启用 HDR。使用
--hdr即使没有 HDR 源也强制 HDR,或使用--sdr即使存在 HDR 源也强制 SDR。
快速开始
将 HDR 源添加到合成
Hyperframes 从源的色彩空间元数据检测 HDR。最可靠的 HDR 源是:
- 标记为 BT.2020 并带有 PQ(
smpte2084)或 HLG(arib-std-b67)传输函数的 HDR 视频 - 作为 16-bit PNG 并带有 BT.2020 PQ 编码的 HDR 静态图片
参见源媒体了解完整详情。
正常渲染
npx hyperframes render --output output.mp4
HDR 输出需要 --format mp4。如果 Hyperframes 检测到 HDR 源,会自动渲染 HDR。如果你同时传入 --format mov 或 --format webm,Hyperframes 会记录警告并回退到 SDR。
验证输出为 HDR
使用 ffprobe 确认编码流携带 HDR 颜色标记和 HDR10 元数据:
ffprobe -v error -show_streams output.mp4 | grep -E 'color_transfer|color_primaries|color_space'
参见验证 HDR 输出了解要查找的内容。
HDR 模式的工作原理
在渲染期间,producer:
探测每个视频和图片源
对每个 <video> 和 <img> 源运行 ffprobe 以读取其色彩空间(原色、传输函数、矩阵)。此探测驱动默认的自动检测行为,仅在你使用 --sdr 显式强制 SDR 时才跳过。
选择主导的 HDR 传输函数
如果任何源使用 PQ(smpte2084),输出使用 PQ。否则,如果任何源使用 HLG(arib-std-b67),输出使用 HLG。如果未找到 HDR 源,渲染保持为 SDR。
编码为 H.265 10-bit BT.2020
视频编码器切换到 libx265,使用 -pix_fmt yuv420p10le、颜色标记 colorprim=bt2020:transfer=<smpte2084|arib-std-b67>:colormatrix=bt2020nc 和 HDR10 静态元数据(master-display 和 max-cll)。没有该元数据,播放器(QuickTime、YouTube、HDR 电视)会将流色调映射为 SDR BT.2020——这看起来会不对。
原生合成 HDR 源,转换 SDR 叠加层
HDR 视频和图片通过 FFmpeg 提取为 16-bit 线性光像素,不放入 DOM 截图,而是以全位深在服务端合成。SDR DOM 叠加层(文本、形状、HTML 中的 UI)在叠加之前从 sRGB 转换为 BT.2020,因此颜色不会偏移。
源媒体要求
HDR 视频
Hyperframes 从其 ffprobe 色彩空间元数据识别 HDR 视频:
| 指标 | 识别为 HDR |
|---|---|
color_primaries 包含 bt2020 | 是 |
color_space 包含 bt2020 | 是 |
color_transfer = smpte2084(PQ) | 是 — PQ |
color_transfer = arib-std-b67(HLG) | 是 — HLG |
其他(如 bt709、smpte170m) | 否 — 视为 SDR |
有效的 HDR 源是任何流元数据报告 BT.2020 原色加上 PQ 或 HLG 传输函数的 MP4。Hyperframes 会自动检测:
ffprobe -v error -show_streams assets/clip.mp4 | grep color
# color_primaries=bt2020
# color_transfer=smpte2084
# color_space=bt2020nc
HDR 静态图片
Hyperframes 支持以 16-bit PNG 格式提供的 HDR 静态图片,标记为 BT.2020 原色和 PQ 传输函数。将它们作为普通 <img> 放入合成中:
<img class="clip" data-start="0" data-duration="3"
src="./assets/hdr-photo.png" />
当启用 HDR 时,图片会被解码一次为 16-bit 线性光 RGB 并原生合成为 HDR 输出。
ℹ️ Note
HDR
<img>解码限于 16-bit PNG。JPEG、WebP、AVIF 和 APNG 不会被识别为 HDR 源——它们通过正常的 SDR DOM 路径加载。对于 HDR 动态内容,使用<video>元素。
SDR 源与 HDR 混合
你可以在同一合成中自由混合 SDR 和 HDR 媒体:
- SDR 视频 保持在 DOM 截图路径中,获得上述 sRGB → BT.2020 转换
- HDR 视频 以 16-bit 原生提取并合成为 SDR DOM 层的下方
- SDR 图片和 DOM 元素(文本、形状、渐变、GSAP 动画)从 sRGB 转换为 BT.2020
这是处理合成的相同管线,例如在带有动画文本的 SDR 下方三分之一字幕条下播放 HDR 无人机片段。
输出格式要求
| 输出格式 | HDR 支持 |
|---|---|
mp4 | 是 — H.265 10-bit BT.2020,HDR10 元数据 |
mov | 否 — 回退到 SDR |
webm | 否 — 回退到 SDR |
如果启用了 HDR 且你同时传入 --format mov 或 --format webm,Hyperframes 会记录消息并生成等效的 SDR 渲染。没有错误——渲染仍会完成——因此请检查日志(或你的验证步骤)以确认你得到了 HDR。
验证 HDR 输出
使用 ffprobe 确认颜色标记和 HDR10 静态元数据都存在:
ffprobe -v error -show_streams -select_streams v:0 output.mp4 \
| grep -E 'codec_name|pix_fmt|color_transfer|color_primaries|color_space'
对于 PQ HDR10 渲染,你应该看到:
codec_name=hevc
pix_fmt=yuv420p10le
color_space=bt2020nc
color_primaries=bt2020
color_transfer=smpte2084
然后检查 HDR10 SEI / 容器框:
ffprobe -v error -show_frames -read_intervals "%+#1" \
-show_entries frame=side_data_list output.mp4
你应该看到 Mastering display metadata 和 Content light level metadata 条目。没有它们,支持 HDR 的播放器会将文件视为 SDR BT.2020,在 HDR 显示器上颜色会看起来褪色或不对。
对于 HLG 渲染,唯一的区别是 color_transfer=arib-std-b67——其余检查相同。
Docker 渲染
Docker 使用与本地渲染相同的自动检测逻辑,因此你可以从容器化渲染器生成 HDR10 MP4 输出,无需额外标志:
npx hyperframes render --docker --output output.mp4
容器运行与本地渲染器相同的探测 → 合成 → 编码管线。使用验证 HDR 输出中描述的相同 ffprobe 检查验证输出。
ℹ️ Note
Docker HDR 渲染目前对 SDR DOM 层运行在 CPU 侧(容器回退到软件 WebGL,因为默认未配置 GPU 直通)。因此帧捕获比本地有头 Chrome 慢——在确定 CI runner 规模前,请关闭
--quiet测量你自己的合成并比较挂钟时间。编码的 HDR10 元数据和像素数据与本地渲染相同。
限制
- 仅 MP4 — 使用
--format mov或--format webm的 HDR 输出回退到 SDR - HDR 图片:仅 16-bit PNG — 其他格式(JPEG、WebP、AVIF、APNG)不会被解码为 HDR,会通过 SDR DOM 路径
- 仅 H.265 — H.264 被剥离 — 使用
codec: "h264"和hdr: { transfer }调用编码器会被拒绝;编码器记录警告、丢弃hdr并将输出标记为 SDR/BT.709。libx264无法编码 HDR,替代方案是"半 HDR"文件(BT.2020 容器标记但位流中是 BT.709 VUI 块),这会混淆支持 HDR 的播放器 - GPU H.265 发出颜色标记但不发出静态母版元数据 —
useGpu: true配合 HDR(nvenc、videotoolbox、amf、qsv、vaapi)为流标记 BT.2020 + 正确的传输函数(smpte2084 / arib-std-b67),但不嵌入master-display或max-cllSEI。ffmpeg 不允许这些标志通过硬件编码器。输出适用于预览和创作,但不适用于 HDR10 感知的交付(Apple TV、YouTube、Netflix)。对于符合规范的 HDR10 生产输出,保持useGpu: false以便 SWlibx265路径嵌入母版元数据。 - Player 支持 —
<hyperframes-player>Web 组件在浏览器中播放编码的 MP4,并继承宿主浏览器提供的 HDR 支持;它不实现自己的 HDR 管线 - 有头 Chrome HDR DOM 捕获 — 引擎提供了一个单独的基于 WebGPU 的捕获路径,用于将 CSS 动画 DOM 直接渲染为 HDR(
initHdrReadback、launchHdrBrowser)。它需要带有--enable-unsafe-webgpu的有头 Chrome,不被默认渲染管线使用。如果你正在构建自定义集成,请参见引擎:HDR。
常见陷阱
| 症状 | 可能原因 |
|---|---|
| 输出看起来与 SDR 相同 | 源媒体是 SDR,或使用了 --sdr 强制 SDR。对输入运行 ffprobe 并检查渲染日志 |
| 输出"有点 HDR"但在 YouTube/QuickTime 上色调映射不对 | 编码流上缺少 HDR10 静态元数据。使用上述 ffprobe 代码片段验证 |
| Docker 渲染比本地慢得多 | 预期行为——容器回退到软件 WebGL 进行 SDR DOM 捕获。像素输出相同 |
使用了 --format webm 得到了 SDR | 预期行为——HDR 输出仅限 MP4 |
HDR <img> 看起来像 SDR / 褪色 | 源不是 16-bit PNG。重新导出为 16-bit PNG(BT.2020 PQ)或改用 <video> 元素 |
下一步
- 渲染 本地 vs Docker、质量预设、worker
- CLI
完整的
render命令参考,包括 HDR 自动检测、--hdr和--sdr - 引擎:HDR API
从
@hyperframes/engine导出的公共 HDR 工具 - 常见错误 影响渲染输出的陷阱