halfsize

halfsize / HDR

HDR 视频压完,为什么发灰?

在相册里明明很鲜艳。压了一遍之后,天空白成一片,人脸发灰,整段片子像蒙了一层纱。 这不是码率的问题,把码率调高也救不回来。

iPhone 到底录了什么

从 iPhone 12 开始,默认相机录的是 HLG HDR:10bit 像素、BT.2020 色域、 传递函数标记为 arib-std-b67。安卓旗舰大多录 HLG 或 PQ(smpte2084,也就是 HDR10 的曲线)。文件里存的不是「场景颜色」, 而是需要配合已知显示设备才能解释的 HDR 码值。

压缩工具会犯的两种错

两种情况下文件都是合法的、能播的,只是看起来不对。而压缩的人通常会以为是码率给少了。

一个判断方法:如果调高码率颜色也回不来,那它从来就不是码率问题。

解法是一次色彩转换,不是一个勾选框

要把 HDR 放进普通的 8bit SDR 文件,必须先进线性光、压缩动态范围,再把结果重新标记成 BT.709。用 FFmpeg 的 zscale 和 tonemap 滤镜,这是一条滤镜链:

zscale=tin=arib-std-b67:min=bt2020nc:pin=bt2020:t=linear:npl=100,
format=gbrpf32le,
zscale=p=bt709,
tonemap=tonemap=hable:desat=0,
zscale=t=bt709:m=bt709:r=tv,
format=yuv420p

npl 是标称峰值亮度。HLG 是相对的,100 就够;PQ 是对着真实峰值做的,通常是 1000 尼特。所以 PQ 源片第一行要换成 tin=smpte2084:...:npl=1000。

顺序很关键。tone map 必须在缩放之前做,而且要在源片的传递函数上做。 先缩放,等于在 HDR 码值上重采样,然后再靠猜。

halfsize 从 0.1.9 起怎么做

探测阶段读 color_transfer,在 scale 滤镜之前插入对应的转换链,输出标记为 bt709。--dry-run 能直接看到:

$ npx halfsize IMG_2041.MOV --to 20mb --dry-run

  IMG_2041.MOV
  214 MB  38s  3840x2160  30.00 fps  hevc

  target     20.0 MB
  plan       H.264  1280x720  4.18 Mbps  audio 128 kbps  2-pass
  scale      3840x2160 → 1280x720
  hdr        HLG → SDR BT.709

画质检测也要走同一套。拿没处理过的 HDR 源片去和 SDR 输出比,会把传递函数的差异 当成「压缩损失」,VMAF 数字毫无意义。所以算 SSIM 和 VMAF 之前,参考帧同样要先 tone map。

检查你自己的文件

$ ffprobe -v error -select_streams v:0 \
  -show_entries stream=color_transfer,color_primaries,color_space,pix_fmt \
  -of default=nw=1 视频.mov

color_transfer=arib-std-b67   # HLG
color_primaries=bt2020
color_space=bt2020nc
pix_fmt=yuv420p10le

如果 color_transfer 是 smpte2084,那是 PQ。如果是 bt709,本来就是 SDR,以上都不适用。BT.2020 矩阵配 SDR 传递函数是广色域, 不是 HDR,重新编码不会有事。

「能保留 HDR 吗?」

halfsize 目前不保留。输出是 SDR BT.709,也就是 Discord、WhatsApp、微信、浏览器、 邮件客户端和大多数播放器真正能正确显示的那一版。要保留 HDR 需要另一套管线和一个支持 HDR 的 播放器;如果目的是「发到群聊里让人看得正常」,SDR 才是到处都对的那一版。

常见问题

为什么 iPhone 视频压完发灰?

源片是 HLG HDR。工具做出了 8bit 像素却没转换传递函数,于是要么在 SDR 像素上留着 HDR 标记,要么丢掉了播放器需要的元数据。两种都发灰。

把码率调高能修好吗?

不能。码率影响细节,不影响颜色。曲线错了,50 Mbps 出来还是灰的。

能保留 HDR 吗?

halfsize 目前不保留,会转成 SDR BT.709,也就是大多数软件能正确显示的那一版。保留 HDR 需要单独的管线。

怎么判断文件是不是 HDR?

用 ffprobe 看 color_transfer:arib-std-b67 是 HLG,smpte2084 是 PQ。

tone map 会损失画质吗?

它会主动改变观感:把 HDR 的高光压进 SDR 屏幕能显示的范围。替代方案不是「原汁原味」,而是一个发灰的文件。

相关教程