4. HDR 视频基础:HDR 标准概览
做 8K HDR 编码,绕不开 HDR 标准。说实话,我刚接触 HDR 时也被一堆名词搞晕过——HDR10、HLG、Dolby Vision,还有 PQ 曲线、HLG 曲线,再加上 SMPTE ST 2086、MaxFALL、MaxCLL 这些元数据。今天咱们把这些东西理清楚。
4.1 三大 HDR 标准:HDR10、HLG、Dolby Vision
目前主流 HDR 标准就三个。我习惯把它们分成两类:静态元数据和动态元数据。
| 标准 | 元数据方式 | 传输曲线 | 色深 | 典型应用 |
|---|---|---|---|---|
| HDR10 | 静态(整部影片一套) | PQ(ST 2084) | 10-bit | 蓝光、流媒体、YouTube |
| HLG | 无元数据(兼容 SDR) | HLG(ARIB STD-B67) | 10-bit | 广播电视、直播 |
| Dolby Vision | 动态(逐场景) | PQ(ST 2084) | 12-bit | 影院、高端流媒体 |
HDR10 是最基础的。它是开放标准,所有 HDR 设备都支持。但它的元数据是静态的——整部影片只给一组亮度、色域信息。我在项目里遇到过一个问题:一部电影有的场景很亮,有的很暗,HDR10 只能取一个折中值,暗场细节可能就丢了。
HLG 是 BBC 和 NHK 搞的。它最大的特点是兼容 SDR 显示设备。你想想看,电视台不可能让观众换电视才能看 HDR 节目。HLG 的信号在 SDR 电视上显示正常,在 HDR 电视上显示高动态范围。我参与过几个广电项目,HLG 在直播场景下确实省心——不需要元数据,直接推流就行。
Dolby Vision 是杜比家的,动态元数据是它的杀手锏。它会分析每个场景甚至每帧的亮度信息,逐场景调整映射。效果确实好,但需要授权费。我记得有一次对比测试,同一部片子用 HDR10 和 Dolby Vision 分别编码,暗部细节差距肉眼可见。
核心结论:做 8K HDR 编码,HDR10 是底线支持,HLG 适合广电场景,Dolby Vision 追求极致画质。AV1 编码器对这三种标准都支持,但元数据传递方式有差异,后面章节会细讲。
4.2 PQ 与 HLG 曲线
HDR 和 SDR 最大的区别是什么?亮度范围。SDR 只有 0.1~100 cd/m²,HDR 能到 0.005~10,000 cd/m²。但 10-bit 只有 1024 个灰度级,怎么分配这些亮度值?这就靠 电光转换函数(EOTF) 了。
4.2.1 PQ 曲线(Perceptual Quantizer)
PQ 曲线是 SMPTE ST 2084 标准定义的。它的核心思想是:人眼对暗部变化更敏感,对亮部变化不敏感。所以 PQ 曲线在暗部分配更多码值,亮部分配更少。
PQ 曲线的数学表达式是这样的:
L = ((max(L_pq^(1/m2) - c1, 0)) / (c2 - c3 * L_pq^(1/m2)))^(1/m1)
其中:
L_pq = 归一化的电信号值(0~1)
L = 亮度值(cd/m²)
m1 = 2610/4096 × 1/4 ≈ 0.1593
m2 = 2523/4096 × 128 ≈ 78.8438
c1 = 3424/4096 = 0.8359
c2 = 2413/4096 × 32 ≈ 18.8516
c3 = 2392/4096 × 32 ≈ 18.6875
嗯,公式看着复杂。但你只要记住:PQ 曲线是亮度映射。什么意思?一个 PQ 码值对应一个亮度值,不管显示设备是什么。比如 PQ 码值 512 对应约 100 cd/m²,在任何 PQ 显示器上都一样。
我的经验:做 8K HDR 编码时,PQ 曲线对码率分配影响很大。暗部细节多的地方需要更多码率,因为 PQ 在暗部分配了更多码值。我曾经在编码一个夜景场景时,默认码率控制导致暗部出现条带,后来调整了码率分配策略才解决。
4.2.2 HLG 曲线(Hybrid Log-Gamma)
HLG 曲线是另一种思路。它把信号分成两部分:
- 对数部分(Log):处理高光区域
- 伽马部分(Gamma):处理暗部区域
HLG 的数学表达式相对简单:
E' = sqrt(3 * E) for 0 ≤ E ≤ 1/12
E' = a * ln(12 * E - b) + c for 1/12 < E ≤ 1
其中:
a = 0.17883277
b = 0.28466892
c = 0.55991073
HLG 和 PQ 最大的区别:HLG 是相对亮度映射。它不指定亮度值,而是根据显示设备的能力自适应。SDR 电视看到 SDR 效果,HDR 电视看到 HDR 效果。这也是为什么 HLG 不需要元数据。
| 特性 | PQ(ST 2084) | HLG |
|---|---|---|
| 亮度映射方式 | 亮度 | 相对亮度 |
| 峰值亮度 | 10,000 cd/m² | 取决于设备(通常 1,000~2,000) |
| SDR 兼容性 | 不兼容 | 原生兼容 |
| 元数据需求 | 需要 | 不需要 |
| 典型应用 | 流媒体、蓝光 | 广播电视、直播 |
注意:HLG 虽然兼容 SDR,但 HDR 效果上限受限于显示设备。如果显示设备峰值亮度只有 400 cd/m²,HLG 的高光细节就出不来。PQ 则能保证内容创作者意图的亮度映射,前提是显示设备支持。
4.3 HDR 元数据:SMPTE ST 2086、MaxFALL、MaxCLL
元数据是 HDR 的「说明书」。显示设备靠它知道怎么正确显示 HDR 内容。HDR10 使用静态元数据,Dolby Vision 使用动态元数据。咱们先看静态元数据的三要素。
4.3.1 SMPTE ST 2086(Mastering Display Color Volume)
这个元数据描述的是调色监视器的能力。包含三个信息:
- 主色度(Primaries):调色监视器的 R/G/B 色坐标
- 白点(White Point):通常 D65
- 最大亮度(MaxLum)和最小亮度(MinLum):调色监视器的亮度范围
举个例子:
Mastering display color volume:
Primaries (x, y):
R: (0.708, 0.292)
G: (0.170, 0.797)
B: (0.131, 0.046)
White point (x, y): (0.3127, 0.3290)
Max luminance: 1000 cd/m²
Min luminance: 0.005 cd/m²
这个信息有什么用?显示设备可以根据它做色域映射。如果你的电视色域比调色监视器小,就需要把超出部分映射到可显示范围。我见过一些低端电视直接裁剪,导致颜色失真——这就是元数据没用好。
4.3.2 MaxFALL(Maximum Frame Average Light Level)
MaxFALL 是整部影片中,所有帧的平均亮度的最大值。计算方式:
- 对每一帧,计算所有像素亮度的平均值
- 取所有帧中这个平均值的最大值
这个值告诉显示设备:这部影片最亮的「平均场景」有多亮。显示设备可以用它来调整背光策略。比如 MaxFALL 是 400 cd/m²,电视就知道不需要全程开满背光。
4.3.3 MaxCLL(Maximum Content Light Level)
MaxCLL 是整部影片中,单个像素的最大亮度值。它代表影片的「峰值亮度」。比如一个爆炸场景中某个像素达到 1,000 cd/m²,MaxCLL 就是 1,000。
这两个值在编码时怎么用?我举个例子:
# 使用 FFmpeg 提取 HDR10 元数据
ffmpeg -i input.mkv -f lavfi -i "null" -vframes 1 -vf \
"signalstats,metadata=print:file=-" -f null -
# 或者用 mediainfo 查看
mediainfo --Details=1 input.mkv | grep -i "max"
关键点:MaxFALL 和 MaxCLL 是内容分析出来的,不是调色师手动设置的。编码时如果这两个值设置不对,显示设备可能错误地调整亮度。我曾经遇到一个案例:MaxCLL 设得太低,导致高亮场景被削波;设得太高,又导致整体亮度被压低。正确做法是用工具逐帧分析。
4.4 HDR 元数据在 AV1 中的传递
AV1 编码时,HDR 元数据通过 SEI(Supplemental Enhancement Information) 消息传递。具体来说:
- HDR10:使用 AV1 的
mastering_display_color_volume和content_light_levelOBU(Open Bitstream Unit) - HLG:不需要元数据,但需要标记色彩原色和传输特性
- Dolby Vision:使用 RPU(Reference Processing Unit)数据,通过私有 SEI 传递
用 SVT-AV1 编码 HDR10 内容的示例:
# 编码 HDR10 内容
SvtAv1EncApp -i input.y4m -b output.ivf \
--color-primaries bt2020 \
--transfer-characteristics smpte2084 \
--matrix-coefficients bt2020-ncl \
--mastering-display "G(0.170,0.797)B(0.131,0.046)R(0.708,0.292)WP(0.3127,0.3290)L(1000,0.005)" \
--content-light "MaxFALL=400,MaxCLL=1000"
我的建议:编码前先用工具验证元数据是否正确。我习惯用 ffmpeg 的 showinfo 滤镜或者 exiftool 检查。元数据错了,解码端显示效果会出大问题——而且这种问题很难排查,因为编码过程没有报错。
这张图把 HDR 基础的三块内容串起来了。左边是标准选择,中间是传输曲线,右边是元数据。这三块决定了你的 HDR 内容在编码端怎么处理、在解码端怎么显示。
避坑指南:我曾经在项目里遇到一个坑——编码时忘记设置 --color-primaries 和 --transfer-characteristics,结果解码器默认按 SDR 处理,颜色完全不对。HDR 编码时,色彩原色、传输特性、矩阵系数这三个参数必须显式设置,不要依赖默认值。