Add Avisynth video encoding workflow

This commit is contained in:
ajp_anton
2026-07-21 00:41:00 +00:00
parent f50f465465
commit 49296d6f45
37 changed files with 9487 additions and 76 deletions
+341
View File
@@ -0,0 +1,341 @@
# media-batch-tools Avisynth+ helpers.
#
# This file is imported by generated hidden source scripts. Keep functions here
# small and dependency-light unless the visible scripts explicitly document the
# required plugins.
function MBT_MarkSource(clip c, int source_id, int "matrix")
{
# 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))
runtime = """
last.propSet("mbt_source_id", """ + String(source_id) + """).\
propSet("mbt_source_frame", current_frame).\
propSet("mbt_drop_frame", 0).\
propSet("_Matrix", """ + String(matrix) + """).\
propSet("mbt_frame_time_seconds", mbt_frame_time_seconds).\
propSet("mbt_relative_timestamp", mbt_relative_timestamp).\
propSet("mbt_absolute_timestamp", mbt_absolute_timestamp).\
propSet("mbt_frame_duration_seconds", mbt_frame_duration_seconds).\
propSet("mbt_frame_duration", mbt_frame_duration)
"""
return c.ScriptClip(runtime)
}
function MBT_AudioSource(clip video, string source_path, string audio_cache_path)
{
audio = FFAudioSource(source_path, cachefile=audio_cache_path)
return AudioDub(video, audio)
}
function MBT_Drop(clip c, int start, int "end")
{
return MBT_SetDrop(c, 1, start, end)
}
function MBT_Undrop(clip c, int start, int "end")
{
return MBT_SetDrop(c, 0, start, end)
}
function MBT_SetDrop(clip c, int value, int start, int "end")
{
end = Default(end, -1)
end = (end < 0) ? start - end - 1 : end
runtime = """
(current_frame >= """ + String(start) + """ && current_frame <= """ + String(end) + """) ? \
last.propSet("mbt_drop_frame", """ + String(value) + """) : last
"""
return c.ScriptClip(runtime)
}
function MBT_DropEvery(clip c, int cycle, int "offset0", int "offset1", int "offset2", int "offset3", int "offset4", int "offset5", int "offset6", int "offset7", int "offset8", int "offset9", int "offset10", int "offset11", int "offset12", int "offset13", int "offset14", int "offset15")
{
return MBT_SetDropEvery(c, 1, cycle, offset0, offset1, offset2, offset3, offset4, offset5, offset6, offset7, offset8, offset9, offset10, offset11, offset12, offset13, offset14, offset15)
}
function MBT_UndropEvery(clip c, int cycle, int "offset0", int "offset1", int "offset2", int "offset3", int "offset4", int "offset5", int "offset6", int "offset7", int "offset8", int "offset9", int "offset10", int "offset11", int "offset12", int "offset13", int "offset14", int "offset15")
{
return MBT_SetDropEvery(c, 0, cycle, offset0, offset1, offset2, offset3, offset4, offset5, offset6, offset7, offset8, offset9, offset10, offset11, offset12, offset13, offset14, offset15)
}
function MBT_SetDropEvery(clip c, int value, int cycle, int "offset0", int "offset1", int "offset2", int "offset3", int "offset4", int "offset5", int "offset6", int "offset7", int "offset8", int "offset9", int "offset10", int "offset11", int "offset12", int "offset13", int "offset14", int "offset15")
{
expr = "false"
expr = Defined(offset0) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset0) + ")" : expr
expr = Defined(offset1) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset1) + ")" : expr
expr = Defined(offset2) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset2) + ")" : expr
expr = Defined(offset3) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset3) + ")" : expr
expr = Defined(offset4) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset4) + ")" : expr
expr = Defined(offset5) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset5) + ")" : expr
expr = Defined(offset6) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset6) + ")" : expr
expr = Defined(offset7) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset7) + ")" : expr
expr = Defined(offset8) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset8) + ")" : expr
expr = Defined(offset9) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset9) + ")" : expr
expr = Defined(offset10) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset10) + ")" : expr
expr = Defined(offset11) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset11) + ")" : expr
expr = Defined(offset12) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset12) + ")" : expr
expr = Defined(offset13) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset13) + ")" : expr
expr = Defined(offset14) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset14) + ")" : expr
expr = Defined(offset15) ? expr + " || (current_frame % " + String(cycle) + " == " + String(offset15) + ")" : expr
runtime = """
(""" + expr + """) ? last.propSet("mbt_drop_frame", """ + String(value) + """) : last
"""
return c.ScriptClip(runtime)
}
function MBT_Info(clip c, int "size", int "align")
{
# Overlay media-batch-tools frame properties for inspection while editing.
size = Default(size, 16)
align = Default(align, 7)
runtime = """
drop_value = propGetInt("mbt_drop_frame") == 0 ? "False" : "True"
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
Subtitle(last, text, size=""" + String(size) + """, align=""" + String(align) + """)
"""
return c.ScriptClip(runtime)
}
function Cropf(clip c, float l, float t, float w, float h)
{
return c.MBT_LinearResize(
\ Round(c.Width * w),
\ Round(c.Height * h),
\ c.Width * l,
\ c.Height * t,
\ c.Width * w,
\ c.Height * h
\)
}
function RotateCrop(clip c, float angle, float "dar")
{
dar = Default(dar, Float(c.Width) / Float(c.Height))
radians = angle * Pi() / 180.0
cosine = Abs(Cos(radians))
sine = Abs(Sin(radians))
crop_h = Min(
\ Float(c.Height),
\ Float(c.Width) / dar,
\ Float(c.Width) / (dar * cosine + sine),
\ Float(c.Height) / (dar * sine + cosine)
\)
crop_w = crop_h * dar
xalign = (c.Is420 || c.Is422) ? 2 : 1
yalign = c.Is420 ? 2 : 1
left = Ceil((c.Width - crop_w) / (2.0 * xalign)) * xalign
top = Ceil((c.Height - crop_h) / (2.0 * yalign)) * yalign
turned = c.Turn(angle=angle)
return turned.Crop(left, top, c.Width - 2 * left, c.Height - 2 * top)
}
function Resize(clip v, int "w", int "h", float "dar", float "xcrop", float "ycrop", int "pos", bool "linear", string "input_matrix", string "output_matrix")
{
# Resize with optional aspect-ratio crop.
# w/h: target size. dar: display aspect ratio when one dimension is omitted.
# xcrop/ycrop: percent cropped from each side before fitting. pos uses keypad
# placement: 1 top-left, 5 center, 9 bottom-right.
wo = v.Width
ho = v.Height
xcrop = Default(xcrop, 0.0) / 100.0
ycrop = Default(ycrop, 0.0) / 100.0
pos = Default(pos, 5)
pos = (pos < 1 || pos > 9) ? 5 : pos
dar = Default(dar, Float(wo) / Float(ho))
w = Defined(w) ? w : (Defined(h) ? Round(h * 0.5 * dar) * 2 : wo)
h = Defined(h) ? h : Round(w * 0.5 / dar) * 2
dar = Float(w) / Float(h)
cropped_w = (1.0 - 2.0 * xcrop) * wo
cropped_h = (1.0 - 2.0 * ycrop) * ho
crop_extra_w = (cropped_w / cropped_h > dar) ? (cropped_w - cropped_h * dar) : 0.0
crop_extra_h = (cropped_w / cropped_h < dar) ? (cropped_h - cropped_w / dar) : 0.0
crop_extra_t = crop_extra_h * ((pos <= 3) ? 0.0 : ((pos >= 7) ? 1.0 : 0.5))
crop_extra_b = crop_extra_h * ((pos >= 7) ? 0.0 : ((pos <= 3) ? 1.0 : 0.5))
crop_extra_l = crop_extra_w * ((pos % 3 == 1) ? 0.0 : ((pos % 3 == 0) ? 1.0 : 0.5))
crop_extra_r = crop_extra_w * ((pos % 3 == 0) ? 0.0 : ((pos % 3 == 1) ? 1.0 : 0.5))
crop_l = wo * xcrop + crop_extra_l
crop_t = ho * ycrop + crop_extra_t
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))
return v.MBT_LinearResize(w, h, crop_l, crop_t, crop_w, crop_h, linear=linear, input_matrix=input_matrix, output_matrix=output_matrix)
}
function MBT_LinearResize(clip src, int tw, int th,
\ float "src_left", float "src_top", float "src_width", float "src_height",
\ string "kernel", float "b", float "c", int "taps", float "p", int "bitdepth",
\ string "hkernel", string "vkernel", bool "linear", string "input_matrix", string "output_matrix")
{
uscale = "Spline36"
dscale = "CatmullRom"
hkernel = Default(hkernel , Default(kernel , (tw > src.Width ? uscale : dscale)))
vkernel = Default(vkernel , Default(kernel , (th > src.Height ? uscale : dscale)))
sl = Default(src_left , 0)
st = Default(src_top , 0)
sw = Default(src_width , src.Width)
sh = Default(src_height , src.Height)
b = Default(b , 1.0 / 3.0)
c = Default(c , 1.0 / 3.0)
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)."
\)
clp = (src.IsRGB ? (src.HasAlpha ? src.ConvertToPlanarRGBA
\ : src.ConvertToPlanarRGB)
\ : src.ConvertToPlanarRGB(matrix=input_matrix))
clp = clp.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 = 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
return clp
}
function MBT_DefaultMatrix(int w, int h)
{
return (w >= 3840 || h >= 2160) ? "Rec2020" : ((w >= 1280 || h >= 720) ? "Rec709" : "Rec601")
}
function MBT_MatrixNameFromCode(int matrix)
{
return (matrix == 1) ? "Rec709"
\ : (matrix == 9) ? "Rec2020"
\ : (matrix == 10) ? "Rec2020"
\ : (matrix == 5) ? "Rec601"
\ : (matrix == 6) ? "Rec601"
\ : ""
}
function MBT_MatrixCodeForConvert(string matrix)
{
return (matrix == "Rec601") ? "601"
\ : (matrix == "Rec709") ? "709"
\ : (matrix == "Rec2020") ? "2020"
\ : matrix
}
function MBT_MatrixInt(string matrix)
{
return (matrix == "Rec709") ? 1
\ : (matrix == "Rec2020") ? 9
\ : (matrix == "Rec601") ? 6
\ : 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_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))
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))))
}
function DeShake(clip c, int "w", int "h", float "dar", float "crop", float "xcrop", float "ycrop", int "pos", bool "zoom", bool "rot", float "freq")
{
# Stabilize through MVTools + DePan functions. Those plugins must be loaded
# in Avisynth before this function is called.
crop = Default(crop, 2.5)
xcrop = Default(xcrop, crop)
ycrop = Default(ycrop, crop)
zoom = Default(zoom, true)
rot = Default(rot, true)
freq = Default(freq, 1.0)
vectors = c.MSuper().MAnalyse(isb=false, dct=5)
mdata = MDepan(c, vectors, thscd1=1000, thscd2=1000, zoom=zoom, rot=rot, error=255)
stabilized = DePanStabilize(
\ c,
\ data=mdata,
\ dxmax=c.Width * xcrop / 100.0,
\ dymax=c.Height * ycrop / 100.0,
\ rotmax=3.0,
\ mirror=15,
\ cutoff=freq
\)
return (Defined(w) || Defined(h) || Defined(dar)) ? Resize(stabilized, w, h, dar, xcrop, ycrop, pos) : stabilized
}
function FixContrast(clip c, int "low", int "high")
{
# Map input luma range to limited-range video luma.
low = Default(low, 16)
high = Default(high, 235)
return c.Levels(low, 1.0, high, 16, 235, coring=false)
}