本文主要说明自托管媒体库(以 Octans 播放子系统为例)在服务端 HLS 转码时,如何在软件、tonemap_vaapi 与 tonemap_opencl 之间做 tone mapping 选型:能力门禁、按动态范围分流的 Planner 逻辑、验证分层含义,以及「厂商 codec 矩阵 ≠ 本机已接线」的边界。设备节点以 /dev/dri/renderD128 一类占位符给出。
浏览器 Web 播放往往不要求客户端原生吃下全部 HDR / Dolby Vision 组合,而是在服务端把内容压到可播的 SDR / BT.709 基线。真正执行编解码的不是 Web 框架本身,而是托管的 FFmpeg 子进程;服务端负责的是:识别媒体事实 → 探测运行时能力 → 选链路 → 失败可观察地回退。
先分清术语
| 术语 | 含义 | 常见误区 |
|---|---|---|
| VAAPI | Linux 通用视频加速 API;能力来自底层驱动(如 Intel iHD) | 「装了 VAAPI 包」≠ 硬解/硬编/tonemap 都可用 |
| OpenCL interop | 把 VAAPI 表面映射到 OpenCL,做 tonemap_opencl 后再 map 回 VAAPI | 不等于独立 OpenCL 解码器;仍依赖 VAAPI 硬解/硬编 |
| QSV / NVENC / AMF | 厂商专有编解码路径 | 与当前「VAAPI + OpenCL」主线是不同 provider 候选 |
| Tone mapping | 动态范围 / 色彩转换(HDR/HLG/DOVI → SDR) | 不等于降分辨率、降码率(那是输出质量处理) |
| Capability gate | 启动或运行时探测到的真实 codec / filter / hw 能力 | 不能用「二进制能 -version」替代 |
工程上的一句话:
ffmpeg 编译进了某个 encoder
≠ 这台机器运行时可用
≠ Planner 已经把这条路接入业务 HLS
真正可用需要三件事同时成立:硬件存在、驱动与 ICD 可用、当前 FFmpeg 构建支持对应后端;业务上还要第四件:能力图已探测、命令模板已接线、样片验证通过。
后端硬转码基线:为什么是 VAAPI + OpenCL
家用 / 轻量多用户 Linux 媒体服务器上,Intel 核显走 VAAPI 通常比先上 QSV 更适合做统一基线:
- Linux 侧更通用,和
libva、intel-media-driver、FFmpeg 滤镜栈更容易收敛。 - 后续 scale、色彩处理、硬件滤镜路径更直接。
- 同一套思路后续也能部分复用到 AMD 的 VAAPI 路线。
NVIDIA 更适合高吞吐、多路并发的 NVENC/NVDEC 专机;AMD 可走 VAAPI 或后续专项 AMF。当前主线先把 Linux / Intel VAAPI 与 OpenCL interop 跑稳,其它厂商 provider 按真实硬件再补。
概念上的全硬件视频链路:
VAAPI decode / upload
→ VAAPI scale 或 OpenCL tone mapping
→ VAAPI encode
→ fMP4 HLS 输出
设备与工具链占位:
render device: /dev/dri/renderD128 # 以本机 ls /dev/dri 为准
ffmpeg root: <ffmpeg-root> # 例:/opt/octans-ffmpeg
ffmpeg: <ffmpeg-root>/bin/ffmpeg
OpenCL ICD: 发行版 intel-opencl-icd 一类包(厂商与版本因环境而异)
动态范围如何分流
Tone mapping 只在「需要把 HDR 类内容变成 Web SDR」时介入。SDR 源不需要动态范围转换,只走普通 VAAPI 或软件的 decode / scale / encode。
分流表(EnginePolicy=Auto 口径)
| 输入色彩范围 | 优先硬件路线 | 软件基线 | 说明 |
|---|---|---|---|
| SDR | VAAPI decode → scale_vaapi → h264_vaapi / hevc_vaapi | 软件 decode/encode | 无 tone mapping |
| HDR10 / PQ | 优先 tonemap_vaapi;能力缺失时可试 OpenCL | tonemapx → BT.709 | HDR10+ 不保留 dynamic metadata,按 PQ 基线 |
| HDR10+ | 同 HDR10 | 同 HDR10 | 动态元数据不保留进输出 |
| HLG | tonemap_vaapi 不适用;OpenCL:VAAPI decode → tonemap_opencl → scale_vaapi → encode | tonemapx | HLG 是 OpenCL 硬件链的典型动机 |
| DV 有可用 fallback | 按 fallback 类型(SDR / HDR10 / HDR10+ / HLG)复用上表 | 按 fallback | 转码时不应用 DV RPU/EL,不保留 DV metadata |
| pure DOVI / 无 fallback(如 P5) | OpenCL:tonemap_opencl:apply_dovi=true 串 VAAPI 解/编 | tonemapx:apply_dovi=true | DOVI reshaping 必须显式 apply_dovi |
链路 ID 便于日志与排障对齐(名称可因实现略有差异):
| 链路 ID(概念) | 适用 |
|---|---|
vaapi-tonemap-hdr-bt709-nv12 | HDR10 / HDR10+ 等 PQ 系,VAAPI tonemap |
opencl-tonemap-hdr-bt709-nv12 | HLG / 部分 HDR 的 OpenCL tonemap |
opencl-tonemap-dovi-bt709-nv12 | pure DOVI,apply_dovi=true |
tonemapx-*-bt709-yuv420p | 软件 fallback 或显式软件 engine |
不要把 OpenCL 链路混进 tonemap_vaapi 的 capability 标记。 二者依赖不同:OpenCL 需要 ICD 初始化与 VAAPI/OpenCL interop 扩展;失败模式、探测项、回退策略都不相同。
OpenCL 全硬件链示意
VAAPI decode
→ hwmap 到 OpenCL
→ tonemap_opencl(目标 t/m/p=bt709,format=nv12)
→ hwmap 回 VAAPI
→ scale_vaapi
→ h264_vaapi / hevc_vaapi
代表性命令结构(路径已通用化;业务 HLS 还有 playlist / segment / pause 等参数,此处仅示意 filter 串联):
<ffmpeg-root>/bin/ffmpeg \
-init_hw_device vaapi=va:/dev/dri/renderD128 \
-init_hw_device opencl=ocl@va \
-filter_hw_device ocl \
-hwaccel vaapi \
-hwaccel_device va \
-hwaccel_output_format vaapi \
-i "$input" \
-vf 'hwmap=derive_device=opencl,tonemap_opencl=tonemap=bt2390:t=bt709:m=bt709:p=bt709:format=nv12:apply_dovi=true,hwmap=derive_device=vaapi:reverse=1,scale_vaapi=w=1920:h=1080:format=nv12,setsar=1' \
-c:v hevc_vaapi \
-tag:v hvc1 \
"$output"
要点:
- HLG 不要误开
apply_dovi=true;pure DOVI 必须显式写出。 - 非 16:9 源注意
setsar=1或等价处理,避免播放器按异常 SAR 展示。 - 输出色彩标记应落到
bt709/bt709/bt709,不要只依赖 encoder 默认 metadata。 - 日志里若出现
clCreateFromVA_APIMediaSurfaceINTEL一类 interop 符号,说明走了 Intel VAAPI/OpenCL 互通路径(厂商扩展,不可默认跨卡通用)。
能力门禁:Planner 真正在看什么
选型顺序可以粗画成:
媒体事实(codec / profile / bit depth / transfer / DOVI fallback)
+ 客户端能力(能否播某种 HLS 输出 codec 等)
+ 运行时 capability graph
+ 策略(EnginePolicy=Auto | 显式 VAAPI | 显式 OpenCL | 显式软件)
→ 选定 transform chain + encoder
→ 启动失败则按策略 fallback 或 fail fast
应单独探测的门
| 门 | 含义 |
|---|---|
| render 设备 | /dev/dri/renderD* 存在且进程有权限 |
| VAAPI 基础 | vainfo / FFmpeg hwaccels 含 vaapi;目标 encoder(h264_vaapi / hevc_vaapi 等)可用 |
tonemap_vaapi | 滤镜存在且对目标 transfer(如 PQ)可初始化 |
| OpenCL platform | ICD 已安装;初始化平台数 > 0(未装 ICD 常见 -1001) |
tonemap_opencl | 滤镜、算法、目标色彩、apply_dovi 能力 |
| VAAPI↔OpenCL interop | 能否 hwmap 往返,而不是只软解再 hwupload |
| 输出侧 | 目标分辨率 / profile constraints、客户端是否接受 HEVC HLS 等 |
能力开启以探测结果为准,不以「装了某某 deb 包名」为准。配置侧常见原则:
EnginePolicy=Auto:按上表优先硬件,能力缺失或启动失败可回退软件tonemapx。- 显式 OpenCL / 显式 VAAPI:能力不足时宜 fail fast,避免静默跑成另一条链却写着「硬转码」。
- 软件
tonemapx与 OpenCLtonemap_opencl的算法配置应分开,避免把 CPU 曲线误读成硬件通用配置。 - 历史上的
zscale + tonemap不宜再当第二套软件 fallback 与tonemapx并存:pure DOVI 需要apply_dovi级别的 reshaping;双软件链只会放大归因成本。缺tonemapx时应 fail fast。
硬件失败时的推荐策略是:按配置回退软件,而不是直接让用户「播不了」;但 fallback 必须可观察——日志应写明实际路径是 vaapi、opencl、software 还是 vaapi-fallback-software,并带上 device、engine、filter chain 与原因。
「验证」到底验证了什么
ffmpeg -version 成功不等于播放可用。建议分层,前一层失败不进入后一层:
1. 二进制与动态库完整
2. 关键 codec / filter / muxer 与项目补丁行为存在
3. capability helper / 后端能力图识别正确
4. 最小 VAAPI 编码冒烟(testsrc + h264_vaapi 等)
5. 真实样片:SDR 硬解硬编 HLS
6. 真实样片:HDR10 VAAPI tonemap HLS;HLG / pure DOVI OpenCL 链
7. 业务会话:playlist、segment、浏览器播放、runtime pause / seek、fallback 归因
OpenCL tone mapping 的研究验证通常分三层:
- 软件解码后
hwupload到 OpenCL,确认tonemap_opencl本身可用。 VAAPI decode → OpenCL tonemap → VAAPI encode串通。- 接上
scale_vaapi,输出 H.264 / H.265 样片并做观感检查。
MP4 短样片通过 ≠ 业务 HLS 已接入。 连续 seek、event playlist、stdin runtime pause、多会话并发,都要单独验收。Docker 与 Host 还要分别确认:/dev/dri 映射、用户组 video/render、OpenCL ICD 是否进镜像。
本机冒烟示例
ls -l /dev/dri
vainfo --display drm --device /dev/dri/renderD128
<ffmpeg-root>/bin/ffmpeg -hide_banner -hwaccels
<ffmpeg-root>/bin/ffmpeg -hide_banner -encoders | rg 'vaapi|libx26'
# 最小 VAAPI 编码
<ffmpeg-root>/bin/ffmpeg -hide_banner -y \
-vaapi_device /dev/dri/renderD128 \
-f lavfi -i testsrc2=size=1280x720:rate=30 \
-t 2 \
-vf 'format=nv12,hwupload' \
-c:v h264_vaapi \
/tmp/vaapi-smoke.mp4
OpenCL 未就绪时的典型失败:
Failed to get number of OpenCL platforms: -1001
处理方向是安装匹配 GPU 的 OpenCL ICD,并确认容器/服务进程能读到 ICD 配置,而不是只换 FFmpeg 二进制。
性能观察:只当结论,不当普适 SLA
在单机 Intel iHD + UHD 类核显、约 60s 样片对照上,有过这些方向性结论(数值因驱动、分辨率、码率、low-power entrypoint 而变,不可当全球 SLA):
- HDR10 场景:
tonemap_vaapi通常比tonemap_opencl更快;能走 VAAPI 就优先 VAAPI。 - HLG / pure DOVI:硬件 tonemap 依赖 OpenCL 路线;软件
tonemapx是 Auto 的安全网。 - 输出 codec:同场景 H.264 VAAPI 往往比未调优的 H.265 VAAPI 更容易拿到实时余量;若硬件暴露 HEVC low-power encode entrypoint,H.265 速度可显著改善。
- 服务端分片生产长期
speed < 1x时,前端会表现为缓冲难涨、seek 后长时间 preparing——根因可能在 encoder 参数,而不只是客户端网络。
这些结论只服务「本机默认策略怎么设」;换 GPU 代际、关 low-power、换分辨率,必须重测。
边界:GPU 矩阵不是万能答案
厂商公开的固定功能编解码矩阵(H.264 / HEVC / AV1 / VP9 等按代际的 D/E)回答的是:
「这块硅理论上有没有固定功能单元」
它不回答:
- 当前 FFmpeg 是否编译并探测到该路径;
- Docker 是否映射了 render 节点与 ICD;
tonemap_vaapi是否覆盖 HLG;- pure DOVI 是否有
apply_dovi的硬/软链路; - Planner 是否已把该 codec 接进 HLS 输入/输出白名单。
再补几条工程红线:
- SKU 例外:无核显 Core F、无 NVENC 的低端 NVIDIA、RX 6500/W6400 一类「几乎无硬编」SKU,不能只按品牌粗判。
- Profile / bit depth:「支持 HEVC」≠ Main 10 / 4:2:2 / 4:4:4 都能硬转。
- AV1 解编分离:多数平台先有 decode、后有 encode;不能写「有 AV1 就能硬编 HLS」。
- 长尾 codec(ProRes、DNxHR、FFV1、老屏幕录制等):默认软件,不进固定功能硬解承诺。
- 跨厂商 OpenCL interop:Intel 上验证的 VAAPI↔OpenCL 扩展,不自动等于 AMD/NVIDIA 同构可用。
- Vulkan / libplacebo:即便 FFmpeg 编进了相关能力,未接入业务链路前不能写成「当前支持」。
更稳妥的数据模型是两步:
1) 媒体流识别:codec / profile / pix_fmt / transfer / hdr_metadata / dovi_fallback
2) 设备能力匹配:GPU + 驱动 + API + 本项目 capability graph + 输出策略
运维检查清单
| 现象 | 优先查 |
|---|---|
| 总是软件转码 | 能力图是否缺 VAAPI/OpenCL;render 权限;容器 /dev/dri |
| HDR10 正常、HLG 极慢或失败 | 是否误走 tonemap_vaapi;OpenCL ICD 与 interop |
| pure DOVI 发灰 / 错色 | 是否缺少 apply_dovi=true;是否落到无 DOVI 的滤镜链 |
| 有 OpenCL 滤镜仍初始化失败 | ICD 包、容器环境变量、多 GPU 下 device 选择 |
| 画面 SAR 异常 | 非 16:9 是否补了 setsar=1 |
| 日志写 hard 实际是 soft | fallback 是否可观察;显式策略是否应 fail fast |
| 换机后全挂 | 驱动 / 内核 / SR-IOV VF / render 节点编号变化 |
Unraid 等场景下把核显 VF 直通进 Ubuntu 再跑 VAAPI,属于设备如何出现在 /dev/dri 的问题;本文不展开,见同系列 Unraid / UHD 770 文。
注意事项
- 本文是选型与验证口径,不是完整 codec 支持矩阵,也不是 API 契约。
- 命令中的
/dev/dri/renderD128、<ffmpeg-root>均为占位;以本机ls、配置文件与 capability 日志为准。 - 内网样片路径、对象存储 artifact、精确 deb digest、私有 registry 不要写进公开文。
- 硬件加速失败应可回退、可观测;不要用「神秘卡顿」代替明确的 engine 字段。
- 验证过的是特定驱动 + FFmpeg runtime + 样片集合;升级驱动或 runtime 后应重跑分层验证。
相关阅读
同系列还可对照:
- 媒体库 FFmpeg 工具链:从 Jellyfin 构建到自维护 runtime:专用 FFmpeg、能力探测与「二进制能跑」分层验证。
- Unraid 上给 Ubuntu 虚拟机 SR-IOV 直通 Intel UHD 770 做 VAAPI 转码:render 设备如何从宿主机落到客机
/dev/dri。 - 媒体库播放排障:从会话创建到 HLS / DirectPlay / 字幕链路:会话、HLS window 与硬解回退日志口径。
来源
本文综合改写自 Octans 项目文档中的硬件转码基线说明、OpenCL + VAAPI tone mapping 验证研究、视频编解码硬件支持复核,以及播放转码支持矩阵中的正式分流口径;性能段落仅吸收公开 benchmark 中的方向性结论。路径与版本已通用化,不绑定特定内网环境或对象存储位置。