使用指南

HDR 渲染

当源包含 HDR 视频或图片时,将合成渲染为 HDR10 MP4(BT.2020 PQ 或 HLG,10-bit H.265)。

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-displaymax-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
其他(如 bt709smpte170m否 — 视为 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 metadataContent 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-displaymax-cll SEI。ffmpeg 不允许这些标志通过硬件编码器。输出适用于预览和创作,但不适用于 HDR10 感知的交付(Apple TV、YouTube、Netflix)。对于符合规范的 HDR10 生产输出,保持 useGpu: false 以便 SW libx265 路径嵌入母版元数据。
  • Player 支持<hyperframes-player> Web 组件在浏览器中播放编码的 MP4,并继承宿主浏览器提供的 HDR 支持;它不实现自己的 HDR 管线
  • 有头 Chrome HDR DOM 捕获 — 引擎提供了一个单独的基于 WebGPU 的捕获路径,用于将 CSS 动画 DOM 直接渲染为 HDR(initHdrReadbacklaunchHdrBrowser)。它需要带有 --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 工具
  • 常见错误 影响渲染输出的陷阱