Enhance Avisynth video workflow and metadata tools
This commit is contained in:
+409
-64
@@ -4,18 +4,43 @@
|
||||
# small and dependency-light unless the visible scripts explicitly document the
|
||||
# required plugins.
|
||||
|
||||
function MBT_MarkSource(clip c, int source_id, int "matrix")
|
||||
function MBT_MarkSource(clip c, int source_id, int "matrix", int "primaries", int "transfer", int "color_range", float "hdr_peak", float "absolute_timestamp_end_seconds", float "source_duration_seconds")
|
||||
{
|
||||
# Attach source identity to each frame. Python reads these properties after
|
||||
# running the user-edited script and maps frames back to ffprobe timestamps.
|
||||
# Timestamp/duration variables are supplied by generated ConditionalReader
|
||||
# files when available.
|
||||
matrix = Default(matrix, MBT_GetMatrixCode(c))
|
||||
# Timing values are attached separately after ConditionalReader has supplied
|
||||
# their per-frame variables.
|
||||
matrix = Defined(matrix) ? matrix : 2
|
||||
primaries = Defined(primaries) ? primaries : 2
|
||||
transfer = Defined(transfer) ? transfer : 2
|
||||
color_range = Defined(color_range) ? color_range : 0
|
||||
hdr_peak = Default(hdr_peak, 1000.0)
|
||||
absolute_timestamp_end_seconds = Default(absolute_timestamp_end_seconds, 0.0)
|
||||
source_duration_seconds = Default(source_duration_seconds, 0.0)
|
||||
runtime = """
|
||||
last.propSet("mbt_source_id", """ + String(source_id) + """).\
|
||||
propSet("mbt_source_frame", current_frame).\
|
||||
propSet("mbt_drop_frame", 0).\
|
||||
propSet("mbt_absolute_timestretch", 1.0).\
|
||||
propSet("mbt_absolute_timestamp_end_seconds", """ + String(absolute_timestamp_end_seconds) + """).\
|
||||
propSet("mbt_source_duration_seconds", """ + String(source_duration_seconds) + """).\
|
||||
propSet("mbt_absolute_timestamp_start_seconds", """ + String(absolute_timestamp_end_seconds - source_duration_seconds) + """).\
|
||||
propSet("_Matrix", """ + String(matrix) + """).\
|
||||
propSet("mbt_hdr_peak", """ + String(hdr_peak) + """).\
|
||||
propSet("_Primaries", """ + String(primaries) + """).\
|
||||
propSet("_Transfer", """ + String(transfer) + """).\
|
||||
propSet("_ColorRange", """ + String(color_range) + """)
|
||||
"""
|
||||
source = c.PropSet("mbt_hdr_peak", hdr_peak).\
|
||||
MBT_SetColor(MBT_MatrixNameFromCode(matrix), primaries, transfer, color_range)
|
||||
return source.ScriptClip(runtime)
|
||||
}
|
||||
|
||||
function MBT_MarkTiming(clip c)
|
||||
{
|
||||
runtime = """
|
||||
source_start = propGetFloat("mbt_absolute_timestamp_start_seconds")
|
||||
last.propSet("mbt_absolute_timestamp_seconds", source_start + mbt_frame_time_seconds).\
|
||||
propSet("mbt_frame_time_seconds", mbt_frame_time_seconds).\
|
||||
propSet("mbt_relative_timestamp", mbt_relative_timestamp).\
|
||||
propSet("mbt_absolute_timestamp", mbt_absolute_timestamp).\
|
||||
@@ -25,6 +50,86 @@ function MBT_MarkSource(clip c, int source_id, int "matrix")
|
||||
return c.ScriptClip(runtime)
|
||||
}
|
||||
|
||||
function MBT_AbsoluteTimeStretch(clip c, float factor)
|
||||
{
|
||||
Assert(factor > 0.0, "MBT_AbsoluteTimeStretch factor must be greater than zero.")
|
||||
runtime = """
|
||||
source_end = propGetFloat("mbt_absolute_timestamp_end_seconds")
|
||||
source_duration = propGetFloat("mbt_source_duration_seconds")
|
||||
previous_factor = propGetFloat("mbt_absolute_timestretch")
|
||||
total_factor = previous_factor * """ + String(factor) + """
|
||||
Assert(source_end > 0.0 && source_duration > 0.0, "MBT_AbsoluteTimeStretch requires source end timestamp and duration metadata.")
|
||||
source_start = source_end - source_duration * total_factor
|
||||
stretched_timestamp = source_start + mbt_frame_time_seconds * total_factor
|
||||
last.propSet("mbt_absolute_timestamp_start_seconds", source_start).\
|
||||
propSet("mbt_absolute_timestamp_seconds", stretched_timestamp).\
|
||||
propSet("mbt_absolute_timestamp", MBT_FormatUtcTimestamp(stretched_timestamp)).\
|
||||
propSet("mbt_absolute_timestretch", total_factor)
|
||||
"""
|
||||
return c.ScriptClip(runtime)
|
||||
}
|
||||
|
||||
function MBT_IsLeapYear(int year)
|
||||
{
|
||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
|
||||
}
|
||||
|
||||
function MBT_DaysInYear(int year)
|
||||
{
|
||||
return MBT_IsLeapYear(year) ? 366 : 365
|
||||
}
|
||||
|
||||
function MBT_DaysInMonth(int year, int month)
|
||||
{
|
||||
return month == 2 ? (MBT_IsLeapYear(year) ? 29 : 28)
|
||||
\ : (month == 4 || month == 6 || month == 9 || month == 11) ? 30 : 31
|
||||
}
|
||||
|
||||
function MBT_YearFromEpochDays(int days, int "year")
|
||||
{
|
||||
year = Default(year, 1970)
|
||||
return days < MBT_DaysInYear(year) ? year : MBT_YearFromEpochDays(days - MBT_DaysInYear(year), year + 1)
|
||||
}
|
||||
|
||||
function MBT_DayOfYear(int days, int "year")
|
||||
{
|
||||
year = Default(year, 1970)
|
||||
return days < MBT_DaysInYear(year) ? days : MBT_DayOfYear(days - MBT_DaysInYear(year), year + 1)
|
||||
}
|
||||
|
||||
function MBT_MonthFromDayOfYear(int year, int day, int "month")
|
||||
{
|
||||
month = Default(month, 1)
|
||||
return day < MBT_DaysInMonth(year, month) ? month : MBT_MonthFromDayOfYear(year, day - MBT_DaysInMonth(year, month), month + 1)
|
||||
}
|
||||
|
||||
function MBT_DayOfMonth(int year, int day, int "month")
|
||||
{
|
||||
month = Default(month, 1)
|
||||
return day < MBT_DaysInMonth(year, month) ? day + 1 : MBT_DayOfMonth(year, day - MBT_DaysInMonth(year, month), month + 1)
|
||||
}
|
||||
|
||||
function MBT_Pad(int value, int width)
|
||||
{
|
||||
text = String(value)
|
||||
return StrLen(text) >= width ? text : "0" + MBT_Pad(value, width - 1)
|
||||
}
|
||||
|
||||
function MBT_FormatUtcTimestamp(float timestamp)
|
||||
{
|
||||
whole_seconds = Int(Floor(timestamp))
|
||||
microseconds = Round((timestamp - whole_seconds) * 1000000.0)
|
||||
whole_seconds = microseconds >= 1000000 ? whole_seconds + 1 : whole_seconds
|
||||
microseconds = microseconds >= 1000000 ? 0 : microseconds
|
||||
days = Int(Floor(whole_seconds / 86400.0))
|
||||
day_seconds = whole_seconds - days * 86400
|
||||
year = MBT_YearFromEpochDays(days)
|
||||
day = MBT_DayOfYear(days)
|
||||
month = MBT_MonthFromDayOfYear(year, day)
|
||||
return MBT_Pad(year, 4) + "-" + MBT_Pad(month, 2) + "-" + MBT_Pad(MBT_DayOfMonth(year, day), 2) + "T" + \
|
||||
MBT_Pad(day_seconds / 3600, 2) + ":" + MBT_Pad((day_seconds % 3600) / 60, 2) + ":" + MBT_Pad(day_seconds % 60, 2) + "." + MBT_Pad(microseconds, 6) + "Z"
|
||||
}
|
||||
|
||||
function MBT_AudioSource(clip video, string source_path, string audio_cache_path)
|
||||
{
|
||||
audio = FFAudioSource(source_path, cachefile=audio_cache_path)
|
||||
@@ -94,12 +199,17 @@ function MBT_Info(clip c, int "size", int "align")
|
||||
align = Default(align, 7)
|
||||
runtime = """
|
||||
drop_value = propGetInt("mbt_drop_frame") == 0 ? "False" : "True"
|
||||
matrix = MBT_MatrixNameFromCode(propGetInt("_Matrix"))
|
||||
transfer = propGetInt("_Transfer")
|
||||
transfer_name = transfer == 16 ? "PQ" : (transfer == 18 ? "HLG" : "SDR")
|
||||
range_name = propGetInt("_ColorRange") == 1 ? "full range" : "limited range"
|
||||
text = "Absolute timestamp: " + propGetString("mbt_absolute_timestamp") + Chr(10) + \
|
||||
"Relative timestamp: " + propGetString("mbt_relative_timestamp") + Chr(10) + \
|
||||
Chr(10) + \
|
||||
"Source frame: " + String(propGetInt("mbt_source_frame")) + Chr(10) + \
|
||||
"Frame duration: " + propGetString("mbt_frame_duration") + Chr(10) + \
|
||||
"Drop frame: " + drop_value
|
||||
"Drop frame: " + drop_value + Chr(10) + \
|
||||
"Color: " + matrix + ", " + transfer_name + ", " + range_name
|
||||
Subtitle(last, text, size=""" + String(size) + """, align=""" + String(align) + """)
|
||||
"""
|
||||
return c.ScriptClip(runtime)
|
||||
@@ -176,8 +286,8 @@ function Resize(clip v, int "w", int "h", float "dar", float "xcrop", float "ycr
|
||||
crop_w = cropped_w - crop_extra_l - crop_extra_r
|
||||
crop_h = cropped_h - crop_extra_t - crop_extra_b
|
||||
|
||||
input_matrix = Default(input_matrix, v.IsRGB ? MBT_DefaultMatrix(wo, ho) : MBT_GetMatrixName(v))
|
||||
output_matrix = Default(output_matrix, MBT_DefaultMatrix(w, h))
|
||||
input_matrix = Default(input_matrix, v.IsRGB ? MBT_DefaultMatrix(wo, ho) : mbt_color_matrix)
|
||||
output_matrix = Default(output_matrix, MBT_DefaultOutputMatrix(w, h))
|
||||
return v.MBT_LinearResize(w, h, crop_l, crop_t, crop_w, crop_h, linear=linear, input_matrix=input_matrix, output_matrix=output_matrix)
|
||||
}
|
||||
|
||||
@@ -200,51 +310,85 @@ function MBT_LinearResize(clip src, int tw, int th,
|
||||
p = Default(p , 30.0)
|
||||
bitdepth = Default(bitdepth , src.BitsPerComponent)
|
||||
linear = Defined(linear) ? linear : (sw / Float(tw) >= 1.5 || sh / Float(th) >= 1.5)
|
||||
input_matrix = Default(input_matrix, src.IsRGB ? MBT_DefaultMatrix(src.Width, src.Height) : MBT_GetMatrixName(src))
|
||||
output_matrix = Default(output_matrix, MBT_DefaultMatrix(tw, th))
|
||||
Assert(
|
||||
\ !linear || (FunctionExists("y_gamma_to_linear") && FunctionExists("y_linear_to_gamma")),
|
||||
\ "Resize(linear=true) requires y_gamma_to_linear and y_linear_to_gamma. Load the missing dependency or call Resize(..., linear=false)."
|
||||
\)
|
||||
input_matrix = Default(input_matrix, src.IsRGB ? MBT_DefaultMatrix(src.Width, src.Height) : mbt_color_matrix)
|
||||
output_matrix = Default(output_matrix, MBT_DefaultOutputMatrix(tw, th))
|
||||
|
||||
clp = (src.IsRGB ? (src.HasAlpha ? src.ConvertToPlanarRGBA
|
||||
\ : src.ConvertToPlanarRGB)
|
||||
\ : src.ConvertToPlanarRGB(matrix=input_matrix))
|
||||
clp = clp.ConvertBits(32)
|
||||
return MBT_IsHDR()
|
||||
\ ? (linear
|
||||
\ ? src.MBT_HDRLinearResize(tw, th, sl, st, sw, sh, hkernel, vkernel, b, c, taps, p, bitdepth, input_matrix, output_matrix)
|
||||
\ : src.MBT_HDRResize(tw, th, sl, st, sw, sh, hkernel, vkernel, b, c, taps, p, input_matrix, output_matrix))
|
||||
\ : src.MBT_SDRResize(tw, th, sl, st, sw, sh, hkernel, vkernel, b, c, taps, p, bitdepth, linear, input_matrix, output_matrix)
|
||||
}
|
||||
|
||||
function MBT_HDRResize(clip src, int tw, int th, float sl, float st, float sw, float sh,
|
||||
\ string hkernel, string vkernel, float b, float c, int "taps", float "p",
|
||||
\ string "input_matrix", string "output_matrix")
|
||||
{
|
||||
Assert(input_matrix == output_matrix,
|
||||
\ "HDR Resize preserves its color system. Use MBT_ToSDR before Resize to change it.")
|
||||
return src.MBT_ResizePlanes(tw, th, sl, st, sw, sh, hkernel, vkernel, b, c, taps, p).PropCopy(src)
|
||||
}
|
||||
|
||||
function MBT_SDRResize(clip src, int tw, int th, float sl, float st, float sw, float sh,
|
||||
\ string hkernel, string vkernel, float b, float c, int "taps", float "p", int "bitdepth",
|
||||
\ bool "linear", string "input_matrix", string "output_matrix")
|
||||
{
|
||||
Assert(!linear || (FunctionExists("y_gamma_to_linear") && FunctionExists("y_linear_to_gamma")),
|
||||
\ "Resize(linear=true) requires y_gamma_to_linear and y_linear_to_gamma. Load the missing dependency or call Resize(..., linear=false).")
|
||||
clp = (src.IsRGB ? (src.HasAlpha ? src.ConvertToPlanarRGBA : src.ConvertToPlanarRGB) : src.ConvertToPlanarRGB(matrix=input_matrix)).ConvertBits(32)
|
||||
clp = linear ? clp.y_gamma_to_linear : clp
|
||||
|
||||
if (hkernel != vkernel) {
|
||||
htaps = Default(taps, (hkernel == "Lanczos" ? 3 : 4))
|
||||
vtaps = Default(taps, (vkernel == "Lanczos" ? 3 : 4))
|
||||
clp = clp.MBT_LinearResize(tw, src.Height, sl, 0, sw, 0, hkernel, b, c, htaps, p, linear=false, input_matrix=input_matrix, output_matrix=input_matrix)
|
||||
clp = clp.MBT_LinearResize(tw, th, 0, st, 0, sh, vkernel, b, c, vtaps, p, linear=false, input_matrix=input_matrix, output_matrix=output_matrix)
|
||||
}
|
||||
else {
|
||||
taps = Default(taps, (hkernel == "Lanczos" ? 3 : 4))
|
||||
clp =
|
||||
\ (hkernel == "Bicubic" ) ? clp.BicubicResize(tw, th, b=b, c=c, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Bilinear" ) ? clp.BilinearResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Blackman" ) ? clp.BlackmanResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, taps=taps)
|
||||
\ : (hkernel == "Gauss" ) ? clp.GaussResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, p=p)
|
||||
\ : (hkernel == "Lanczos" ) ? clp.LanczosResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, taps=taps)
|
||||
\ : (hkernel == "Lanczos4" ) ? clp.Lanczos4Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Point" ) ? clp.PointResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Sinc" ) ? clp.SincResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, taps=taps)
|
||||
\ : (hkernel == "Spline16" ) ? clp.Spline16Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Spline36" ) ? clp.Spline36Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Spline64" ) ? clp.Spline64Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "CatmullRom" ) ? clp.BicubicResize(tw, th, b=0.0, c=0.5, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : Assert(false, "Invalid resize kernel.")
|
||||
}
|
||||
|
||||
clp = clp.MBT_ResizePlanes(tw, th, sl, st, sw, sh, hkernel, vkernel, b, c, taps, p)
|
||||
clp = linear ? clp.y_linear_to_gamma : clp
|
||||
clp = src.IsRGB ? (src.HasAlpha ? clp.ConvertToPlanarRGBA : clp.ConvertToPlanarRGB)
|
||||
\ : (src.Is420 ? clp.ConvertToYUV420(matrix=output_matrix).ConvertBits(bitdepth).MBT_SetMatrix(output_matrix)
|
||||
\ : (src.Is422 ? clp.ConvertToYUV422(matrix=output_matrix).ConvertBits(bitdepth).MBT_SetMatrix(output_matrix)
|
||||
\ : (src.Is444 ? clp.ConvertToYUV444(matrix=output_matrix).ConvertBits(bitdepth).MBT_SetMatrix(output_matrix) : clp.ConvertBits(bitdepth).MBT_SetMatrix(output_matrix))))
|
||||
clp = src.IsRGB ? clp.ConvertBits(bitdepth) : clp
|
||||
\ : (src.Is420 ? clp.ConvertToYUV420(matrix=output_matrix)
|
||||
\ : (src.Is422 ? clp.ConvertToYUV422(matrix=output_matrix) : clp.ConvertToYUV444(matrix=output_matrix)))
|
||||
global mbt_color_matrix = output_matrix
|
||||
global mbt_color_primaries = MBT_PrimariesForMatrix(output_matrix)
|
||||
global mbt_color_transfer = 1
|
||||
return src.IsRGB ? clp.ConvertBits(bitdepth).PropCopy(src) : clp.ConvertBits(bitdepth).PropCopy(src).MBT_SetSDRColor(output_matrix, mbt_color_range)
|
||||
}
|
||||
|
||||
return clp
|
||||
function MBT_HDRLinearResize(clip src, int tw, int th, float sl, float st, float sw, float sh,
|
||||
\ string hkernel, string vkernel, float b, float c, int "taps", float "p", int "bitdepth",
|
||||
\ string "input_matrix", string "output_matrix")
|
||||
{
|
||||
Assert(!src.IsRGB, "HDR Resize currently requires planar YUV input.")
|
||||
Assert(input_matrix == output_matrix,
|
||||
\ "HDR Resize preserves its color system. Use MBT_ToSDR before Resize to change it.")
|
||||
Assert(mbt_color_primaries == 9,
|
||||
\ "HDR Resize(linear=true) currently requires Rec2020 primaries. P3 HDR needs mastering-primary support.")
|
||||
Assert(FunctionExists("ConvertYUVtoLinearRGB") && FunctionExists("ConvertLinearRGBtoYUV"),
|
||||
\ "HDR Resize(linear=true) requires HDRTools. Load HDRTools or call Resize(..., linear=false).")
|
||||
clp = src.MBT_LinearHDR(MBT_HDRMode(), mbt_color_range)
|
||||
clp = clp.MBT_ResizePlanes(tw, th, sl, st, sw, sh, hkernel, vkernel, b, c, taps, p)
|
||||
clp = clp.ConvertLinearRGBtoYUV(Color=0, OutputMode=MBT_YuvOutputMode(src), HDRMode=MBT_HDRMode(), OOTF=false, fullrange=mbt_color_range == 1)
|
||||
return clp.ConvertBits(bitdepth).PropCopy(src).MBT_SetColor(input_matrix, mbt_color_primaries, mbt_color_transfer, mbt_color_range)
|
||||
}
|
||||
|
||||
function MBT_ResizePlanes(clip clp, int tw, int th, float sl, float st, float sw, float sh,
|
||||
\ string hkernel, string vkernel, float b, float c, int "taps", float "p")
|
||||
{
|
||||
if (hkernel != vkernel) {
|
||||
htaps = Default(taps, hkernel == "Lanczos" ? 3 : 4)
|
||||
vtaps = Default(taps, vkernel == "Lanczos" ? 3 : 4)
|
||||
clp = clp.MBT_ResizePlanes(tw, clp.Height, sl, 0, sw, clp.Height, hkernel, hkernel, b, c, htaps, p)
|
||||
return clp.MBT_ResizePlanes(tw, th, 0, st, clp.Width, sh, vkernel, vkernel, b, c, vtaps, p)
|
||||
}
|
||||
taps = Default(taps, hkernel == "Lanczos" ? 3 : 4)
|
||||
return
|
||||
\ (hkernel == "Bicubic" ) ? clp.BicubicResize(tw, th, b=b, c=c, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Bilinear" ) ? clp.BilinearResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Blackman" ) ? clp.BlackmanResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, taps=taps)
|
||||
\ : (hkernel == "Gauss" ) ? clp.GaussResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, p=p)
|
||||
\ : (hkernel == "Lanczos" ) ? clp.LanczosResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, taps=taps)
|
||||
\ : (hkernel == "Lanczos4" ) ? clp.Lanczos4Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Point" ) ? clp.PointResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Sinc" ) ? clp.SincResize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh, taps=taps)
|
||||
\ : (hkernel == "Spline16" ) ? clp.Spline16Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Spline36" ) ? clp.Spline36Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "Spline64" ) ? clp.Spline64Resize(tw, th, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : (hkernel == "CatmullRom" ) ? clp.BicubicResize(tw, th, b=0.0, c=0.5, src_left=sl, src_top=st, src_width=sw, src_height=sh)
|
||||
\ : Assert(false, "Invalid resize kernel.")
|
||||
}
|
||||
|
||||
function MBT_DefaultMatrix(int w, int h)
|
||||
@@ -252,6 +396,58 @@ function MBT_DefaultMatrix(int w, int h)
|
||||
return (w >= 3840 || h >= 2160) ? "Rec2020" : ((w >= 1280 || h >= 720) ? "Rec709" : "Rec601")
|
||||
}
|
||||
|
||||
function MBT_IsHDR()
|
||||
{
|
||||
return mbt_color_transfer == 16 || mbt_color_transfer == 18
|
||||
}
|
||||
|
||||
function MBT_DefaultOutputMatrix(int w, int h)
|
||||
{
|
||||
return MBT_IsHDR() ? mbt_color_matrix : MBT_DefaultMatrix(w, h)
|
||||
}
|
||||
|
||||
function MBT_GetPrimariesCode(clip c)
|
||||
{
|
||||
primaries = c.PropGetInt("_Primaries")
|
||||
return primaries == 0 ? 2 : primaries
|
||||
}
|
||||
|
||||
function MBT_GetTransferCode(clip c)
|
||||
{
|
||||
transfer = c.PropGetInt("_Transfer")
|
||||
return transfer == 0 ? 2 : transfer
|
||||
}
|
||||
|
||||
function MBT_GetRangeCode(clip c)
|
||||
{
|
||||
return c.PropGetInt("_ColorRange")
|
||||
}
|
||||
|
||||
function MBT_PrimariesForMatrix(string matrix)
|
||||
{
|
||||
return matrix == "Rec2020" ? 9 : 1
|
||||
}
|
||||
|
||||
function MBT_SDRColorForMatrix(string matrix)
|
||||
{
|
||||
return matrix == "Rec2020" ? 1 : (matrix == "Rec601" ? 3 : 2)
|
||||
}
|
||||
|
||||
function MBT_YuvOutputMode(clip c)
|
||||
{
|
||||
return c.Is420 ? 2 : (c.Is422 ? 1 : 0)
|
||||
}
|
||||
|
||||
function MBT_LinearHDR(clip c, int hdr_mode, int color_range)
|
||||
{
|
||||
return c.ConvertYUVtoLinearRGB(Color=0, OutputMode=2, HDRMode=hdr_mode, OOTF=false, fullrange=color_range == 1)
|
||||
}
|
||||
|
||||
function MBT_HDRMode()
|
||||
{
|
||||
return mbt_color_transfer == 18 ? 2 : 0
|
||||
}
|
||||
|
||||
function MBT_MatrixNameFromCode(int matrix)
|
||||
{
|
||||
return (matrix == 1) ? "Rec709"
|
||||
@@ -278,33 +474,182 @@ function MBT_MatrixInt(string matrix)
|
||||
\ : 2
|
||||
}
|
||||
|
||||
function MBT_GetMatrixCode(clip c)
|
||||
{
|
||||
matrix = MBT_MatrixNameFromCode(c.PropGetInt("_Matrix"))
|
||||
return (matrix == "") ? MBT_MatrixInt(MBT_DefaultMatrix(c.Width, c.Height)) : c.PropGetInt("_Matrix")
|
||||
}
|
||||
|
||||
function MBT_GetMatrixName(clip c)
|
||||
{
|
||||
matrix = MBT_MatrixNameFromCode(MBT_GetMatrixCode(c))
|
||||
return (matrix == "") ? MBT_DefaultMatrix(c.Width, c.Height) : matrix
|
||||
}
|
||||
|
||||
function MBT_SetMatrix(clip c, string matrix)
|
||||
{
|
||||
return c.PropSet("_Matrix", MBT_MatrixInt(matrix))
|
||||
}
|
||||
|
||||
function MBT_SetColor(clip c, string matrix, int primaries, int transfer, int color_range)
|
||||
{
|
||||
return c.PropSet("_Matrix", MBT_MatrixInt(matrix)).\
|
||||
PropSet("_Primaries", primaries).\
|
||||
PropSet("_Transfer", transfer).\
|
||||
PropSet("_ColorRange", color_range)
|
||||
}
|
||||
|
||||
function MBT_SetSDRColor(clip c, string matrix, int color_range)
|
||||
{
|
||||
return c.MBT_SetColor(matrix, MBT_PrimariesForMatrix(matrix), 1, color_range)
|
||||
}
|
||||
|
||||
function MBT_CorrectMatrix(clip c, string "input_matrix", string "output_matrix")
|
||||
{
|
||||
input_matrix = Default(input_matrix, MBT_GetMatrixName(c))
|
||||
output_matrix = Default(output_matrix, MBT_DefaultMatrix(c.Width, c.Height))
|
||||
input_matrix = Default(input_matrix, mbt_color_matrix)
|
||||
output_matrix = Default(output_matrix, MBT_DefaultOutputMatrix(c.Width, c.Height))
|
||||
was_hdr = MBT_IsHDR()
|
||||
Assert(!was_hdr || input_matrix == output_matrix,
|
||||
\ "MBT_CorrectMatrix does not convert HDR color systems. Use MBT_ToSDR or an explicit HDR conversion.")
|
||||
if (!was_hdr) {
|
||||
global mbt_color_matrix = output_matrix
|
||||
global mbt_color_primaries = MBT_PrimariesForMatrix(output_matrix)
|
||||
global mbt_color_transfer = 1
|
||||
}
|
||||
return was_hdr ? c.MBT_SetMatrix(input_matrix) : c.MBT_CorrectSDRMatrix(input_matrix, output_matrix)
|
||||
}
|
||||
|
||||
function MBT_CorrectSDRMatrix(clip c, string input_matrix, string output_matrix)
|
||||
{
|
||||
matrix = MBT_MatrixCodeForConvert(input_matrix) + ":auto=>" + MBT_MatrixCodeForConvert(output_matrix) + ":same"
|
||||
bitdepth = c.BitsPerComponent
|
||||
return c.IsRGB ? c
|
||||
\ : (c.Is420 ? c.ConvertToYUV420(matrix=matrix).ConvertBits(bitdepth).MBT_SetMatrix(output_matrix)
|
||||
\ : (c.Is422 ? c.ConvertToYUV422(matrix=matrix).ConvertBits(bitdepth).MBT_SetMatrix(output_matrix)
|
||||
\ : (c.Is444 ? c.ConvertToYUV444(matrix=matrix).ConvertBits(bitdepth).MBT_SetMatrix(output_matrix) : c.MBT_SetMatrix(output_matrix))))
|
||||
\ : (c.Is420 ? c.ConvertToYUV420(matrix=matrix).ConvertBits(bitdepth).PropCopy(c).MBT_SetSDRColor(output_matrix, mbt_color_range)
|
||||
\ : (c.Is422 ? c.ConvertToYUV422(matrix=matrix).ConvertBits(bitdepth).PropCopy(c).MBT_SetSDRColor(output_matrix, mbt_color_range)
|
||||
\ : (c.Is444 ? c.ConvertToYUV444(matrix=matrix).ConvertBits(bitdepth).PropCopy(c).MBT_SetSDRColor(output_matrix, mbt_color_range) : c.MBT_SetSDRColor(output_matrix, mbt_color_range))))
|
||||
}
|
||||
|
||||
function MBT_ToSDR(clip c, float "hdr_peak", float "sdr_peak", string "method", float "exposure", bool "chroma_correction", string "output_matrix")
|
||||
{
|
||||
transfer = MBT_GetTransferCode(c)
|
||||
primaries = MBT_GetPrimariesCode(c)
|
||||
color_range = MBT_GetRangeCode(c)
|
||||
hdr_mode = transfer == 18 ? 2 : 0
|
||||
Assert(transfer == 16 || transfer == 18, "MBT_ToSDR requires PQ or HLG input.")
|
||||
Assert(!c.IsRGB, "MBT_ToSDR currently requires planar YUV input.")
|
||||
Assert(primaries == 9,
|
||||
\ "MBT_ToSDR currently requires Rec2020 primaries. P3 HDR needs mastering-primary support.")
|
||||
method = Default(method, "MPC")
|
||||
Assert(
|
||||
\ method == "MPC" || method == "Hable" || method == "Mobius" || method == "Reinhard" || method == "ACES" || method == "BT2446C",
|
||||
\ "MBT_ToSDR method must be MPC, Hable, Mobius, Reinhard, ACES, or BT2446C.")
|
||||
chroma_correction = Default(chroma_correction, false)
|
||||
hdr_peak = Default(hdr_peak, hdr_mode == 0 ? 10000.0 : 1000.0)
|
||||
sdr_peak = Default(sdr_peak, 125.0)
|
||||
output_matrix = Default(output_matrix, MBT_DefaultMatrix(c.Width, c.Height))
|
||||
return method == "BT2446C"
|
||||
\ ? c.MBT_ToSDR_BT2446C(hdr_mode, color_range, hdr_peak, sdr_peak, chroma_correction, output_matrix)
|
||||
\ : method == "MPC"
|
||||
\ ? c.MBT_ToSDR_MPC(hdr_mode, color_range, hdr_peak, sdr_peak, exposure, output_matrix)
|
||||
\ : c.MBT_ToSDR_RGB(hdr_mode, color_range, method, exposure, output_matrix)
|
||||
}
|
||||
|
||||
function MBT_ToSDR_BT2446C(clip c, int hdr_mode, int color_range, float hdr_peak, float sdr_peak, bool chroma_correction, string output_matrix)
|
||||
{
|
||||
Assert(FunctionExists("ConvertYUVtoXYZ") && FunctionExists("ConvertXYZtoYUV") && FunctionExists("ConverXYZ_BT2446_C_HDRtoSDR"),
|
||||
\ "MBT_ToSDR requires HDRTools. Load HDRTools before calling it.")
|
||||
output_color = MBT_SDRColorForMatrix(output_matrix)
|
||||
linear = c.ConvertYUVtoXYZ(Color=0, OutputMode=2, HDRMode=hdr_mode, OOTF=false, fullrange=color_range == 1)
|
||||
linear = linear.ConverXYZ_BT2446_C_HDRtoSDR(ChromaC=chroma_correction, PQMode=hdr_mode == 0, Lhdr=hdr_peak, Lsdr=sdr_peak, pColor=0)
|
||||
result = linear.ConvertXYZtoYUV(Color=output_color, OutputMode=MBT_YuvOutputMode(c), OOTF=false, fullrange=false, pColor=0)
|
||||
return result.MBT_SetToSDRProperties(c, output_matrix)
|
||||
}
|
||||
|
||||
function MBT_ToSDR_RGB(clip c, int hdr_mode, int color_range, string method, float "exposure", string "output_matrix")
|
||||
{
|
||||
Assert(FunctionExists("ConvertYUVtoLinearRGB") && FunctionExists("ConvertRGBtoXYZ") && FunctionExists("ConvertXYZtoYUV"),
|
||||
\ "MBT_ToSDR requires HDRTools. Load HDRTools before calling it.")
|
||||
Assert(
|
||||
\ (method == "Hable" && FunctionExists("ConvertRGB_Hable_HDRtoSDR")) ||
|
||||
\ (method == "Mobius" && FunctionExists("ConvertRGB_Mobius_HDRtoSDR")) ||
|
||||
\ (method == "Reinhard" && FunctionExists("ConvertRGB_Reinhard_HDRtoSDR")) ||
|
||||
\ (method == "ACES" && FunctionExists("ConvertRGB_ACES_HDRtoSDR")),
|
||||
\ "MBT_ToSDR method is not provided by the loaded HDRTools plugin.")
|
||||
linear = c.MBT_LinearHDR(hdr_mode, color_range)
|
||||
scale = Defined(exposure) ? exposure : (method == "ACES" ? 1.0 : 2.0)
|
||||
mapped = method == "Hable" ? linear.ConvertRGB_Hable_HDRtoSDR(exposure_R=scale)
|
||||
\ : method == "Mobius" ? linear.ConvertRGB_Mobius_HDRtoSDR(exposure_R=scale)
|
||||
\ : method == "Reinhard" ? linear.ConvertRGB_Reinhard_HDRtoSDR(exposure_R=scale)
|
||||
\ : linear.ConvertRGB_ACES_HDRtoSDR(exposure_R=scale)
|
||||
xyz = mapped.ConvertRGBtoXYZ(Color=1, OOTF=false, EOTF=false)
|
||||
result = xyz.ConvertXYZtoYUV(Color=MBT_SDRColorForMatrix(output_matrix), OutputMode=MBT_YuvOutputMode(c), OOTF=false, fullrange=false, pColor=1)
|
||||
return result.MBT_SetToSDRProperties(c, output_matrix)
|
||||
}
|
||||
|
||||
function MBT_ToSDR_MPC(clip c, int hdr_mode, int color_range, float hdr_peak, float sdr_peak, float "exposure", string "output_matrix")
|
||||
{
|
||||
Assert(FunctionExists("ConvertYUVtoLinearRGB") && FunctionExists("ConvertRGBtoXYZ") && FunctionExists("ConvertXYZtoRGB") && FunctionExists("ConvertLinearRGBtoYUV"),
|
||||
\ "MBT_ToSDR requires HDRTools. Load HDRTools before calling it.")
|
||||
scale = Defined(exposure) ? exposure : hdr_peak / sdr_peak
|
||||
output_color = MBT_SDRColorForMatrix(output_matrix)
|
||||
linear = c.MBT_LinearHDR(hdr_mode, color_range)
|
||||
xyz = linear.ConvertRGBtoXYZ(Color=1, OOTF=false, EOTF=false)
|
||||
xyz = xyz.MBT_HableLuminance(scale)
|
||||
rgb = xyz.ConvertXYZtoRGB(Color=output_color, OutputMode=0, OOTF=false, EOTF=false, pColor=1)
|
||||
rgb = rgb.MBT_GamutMap(output_matrix)
|
||||
result = rgb.ConvertLinearRGBtoYUV(Color=output_color, OutputMode=MBT_YuvOutputMode(c), OOTF=false, EOTF=true, fullrange=false)
|
||||
return result.MBT_SetToSDRProperties(c, output_matrix)
|
||||
}
|
||||
|
||||
function MBT_HableLuminance(clip xyz, float exposure)
|
||||
{
|
||||
luminance = CombinePlanes(xyz, planes="Y", source_planes="G", pixel_type="Y32")
|
||||
mapped = luminance.Expr(MBT_HableExpression(exposure), format="Y32", clamp_float=true)
|
||||
scale = Expr(luminance, mapped, "y x 0.000001 max /", format="Y32", clamp_float=false)
|
||||
scale = MergeRGB(scale, scale, scale, pixel_type="RGBPS")
|
||||
return Expr(xyz, scale, "x y *", "x y *", "x y *", format="RGBPS", clamp_float=false).PropCopy(xyz)
|
||||
}
|
||||
|
||||
function MBT_HableExpression(float exposure)
|
||||
{
|
||||
return "x " + String(exposure) + " * T^ " + \
|
||||
"T T 0.15 * 0.05 + * 0.004 + N^ " + \
|
||||
"N T T 0.15 * 0.5 + * 0.06 + / 0.06666666666666667 - " + String(MBT_HableWhiteScale()) + " * 0 max 1 min"
|
||||
}
|
||||
|
||||
function MBT_GamutMap(clip rgb, string matrix)
|
||||
{
|
||||
red = CombinePlanes(rgb, planes="Y", source_planes="R", pixel_type="Y32")
|
||||
green = CombinePlanes(rgb, planes="Y", source_planes="G", pixel_type="Y32")
|
||||
blue = CombinePlanes(rgb, planes="Y", source_planes="B", pixel_type="Y32")
|
||||
luma = MBT_LumaExpression(matrix)
|
||||
return Expr(
|
||||
\ red, green, blue,
|
||||
\ MBT_GamutExpression("x", luma),
|
||||
\ MBT_GamutExpression("y", luma),
|
||||
\ MBT_GamutExpression("z", luma),
|
||||
\ format="RGBPS",
|
||||
\ clamp_float=true
|
||||
\).PropCopy(rgb)
|
||||
}
|
||||
|
||||
function MBT_LumaExpression(string matrix)
|
||||
{
|
||||
return matrix == "Rec601" ? "x 0.299 * y 0.587 * + z 0.114 * +"
|
||||
\ : matrix == "Rec2020" ? "x 0.2627 * y 0.678 * + z 0.0593 * +"
|
||||
\ : "x 0.2126 * y 0.7152 * + z 0.0722 * +"
|
||||
}
|
||||
|
||||
function MBT_GamutExpression(string channel, string luma)
|
||||
{
|
||||
return luma + " L^ " + \
|
||||
"x y min z min N^ x y max z max X^ " + \
|
||||
"X 1 > 1 L - X L - / 1 ? S^ " + \
|
||||
"N 0 < L L N - / 1 ? T^ S T min S^ " + \
|
||||
channel + " L - S * L +"
|
||||
}
|
||||
|
||||
function MBT_HableWhiteScale()
|
||||
{
|
||||
# 1 / hable(4.8), using the normalized Hable curve constants.
|
||||
return 1.7896902226524685
|
||||
}
|
||||
|
||||
function MBT_SetToSDRProperties(clip c, clip source, string output_matrix)
|
||||
{
|
||||
global mbt_color_matrix = output_matrix
|
||||
global mbt_color_primaries = MBT_PrimariesForMatrix(output_matrix)
|
||||
global mbt_color_transfer = 1
|
||||
global mbt_color_range = 0
|
||||
return c.ConvertBits(source.BitsPerComponent).PropCopy(source).MBT_SetSDRColor(output_matrix, 0)
|
||||
}
|
||||
|
||||
function DeShake(clip c, int "w", int "h", float "dar", float "crop", float "xcrop", float "ycrop", int "pos", bool "zoom", bool "rot", float "freq")
|
||||
|
||||
Reference in New Issue
Block a user