Keywords: Vapoursynth 修复 灰阶 错误 视频 Gray scale range color
查看对比
起因:前几天朋友发给我一段直播源,问我视频的灰阶是不是有点怪。我点开一看,确实是有些偏白,起先还以为是舞台干冰的效果,直到画面切换时,查看黑点的 RGB 值居然为 (16,16,16)。综合判断,我估计视频的灰阶范围只有 16~235,这才导致画面“黑”不下来,也“亮”不上去。
错误的黑阶范围严重影响了观感,我决定尝试修复。我使用的方式是编写 Vapoursynth 脚本将 16-235 的灰阶范围扩展成 0-255,最后输出给 x264 转码(电脑性能有限,x265 速度比较慢)以实现最终目的。
首先,你需要有一个 Vapoursynth
环境和 Vapoursynth
脚本编辑器,安装教程可以在 Google 上查看。
我使用的是 VapourSynth-Editor,可以在 Github 上找到。在视频同目录下新建脚本 Untitled.vpy
,先导入库和视频,接着,我尝试如下代码,把 limited 扩展到 full:
from vapoursynth import core
src = core.lsmas.LWLibavSource(r"video.mp4")
#expand limited to full
clip = fvsfunc.Depth(someinput, bits, range_in='limited', range='full')
按 F5
预览,结果却没有变化。再次分析,发现问题并不是出在范围上。查看一下 MediaInfo:
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L4
Format settings : CABAC / 1 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 1 frame
Format settings, GOP : M=1, N=60
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 1 h 32 min
Bit rate : 4 855 kb/s
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate mode : Variable
Frame rate : 30.000 FPS
Minimum frame rate : 29.412 FPS
Maximum frame rate : 30.303 FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.078
Stream size : 3.13 GiB (97%)
Color range : Limited
Color primaries : BT.601 NTSC
Transfer characteristics : BT.601
Matrix coefficients : BT.601
Codec configuration box : avcC
可以看到 Color range
并没有问题,不知道直播前视频流经过了什么错误转换,导致从 YUV 格式转回 RGB 后,范围还是有问题,和 Color range
无关。于是我决定使用数学表达式,将 16-235 变换到 0-255。这里请教一下 ChatGPT:
通过一番沟通,得到了如下的代码:
# 转换YUV420P8,bt601到RGB24
import vapoursynth as vs
rgb_clip = core.resize.Bicubic(src, format=vs.RGB24, matrix_in_s="470bg", transfer_in_s="601", primaries_in_s="170m", range_in_s="limited")
# RGB16~235到0~255的线性拉升
def rescale_value(value):
return (value - 16) * 255 / (235 - 16)
expr = "x {0} - {1} * {2} /".format(16, 255, (235 - 16))
# 处理拉升
rescaled_clip = core.std.Expr(rgb_clip, [expr, expr, expr])
# 转回YUV空间
output_clip = core.resize.Bicubic(rescaled_clip, format=vs.YUV420P8, matrix_s="709", transfer_s="709", primaries_s="709", range_s="full")
这里要注意,由于视频流的 Color primaries
Transfer characteristics
Matrix coefficients
比较特殊,因此要额外注意第 3 行的参数。
最终得到的代码如下:
from vapoursynth import core
from fvsfunc import Depth
core.max_cache_size = 12000
src = core.lsmas.LWLibavSource(r"pre.mp4")
# 转换YUV420P8,bt601到RGB24
import vapoursynth as vs
rgb_clip = core.resize.Bicubic(src, format=vs.RGB24, matrix_in_s="470bg", transfer_in_s="601", primaries_in_s="170m", range_in_s="limited")
# RGB16~235到0~255的线性拉升
def rescale_value(value):
return (value - 16) * 255 / (235 - 16)
expr = "x {0} - {1} * {2} /".format(16, 255, (235 - 16))
# 处理拉升
rescaled_clip = core.std.Expr(rgb_clip, [expr, expr, expr])
# 转回YUV空间
output_clip = core.resize.Bicubic(rescaled_clip, format=vs.YUV420P8, matrix_s="709", transfer_s="709", primaries_s="709", range_s="full")
out.set_output()
尝试预览:
成功!
对比滑块
最后,使用命令行将 Vapoursynth 的输出传递给 x264,就可以得到一个仅包含视频流的.h264
文件。
vspipe --y4m Untitled.vpy - | x264 --demuxer y4m --preset slow -o output_video.h264 -
当然,你也可以修改 x264 的参数以提升压缩的视频质量,像这样:
vspipe --y4m Untitled.vpy - | x264 --demuxer y4m --cabac=1 --ref=4 --deblock=1:0:0 --analyse=0x3:0x133 --me=umh --subme=10 --psy=1 --psy_rd=1.00:0.00 --mixed_ref=1 --me_range=24 --chroma_me=1 --trellis=2 --8x8dct=1 --cqm=0 --deadzone=21,11 --fast_pskip=0 --chroma_qp_offset=-2 --threads=9 --lookahead_threads=1 --sliced_threads=0 --nr=0 --decimate=0 --interlaced=0 --bluray_compat=0 --constrained_intra=0 --bframes=8 --b_pyramid=2 --b_adapt=2 --b_bias=0 --direct=3 --weightb=1 --open_gop=0 --weightp=2 --keyint=300 --keyint_min=1 --scenecut=40 --intra_refresh=0 --rc_lookahead=60 --rc=crf --mbtree=1 --crf=17.0 --qcomp=0.70 --qpmin=0 --qpmax=32 --qpstep=4 --ip_ratio=1.40 --aq=3:1.00 -o output_video.h264 -
最后使用 ffmpeg 提取原视频音轨并与新的视频流封装:
ffmpeg -i video.mp4 -vn -acodec copy audio.m4a
ffmpeg -i output_video.h264 -i audio.m4a -c copy output.mp4
鸣谢:Kukoc Ryougi
Comments 2 条评论
博主 ■■■■■■
好!
(⌒▽⌒)
博主 CircleCrop
@■■■■■■ V●ᴥ●V