保留原片,先把素材分到三条路
把手机原片设为只读来源,所有检查与转换写到新的候选路径。先记录拍摄设备与模式、原始传输方式、是否经过聊天软件或剪辑器、可用的相机或导出设置截图,以及一份可信参考播放。ffprobe 汇报的是文件和码流中的声明;这些字段能暴露缺失或矛盾,却不能单独证明像素实际采用哪种传递特性。画面看起来灰、暗或过曝也不能独立定性。
| 证据结论 | 本轮动作 |
|---|---|
| 来源记录与声明共同确认是 HDR 像素 | 走外部 HDR→SDR 色调映射,原片不动,新建 SDR 候选。 |
| 独立来源或可靠参考确认像素已经是正确 SDR,只有声明错误 | 仅纠正属性声明,随后重新探测并实际播放;不再对像素做色调映射。 |
| 来源缺失,或来源、声明、参考互相冲突 | 标为未知;停止猜测传递特性、色域和范围,先找回原始文件或可信记录。 |
第二条路要求独立证据,例如产生该文件的受控 SDR 导出记录,或与可信 SDR 参考逐项核对的来源链。单凭“改标签后看起来顺眼”不够。第三条路保护原片,防止二次误处理。
若第二条路已经由受控 SDR 导出记录证明像素为 BT.709、有限范围,只是属性错误,可为新的重编码候选使用这一滤镜参数:
setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=limited
它只标记属性,不做像素变换;但只要作为 -vf 运行,画面就会经历解码、过滤与重新编码,必须另选视频编码器,可能产生有损代际变化,不能声称是流复制或无损容器头修复。保留原片,记录编码设置,再探测并实际观看候选。
用探测命令记录声明与工具可用性
先把输入文件路径写进记录,再运行只读探测:
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,pix_fmt,color_range,color_space,color_transfer,color_primaries -of json INPUT.mov
把原始 JSON 保存为“探测观察”,不要改写成“像素真相”。再记录当前构建和滤镜:
ffmpeg -hide_banner -version
ffmpeg -hide_banner -filters | grep -E '(^|[[:space:]])(zscale|tonemap|setparams)[[:space:]]'
FFmpeg 文档中,zscale 依赖构建时启用 libzimg;tonemap 期望浮点、线性光输入;setparams 只标记帧的色彩属性,不转换像素。转换顺序因此是:用已确认的输入传递与色彩信息完成线性化,在浮点线性光域做色调映射,再转换到明确的 BT.709 SDR 输出并编码。每个输入参数都来自当前素材的已确认记录,不能把手机品牌或“HDR”字样自动替换成某套色域、传递曲线或范围。
本文不提供把未知输入硬塞进固定参数的通用命令。本地写作环境的 FFmpeg 9.0.1 没有 zscale / libzimg,所以本文没有执行 HDR 转换,也没有验证任何转换输出。实际执行前先检查滤镜;缺少所需能力时,改用明确支持该输入与 SDR 输出的色彩管理工具,或团队批准的构建。
已确认 HDR 时,照这份参数映射做候选
下面是一份仅供文档说明、依赖具体构建、未执行的假设方案。它只适用于独立记录已经确认以下全部事实的素材:BT.2020 原色、BT.2020 非恒定亮度矩阵、PQ 传递、有限范围,实际信号峰值为 1000 cd/m²。本例为 zscale 选择 npl=100 这一标称峰值亮度参数。另一个独立的源码事实是:固定版 FFmpeg 的信号峰值辅助实现定义 REFERENCE_WHITE=100,并用 MaxCLL 或母版显示最大亮度除以该常量来确定归一化信号峰值。参数 npl 与归一化常量分别记录;本例采用相同数值,再据 1000/100 得到 peak=10。选择这套候选前提仍是本文的限定设计,不是从手机型号自动得出的通用输入。
| 已确认事实或作者选择 | 对应滤镜项与含义 |
|---|---|
| BT.2020 原色 | setparams 的 color_primaries=bt2020 标记已知输入;zscale 的 primariesin=2020 显式读取该输入。 |
| BT.2020-NCL 矩阵 | colorspace=bt2020nc 与 matrixin=2020_ncl 对应同一已确认矩阵。 |
| PQ 传递 | setparams 用 color_trc=smpte2084 标记已知 PQ。后续 zscale 没有猜写 transferin;按文档默认从输入属性取得传递特性,再以 transfer=linear 线性化。 |
| 有限范围 | range=limited 与 rangein=limited 来自独立来源记录,不由画面外观推测。 |
| 实际信号峰值 1000 cd/m²;本例 npl=100;实现常量 REFERENCE_WHITE=100 | npl=100 是本例选择的 zscale 标称峰值亮度参数;REFERENCE_WHITE=100 是该固定实现的独立归一化常量;tonemap 的 peak=10 来自本例 1000/100,单位为归一化信号比例。它们分别说明处理设置、实现常量与信号峰值。 |
| 作者选择 Mobius 做首个视觉候选 | tonemap=mobius 是待实际观看比较的创作选择,不是元数据推导结果,也不宣称是通用默认。 |
| 输出目标为 BT.709、有限范围、yuv420p | 最后一次 zscale 转到 709 原色/传递/矩阵与有限范围,format 转成 yuv420p,末尾 setparams 明确标记输出属性。 |
下面整行是传给 -vf 的滤镜参数本身,不是完整 ffmpeg 命令:
setparams=color_primaries=bt2020:color_trc=smpte2084:colorspace=bt2020nc:range=limited,zscale=primariesin=2020:matrixin=2020_ncl:rangein=limited:transfer=linear:npl=100,format=pix_fmts=gbrpf32le,tonemap=tonemap=mobius:peak=10,zscale=primaries=709:transfer=709:matrix=709:range=limited,format=pix_fmts=yuv420p,setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=limited
实际命令还必须在别处选择真正的视频编码器与新候选路径;使用 -vf 会解码、过滤并重新编码,不能搭配 -c:v copy。本文不拼装音频、容器或完整编码命令,因为这些取决于真实交接。先在目标机器确认 zscale 可用,再把以上整行作为 -vf 的一个参数用于新候选。输出后保存 ffprobe 观察,并在 SDR 播放链路逐项观看。此处没有运行结果;本地 FFmpeg 9.0.1 缺少 zscale/libzimg。输入色彩事实缺失或互相冲突时,回到素材类型“未知”分支。若色彩事实已确认是 HDR、只有实际峰值或其他转换参数待核实,则保留“已确认 HDR”状态,另记“数值转换方案待定”;先取得可信的峰值证据或明确审核的调色决策,再制定当前素材的方案,暂不照抄这张滤镜图。
原创纸面案例:雨后夜市短片的三路判断
下面的“雨棚下三十秒”是本文虚构的教学案例。没有真实媒体、转换、播放测试或成功结果;文件名与观察均为假设。
创作者要把手机拍摄的夜市片段放进普通 SDR 视频回顾。镜头从湿路面的灯笼倒影摇到摊主递出热饮,背景有白色价牌、红色雨棚和蒸汽。创作者说第一次导出后“整段发灰,灯笼又像被剪平”,但只保留聊天软件转存文件 market-share.mov。这个外观描述先记为症状,不据此宣布 HDR。
| 假设证据状态 | 决定与下一步 |
|---|---|
| 手机原片与拍摄记录找回,来源模式和文件声明一致确认 HDR | 保留原片;按已确认输入制作 SDR 候选。实际观看时检查摊主脸部和蒸汽的中间调、灯笼与价牌高光、湿路黑位,以及摇镜头前后亮度是否突跳。 |
| 受控 SDR 导出日志证明转存文件的像素已是正确 SDR,但文件被错误标记 | 复制到新候选,仅纠正已被证明错误的属性;复查声明并在 SDR 链路完整播放。没有独立日志就不能选这一路。 |
| 只剩转存文件,探测字段缺失或互相矛盾,原片与记录都找不到 | 状态写“未知”;不猜输入曲线,不用标签修复碰碰运气,也不执行 HDR 色调映射。请求原始相机文件或可信导出记录。 |
“修改前”决定是根据发灰外观直接换标签,把像素问题与声明问题混在一起。“修改后”决定是保存证据并进入三路之一。即使第一路生成候选,也只能写“等待 SDR 播放复核”;实际检查通过后才可交接。
真实 SDR 播放决定候选是否能交接
机械检查与观看检查分开记录。探测确认候选能读、输出声明完整、尺寸与时钟符合计划;实际播放确认内容是否可用。至少普通速度完整播放一次。
| 复核项 | 实际要看什么 |
|---|---|
| 中间调 | 人脸、墙面、蒸汽或阴影内主体是否被整体压暗或抬灰;与相邻 SDR 镜头是否连贯。 |
| 高光 | 灯具、窗户、白牌和反光是否出现突兀硬边、大片无层次区域或镜头间跳变;不承诺保存 HDR 全部峰值。 |
| 肤色与中性色 | 不凭“更鲜艳”验收;看肤色是否稳定,中性物是否无意外色偏。 |
| 黑白电平 | 黑位是否被压死或抬起,白位是否持续顶住;结合实际 SDR 范围与播放链路判断。 |
| 镜头序列 | 逐个过剪点和曝光变化,避免单镜头顺眼却造成全片亮度脉冲。 |
| 声音与时钟 | 听完整声音,核对时长、同步与已采用内容;色彩转换不授权顺带改剪辑或混音。 |
发现问题时回到当前候选的转换设置,另存下一候选。保留失败候选与记录,避免覆盖原片或把未经观看的最新文件误当成通过版本。
复制这份已验证 SDR 交接记录
来源与原片: 设备/模式/传输链;只读原片路径或哈希;可信参考。
探测观察: 输入 ffprobe 原始 JSON 路径;声明缺失或矛盾项。
决定与证据: 已确认 HDR 像素 / 已确认 SDR 像素但标签错误 / 未知;独立证据。
构建与滤镜: 工具版本;zscale、tonemap、setparams 或等价能力的实际可用性。
转换记录: 已确认输入;线性化、色调映射、BT.709 SDR 输出步骤与参数;或仅修标签的证据。
候选路径: 新文件路径或哈希;原片保持不动。
输出探测: 编解码、像素格式、范围、色彩空间、传递与原色声明。
实际观看: SDR 播放链;中间调、高光、肤色、中性色、黑白电平、镜头序列、声音与同步。
下游交接: 只有实际检查通过时,记录“已验证 SDR 候选”并交给普通视频回顾编辑;否则写待修或未知。
固定版 Video Recap 的普通装配路径可能复制视频,也可能为了字幕、遮挡、叠加或尺寸而编码 H.264 yuv420p;它没有本文所需的 HDR 色调映射链。透明前景合成路径更明确要求输入已经是带 BT.709 / TV 有限范围声明的 H.264 yuv420p 母版。因此先在外部完成并验证 SDR 候选,再把新文件作为普通编辑输入。原片、未知文件和未观看候选不进入这一步。
常见问题
ffprobe 显示 BT.2020 或 PQ,就能证明像素一定是 HDR 吗?
不能单独证明。它们是文件或码流声明,要与原始拍摄、导出或可信参考证据一起判断。声明可能缺失、错误或在转存中改变。
把 setparams 改成 BT.709 能修好所有发灰视频吗?
不能。setparams 标记属性,不改变像素。只有独立证据确认像素本来就是正确 SDR、问题仅在错误声明时,才走属性修正;确认 HDR 像素需要真实转换。
用 skill 来做
用 $video-recap 从这份已验证的 SDR 文件继续制作普通视频回顾。输入路径是我在交接记录中标为“已验证 SDR 候选”的新文件;请保留原始手机文件和转换记录,不把 HDR 转换当作该 skill 的原生能力。先读取实际素材并规划剪辑、旁白、字幕与成片,再生成新输出;报告使用的 SDR 候选版本和仍需人工观看、试听的项目。
查看具体方法: Video Recap 普通装配与编码边界 · 透明前景合成要求已准备好的 BT.709 SDR 母版 · ffprobe 官方文档 · FFmpeg zscale 官方滤镜文档 · FFmpeg tonemap 官方滤镜文档 · FFmpeg setparams 官方滤镜文档 · FFmpeg 固定版参考白常量 · FFmpeg 固定版归一化信号峰值计算