基于分辨率判定的FFmpeg色彩空间保留脚本方案是否可行?
FFmpeg色彩空间保留脚本的评估与优化建议
我正尝试在FFmpeg脚本中实现逻辑,确保视频在upscale时始终保留原始色彩空间。仅设置元数据似乎即可实现这一点,但难点在于确定所需的元数据,尤其是当源视频的色彩空间及相关色彩数据显示为
unknown时,这种情况在我的许多源视频中十分常见。据我理解,视频的原始色彩空间由两个因素决定:视频是标清还是高清;若为标清,则是NTSC还是PAL/SECAM格式。基于此,我编写了以下逻辑,通过检测视频高度来设置对应的色彩空间:
height=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=nw=1:nk=1 "$1" | tr -d $'\r') colour_space=$(ffprobe -v error -select_streams v:0 -show_entries stream=color_space -of default=nw=1:nk=1 "$1" | tr -d $'\r') # If input is standard definition and colourspace is BT601 (NTSC) if [[ $height -lt 720 && $colour_space == "smpte170m" ]]; then colour_metadata="-colorspace smpte170m -color_trc smpte170m -color_primaries smpte170m" # set metadata to BT601 (NTSC) # If input is standard definition and colourspace is BT601 (PAL and SECAM) or unknown elif [[ $height -lt 720 && ($colour_space == "bt470bg" || $colour_space == "unknown") ]]; then colour_metadata="-colorspace bt470bg -color_trc gamma28 -color_primaries bt470bg" # set metadata to superior/more common PAL/SECAM elif [[ $height -ge 720 ]]; then # If input is high definition colour_metadata="-colorspace bt709 -color_trc bt709 -color_primaries bt709" # set metadata to BT.709 else echo "Unrecognised colorspace $color_space detected, leaving colour untouched" fi请问该方案是否适用于大多数视频?是否存在可改进的问题,或是我遗漏了某些导致方案完全失效的因素?
方案可行性评估
你的方案在绝大多数传统广播电视场景下是有效的,能覆盖常见的NTSC/PAL标清、BT.709高清内容,处理unknown色彩空间的标清视频时,默认选用bt470bg的策略也符合行业普遍情况。
现有问题与改进点
- 核心变量错误:脚本中误将视频
width赋值给height变量,导致分辨率判断完全颠倒。修正为获取视频高度:height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=nw=1:nk=1 "$1" | tr -d $'\r') - 色彩参数匹配错误:
- smpte170m(NTSC)对应的色彩传递函数应为
bt1886,而非smpte170m,否则会导致亮度偏差; - bt470bg的标准传递函数是
bt1886,不是gamma28——gamma28是旧标准,现代设备普遍适配BT.1886,用gamma28会让画面偏暗;
- smpte170m(NTSC)对应的色彩传递函数应为
- 变量拼写错误:else分支中的
$color_space少了字母u,应改为$colour_space,否则会输出空值。
可能遗漏的失效场景
- 非标准分辨率内容:
- 部分VGA分辨率(640x480)的视频可能是BT.709色彩空间(比如早期数字拍摄的网络内容),会被误判为标清BT.601;
- 专业影视高清/4K视频可能使用BT.2020色彩空间,脚本会强制设为BT.709,导致色彩失真;
- HDR视频:若源视频是HLG或PQ传递函数的HDR内容,脚本会强制设置为SDR的BT.709参数,完全破坏HDR效果;
- 分辨率与色彩空间不匹配:有些标清视频是按BT.709制作的,脚本会错误套用BT.601参数。
优化后的脚本示例
优先信任源视频的已知元数据,仅在元数据未知时用分辨率+帧率辅助判断:
# 获取视频核心参数 height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=nw=1:nk=1 "$1" | tr -d $'\r') colour_space=$(ffprobe -v error -select_streams v:0 -show_entries stream=color_space -of default=nw=1:nk=1 "$1" | tr -d $'\r') colour_trc=$(ffprobe -v error -select_streams v:0 -show_entries stream=color_trc -of default=nw=1:nk=1 "$1" | tr -d $'\r') colour_primaries=$(ffprobe -v error -select_streams v:0 -show_entries stream=color_primaries -of default=nw=1:nk=1 "$1" | tr -d $'\r') # 优先使用已知元数据 if [[ $colour_space != "unknown" && $colour_trc != "unknown" && $colour_primaries != "unknown" ]]; then colour_metadata="-colorspace $colour_space -color_trc $colour_trc -color_primaries $colour_primaries" else # 元数据未知时用分辨率+帧率兜底 if [[ $height -lt 720 ]]; then # 通过帧率判断NTSC/PAL fps=$(ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=nw=1:nk=1 "$1" | tr -d $'\r') if [[ $fps == "30000/1001" || $colour_space == "smpte170m" ]]; then colour_metadata="-colorspace smpte170m -color_trc bt1886 -color_primaries smpte170m" else colour_metadata="-colorspace bt470bg -color_trc bt1886 -color_primaries bt470bg" fi elif [[ $height -ge 720 && $height -lt 2160 ]]; then colour_metadata="-colorspace bt709 -color_trc bt1886 -color_primaries bt709" elif [[ $height -ge 2160 ]]; then # 4K及以上优先匹配BT.2020 if [[ $colour_space == "bt2020nc" || $colour_space == "bt2020c" ]]; then colour_metadata="-colorspace $colour_space -color_trc $colour_trc -color_primaries bt2020" else colour_metadata="-colorspace bt2020nc -color_trc bt1886 -color_primaries bt2020" fi else echo "Unrecognised video dimensions or colorspace detected, leaving colour untouched" colour_metadata="" fi fi
内容的提问来源于stack exchange,提问作者Hashim Aziz
相关产品推荐
相关产品推荐

