Skip to content

Instantly share code, notes, and snippets.

@4re
Last active March 20, 2020 19:19
Show Gist options
  • Save 4re/3acdb8d90abf78643d4e to your computer and use it in GitHub Desktop.
Save 4re/3acdb8d90abf78643d4e to your computer and use it in GitHub Desktop.
scoll Scritp Collection for Vapoursynth
""" scoll.py +++ Script Collection for VapourSynth: ++++++++++++++++++++++++++++++++++++++++++++++
"""
import vapoursynth as vs
try:
import havsfunc as haf
except:
HAS_HAF = False
else:
HAS_HAF = True
try:
import vshelpers as vsh
except:
raise ImportError('You need to install vshelpers module.')
""" misc /////////////////////////////////////////////////////////////////////////////////////////
"""
def ssaa(clip, thrmask=40, aamode=0, ssmode=1, mmode=2, sharpen=False, smask=False):
"""
ssaa +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Small antialiasing function for 1080p. Input must be vs.YUV420P8 or GRAY8.
ssaa(clip, th_mask=11, sharpen=False, smask=False)
th_mask: The lower the threshold, more pixels will be antialiased.
aamode: Antialiasing metoth: 0: SangNom; 1: nnedi3; 2: RemoveGrain.
ssmode: Supersampling metoth: 0:Spline36; 1: nnedi3_rpow2, 2: point
sharpen: Performs contra-sharpening on the antialiased zones.
smask: Shows the zones antialiasing will be applied.
Dependencies:
SangNomMod
Repair
RemoveGrain
fmtconv
nnedi3
Todo:
- Make it work on 16bit mode when aviable.
Changelog:
3.0 Added RemoveGrain aamode and nnedi3 ssmode.
2.0 Adapted to use native repair.
Memory/speed optimizations.
1.0 Initial release.
"""
core = vs.get_core()
fw = clip.width
fh = clip.height
if clip.format.num_planes > 1:
if clip.format.color_family != vs.YUV:
raise ValueError('Input video format should be 8 bits YUV or GRAY8.')
else:
clipl = vsh.get_luma(clip)
else:
clipl = clip
cluma = core.rgvs.RemoveGrain(clipl, 1)
if thrmask > 0:
mask = vsh.build_mask(c=cluma, edgelvl=thrmask, mode=mmode)
# Super Sampling
if ssmode == 0:
aac = core.fmtc.resample(clip=cluma, w=fw*2, h=fh*2)
if aac.format.bits_per_sample != clip.format.bits_per_sample:
aac = core.fmtc.bitdepth(aac, bits=clip.format.bits_per_sample)
elif ssmode == 1:
aac = core.nnedi3.nnedi3_rpow2(clip=cluma, rfactor=2, correct_shift=1, qual=2)
elif ssmode == 2:
aac = core.fmtc.resample(clip=cluma, kernel='point', w=fw*2, h=fh*2)
if aac.format.bits_per_sample != clip.format.bits_per_sample:
aac = core.fmtc.bitdepth(aac, bits=clip.format.bits_per_sample)
else:
raise ValueError('Wrong ssmode, it should be 0 (fmtc), 1 (nnedi3_rpow2) or 2 (point).')
# Antialiasing
if aamode == 0:
aac = core.std.Transpose(core.sangnom.SangNomMod(clip=aac, aa=255, aac=-1))
aac = core.std.Transpose(core.sangnom.SangNomMod(clip=aac, aa=255, aac=-1))
elif aamode == 1:
aac = core.std.Transpose(core.nnedi3.nnedi3(clip=aac, field=0, nns=2))
aac = core.std.Transpose(core.nnedi3.nnedi3(clip=aac, field=0, nns=2))
elif aamode == 2:
aac = core.rgvs.RemoveGrain(aac, 5).rgvs.RemoveGrain(21).rgvs.RemoveGrain(19)
elif aamode == 3:
aac = core.rgvs.RemoveGrain(aac, 5).rgvs.RemoveGrain(21).rgvs.RemoveGrain(19).std.Transpose()
aac = core.rgvs.RemoveGrain(aac, 5).rgvs.RemoveGrain(21).rgvs.RemoveGrain(19).std.Transpose()
else:
raise ValueError('Wrong aamode, it should be 0 (SangNomMod), 1 (nnedi3), 2 or 3 (RemoveGrain).')
aac = core.fmtc.resample(clip=aac, w=fw, h=fh)
if aac.format.bits_per_sample != clip.format.bits_per_sample:
aac = core.fmtc.bitdepth(aac, bits=clip.format.bits_per_sample)
if aamode == 2 or aamode == 3:
aac = core.rgvs.RemoveGrain(aac, 22)
# Sharpening
if sharpen is True:
aaD = core.std.MakeDiff(cluma, aac)
shrpD = core.std.MakeDiff(aac, core.rgvs.RemoveGrain(aac, 20))
DD = core.rgvs.Repair(clip=shrpD, repairclip=aaD, mode=13)
aac = core.std.MergeDiff(aac, DD)
# Merge chroma
if smask is True and thrmask > 0:
return mask
else:
if thrmask > 0:
last = core.std.MaskedMerge(cluma, aac, mask, planes=0)
else:
last = aac
if clip.format.num_planes > 1:
last = vsh.merge_chroma(last, clip)
return last
def nediaa(c, pm=2):
"""
nediAA - antialiasing function using nnedi3 ++++++++++++++++++++++++++++++
pm: parity mode, should be 2 or 3.
"""
core = vs.get_core()
pm = vsh.clamp(2, pm, 3)
ret = core.nnedi3.nnedi3(c, field=pm)
ret = core.std.Merge(ret[::2], ret[1::2])
return ret
def naa(c, ss=2, chroma=False):
"""
naa - antialiasing function using nnedi3 +++++++++++++++++++++++++++++++++
ss: supersampling value, must be even.
cp: if false chroma will not be altered.
"""
core = vs.get_core()
if ss % 2 != 0:
raise ValueError('ss must be an even number.')
src = c
if chroma is False:
c = vsh.get_luma(c)
if c.format.bits_per_sample > 8:
fapprox = 12
else:
fapprox = 7
ret = core.nnedi3.nnedi3_rpow2(clip=c, rfactor=ss, correct_shift=1, qual=2, fapprox=fapprox, nsize=6)
ret = core.nnedi3.nnedi3(clip=ret, field=0, nns=2, fapprox=fapprox, nsize=6)
ret = core.std.Transpose(ret)
ret = core.nnedi3.nnedi3(clip=ret, field=0, nns=2, fapprox=fapprox, nsize=6)
ret = core.std.Transpose(ret)
ret = core.fmtc.resample(ret, c.width, c.height)
if ret.format.bits_per_sample != c.format.bits_per_sample:
ret = core.fmtc.bitdepth(ret, bits=c.format.bits_per_sample)
if chroma is False:
ret = vsh.merge_chroma(ret, src)
return ret
def daa3mod(src):
""" From: http://forum.doom9.org/showthread.php?p=1639679#post1639679
"""
core = vs.get_core()
clip = core.resize.Spline36(src, src.width, vsh.m4(src.height*3/2))
nn = core.nnedi3.nnedi3(clip, field=-2)
dbl = core.std.Merge(nn[::2], nn[1::2])
dblD = core.std.MakeDiff(clip, dbl)
shrpD = core.std.MakeDiff(dbl, core.rgvs.RemoveGrain(dbl, 20 if clip.width > 1100 else 11))
DD = core.rgvs.Repair(shrpD, dblD, 13)
res = core.std.MergeDiff(dbl, DD).resize.Spline36(src.width, src.height)
return res
def mcdaa3(src, csaa=None):
""" From: http://forum.doom9.org/showthread.php?p=1639679#post1639679
"""
core = vs.get_core()
sup = core.mv.Super(src, pel=2, sharp=1) # HQdn3d(src).FFT3DFilter().MSuper(pel=2, sharp=1) FIXME
fv = core.mv.Analyse(sup, isb=False, delta=1, dct=2, truemotion=False)
bv = core.mv.Analyse(sup, isb=True, delta=1, dct=2, truemotion=True)
if csaa is None:
csaa = daa3mod(src)
momask1 = core.mv.Mask(src, fv, kind=1, ml=2)
momask2 = core.mv.Mask(src, bv, kind=1, ml=3)
momask = core.std.Merge(momask1, momask2)
res = core.std.MaskedMerge(src, csaa, momask)
return None
def edgecleaner(src, strength=8, smode=0, rmode=17, rep=True, hot=False):
""" edgecleaner.py (2013-12-23)
A simple edge cleaning and weak dehaloing function ported to vapoursynth. Ported from:
http://pastebin.com/7TCR7W4x
edgecleaner(src, strength=16, rep=True, rmode=17, smode=0, hot=False)
strength (float) - specifies edge denoising strength (8.0)
rep (boolean) - actives Repair for the aWarpSharped clip (true; requires Repair).
rmode (integer) - specifies the Repair mode; 1 is very mild and good for halos,
16 and 18 are good for edge structure preserval
on strong settings but keep more halos and edge noise,
17 is similar to 16 but keeps much less haloing,
other modes are not recommended (17; requires Repair).
smode (integer) - specifies what method will be used for finding small particles,
ie stars; 0 is disabled, 1 uses RemoveGrain and 2 uses Deen
(0; requires RemoveGrain/Repair/Deen).
hot (boolean) - specifies whether removal of hot pixels should take place (false).
Dependencies:
RemoveGrain (vs)
GeneritFilters (vs)
MaskTools2 (avs)
deen (avs)
aWarpSharp2 (avs)
"""
core = vs.get_core()
smode = vsh.clamp(0, smode, 2)
if src.format.id != vs.YUV420P8:
raise ValueError('Input video format should be YUV420P8.')
if smode != 0:
strength = strength + 2
main = core.avs.aWarpSharp2(src, 128, 1, 0, strength)
if rep is True:
main = core.rgvs.Repair(main, src, rmode)
mask = core.std.Prewitt(clip=src, min=4, max=32).std.Invert()
mask = core.std.Convolution(clip=mask, matrix=[1, 1, 1, 1, 1, 1, 1, 1, 1])
final = core.std.MaskedMerge(src, main, mask, planes=0)
if hot is True:
final = core.rgvs.Repair(final, src, 2)
if smode != 0:
stmask = vsh.starmask(src, smode)
final = core.std.MaskedMerge(final, src, stmask)
return final
def ezydegrain(src, tr=3, thsad=250, blksize=None, overlap=None, pel=None, limit=None, recalc=False, plane=4):
core = vs.get_core()
# Vars
if blksize is None:
if src.width < 1280 or src.height < 720:
blksize = 8
elif src.width >= 3840 or src.height >= 2160:
blksize = 32
else:
blksize = 16
if overlap is None:
overlap = blksize // 2
if pel is None:
if src.width < 1280 or src.height < 720:
pel = 2
else:
pel = 1
if limit is None:
limit = 2**src.format.bits_per_sample-1
# Cheks
if tr not in [1, 2, 3]:
raise ValueError('tr must be 1, 2 or 3.')
# Stuff
last = src
super_ = core.mv.Super(last, pel=pel, sharp=2, rfilter=4)
mvbw3 = core.mv.Analyse(super_, isb=True, delta=3, overlap=overlap, blksize=blksize)
mvbw2 = core.mv.Analyse(super_, isb=True, delta=2, overlap=overlap, blksize=blksize)
mvbw1 = core.mv.Analyse(super_, isb=True, delta=1, overlap=overlap, blksize=blksize)
mvfw1 = core.mv.Analyse(super_, isb=False, delta=1, overlap=overlap, blksize=blksize)
mvfw2 = core.mv.Analyse(super_, isb=False, delta=2, overlap=overlap, blksize=blksize)
mvfw3 = core.mv.Analyse(super_, isb=False, delta=3, overlap=overlap, blksize=blksize)
if recalc is True:
hoverlap = overlap // 2
hblksize = blksize // 2
hthsad = thsad // 2
prefilt = core.rgvs.RemoveGrain(last, 4)
super_r = core.mv.Super(prefilt, pel=pel, sharp=2, rfilter=4)
mvbw3 = core.mv.Recalculate(super_r, mvbw3, overlap=hoverlap, blksize=hblksize, thsad=hthsad)
mvbw2 = core.mv.Recalculate(super_r, mvbw2, overlap=hoverlap, blksize=hblksize, thsad=hthsad)
mvbw1 = core.mv.Recalculate(super_r, mvbw1, overlap=hoverlap, blksize=hblksize, thsad=hthsad)
mvfw1 = core.mv.Recalculate(super_r, mvfw1, overlap=hoverlap, blksize=hblksize, thsad=hthsad)
mvfw2 = core.mv.Recalculate(super_r, mvfw2, overlap=hoverlap, blksize=hblksize, thsad=hthsad)
mvfw3 = core.mv.Recalculate(super_r, mvfw3, overlap=hoverlap, blksize=hblksize, thsad=hthsad)
if tr == 1:
last = core.mv.Degrain1(clip=last, super=super_,
mvbw=mvbw1, mvfw=mvfw1, thsad=thsad, plane=plane)
elif tr == 2:
last = core.mv.Degrain2(clip=last, super=super_,
mvbw=mvbw1, mvfw=mvfw1, mvbw2=mvbw2, mvfw2=mvfw2,
thsad=thsad, plane=plane)
elif tr == 3:
last = core.mv.Degrain3(clip=last, super=super_,
mvbw=mvbw1, mvfw=mvfw1, mvbw2=mvbw2,
mvfw2=mvfw2, mvbw3=mvbw3, mvfw3=mvfw3,
thsad=thsad, plane=plane)
return last
def removedirt(c, repmode=16):
core = vs.get_core()
if c.format.num_planes > 1:
repmodes = [repmode, repmode, 1]
greymode = 0
else:
repmodes = [repmode]
greymode = 1
cleansed = core.rgvs.Clense(c)
sbegin = core.rgvs.ForwardClense(c)
send = core.rgvs.BackwardClense(c)
scenechange = core.rdvs.SCSelect(c, sbegin, send, cleansed)
alt = core.rgvs.Repair(clip=scenechange, repairclip=c, mode=repmodes)
restore = core.rgvs.Repair(clip=cleansed, repairclip=c, mode=repmodes)
corrected = core.rdvs.RestoreMotionBlocks(cleansed, restore, neighbour=c, alternative=alt,
gmthreshold=70, dist=1, dmode=2, noise=10, noisy=12,
grey=greymode)
return core.rgvs.RemoveGrain(corrected, mode=[17, 17, 1])
def unsharpmask(clip, strength=1.0, repair=False, repmode=16):
core = vs.get_core()
blur_clip = core.generic.GBlur(clip, sigma=strength, planes=[0])
sharp_clip = core.std.Expr([clip, blur_clip], ['x x + y -', ''])
if repair is True:
rclip = core.rgvs.Repair(clip=sharp_clip, repairclip=clip, mode=repmode)
else:
rclip = sharp_clip
return rclip
def detailsharpen(clip, sstr=1.01, estr=10, ethr=5, repair=False, rmode=12):
core = vs.get_core()
bd = clip.format.bits_per_sample
max_ = 2 ** bd - 1
mid = (max_ + 1) // 2
scl = (max_ + 1) // 256
src = clip
clip = vsh.get_luma(clip)
blur = core.rgvs.RemoveGrain(clip, 20)
# "x y == x x x y - abs 0.25 ^ 4.24 * x y - 2 ^ x y - 2 ^ 2 + / * x y - x y - abs / * 1 x y - abs 16 / 4 ^ + / + ?"
# "x x y - abs 0.25 ^ 4.24 * x y - x y - abs 2 + / * +"
# 'x x y - abs 4 / 1 4 / ^ 4 * 1.5 * x y - x y - abs 2 + / * +'
# 'x x y - abs 1 4 / ^ 2.83 * 1.5 * x y - x y - abs 2 + / * +'
# expr = 'x x y - 1 x y - 16 / 4 ^ + / +'
expr = '{x} {x} {y} - abs 4 / log 0.25 * exp 4 * {st} * {x} {y} - {x} {y} - abs 1.001 + / * + {sc}'.format(
x='x {} /'.format(scl) if bd != 8 else 'x',
y='y {} /'.format(scl) if bd != 8 else 'y',
sc='{} *'.format(scl) if bd != 8 else '',
st=sstr)
clip = core.std.Expr([clip, blur], [expr])
if estr > 0:
tmp = clip
clip = core.msmoosh.MSharpen(clip, threshold=ethr, strength=estr)
if repair is True:
clip = core.rgvs.Repair(clip=clip, repairclip=tmp, mode=rmode)
clip = vsh.merge_chroma(clip, src)
return clip
def assrenderwrapper(clip, data, charset=None, debuglevel=None, fontdir=None, linespacing=None,
margins=None, sar=None, scale=None):
core = vs.get_core()
subs = core.assvapour.AssRender(clip=clip, data=data, charset=charset, debuglevel=debuglevel,
fontdir=fontdir, linespacing=linespacing, margins=margins, sar=sar,
scale=scale)
subs[0] = core.resize.Bicubic(subs[0], format=clip.format.id)
subs[1] = core.resize.Bicubic(subs[1], format=clip.format.id)
return core.std.MaskedMerge(clipa=clip, clipb=subs[0], mask=subs[1])
def subtitlewrapper(clip, text, debuglevel=None, fontdir=None, linespacing=None, margins=None,
sar=None, style=None):
core = vs.get_core()
subs = core.assvapour.Subtitle(clip=clip, text=text, debuglevel=debuglevel, fontdir=fontdir,
linespacing=linespacing, margins=margins, sar=sar, style=style)
subs[0] = core.resize.Bicubic(subs[0], format=clip.format.id)
subs[1] = core.resize.Bicubic(subs[1], format=clip.format.id)
return core.std.MaskedMerge(clipa=clip, clipb=subs[0], mask=subs[1])
def resamplehq(src, width=None, height=None, kernel="spline36", srcmatrix="709", dstmatrix=None,
src_left=0, src_top=0, src_width=0, src_height=0, noring=False, sigmoid=False, dither=True):
core = vs.get_core()
# Var stuff
clip = src
if dstmatrix is None:
dstmatrix = srcmatrix
if src.format.bits_per_sample != 16:
clip = core.fmtc.bitdepth(clip=clip, bits=16)
tid = clip.format.id
# Convert to RGB
if src.format.color_family != vs.RGB:
clip = core.fmtc.resample(clip=clip, css="444")
clip = core.fmtc.matrix(clip=clip, mat=srcmatrix, col_fam=vs.RGB)
# Do stuff
clip = haf.GammaToLinear(clip, sigmoid=sigmoid)
clip = haf.Resize(clip, w=width, h=height, kernel=kernel, noring=noring,
sx=src_left, sy=src_top, sw=src_width, sh=src_height)
clip = haf.LinearToGamma(clip, sigmoid=sigmoid)
# Back to original format
if src.format.color_family != vs.RGB:
clip = core.fmtc.matrix(clip=clip, mat=dstmatrix, col_fam=src.format.color_family)
clip = core.fmtc.resample(clip=clip, csp=tid)
# Dither as needed
if dither is True and src.format.bits_per_sample != 16:
clip = core.fmtc.bitdepth(clip=clip, bits=src.format.bits_per_sample)
return clip
""" rangeutils ///////////////////////////////////////////////////////////////////////////////////
"""
def replace_range(clip1, clip2, start, end=None):
""" Replaces a range of frames of a clip with the same range of
frames from another clip.
If no end frame is given, it will only replace the start frame.
"""
core = vs.get_core()
if end is None:
end = start
if start < 0 or start > clip1.num_frames - 1:
raise ValueError('start frame out of bounds: {}.'.format(start))
if end < start or end > clip1.num_frames - 1:
raise ValueError('end frame out of bounds: {}.'.format(end))
if start > 0:
temp = 'core.std.Trim(clip1, 0, start - 1) + '
else:
temp = ''
temp += 'core.std.Trim(clip2, start, end)'
if end < clip1.num_frames - 1:
temp += '+ core.std.Trim(clip1, end + 1)'
final = eval(temp)
if clip1.num_frames != final.num_frames:
raise ValueError('input / output framecount missmatch (got: {}; expected: {}).'
.format(final.num_frames, clip1.num_frames))
return final
def delete_range(src, start, end=None):
""" Deletes a range of frames from a clip.
If no end frame is given, it will only delete the start frame.
"""
core = vs.get_core()
if end is None:
end = start
if start < 0 or start > src.num_frames - 1:
raise ValueError('start frame out of bounds: {}.'.format(start))
if end < start or end > src.num_frames - 1:
raise ValueError('end frame out of bounds: {}.'.format(end))
if start != 0:
final = src[:start]
if end < src.num_frames - 1:
final = final + src[end + 1:]
else:
final = src[end + 1:]
if src.num_frames != final.num_frames + (end - start + 1):
raise ValueError('output expected framecount missmatch.')
return final
def freeze_loop(src, start, end, loopStart, loopEnd=None):
""" Freezes a range of frames form start to end using the frames
comprended between loopStart and loopEnd.
If no end frames are provided for the range or the loop,
start frames will be used instead.
"""
core = vs.get_core()
if loopEnd is None:
loopEnd = loopStart
if start < 0 or start > src.num_frames - 1:
raise ValueError('start frame out of bounds: {}.'.format(start))
if loopStart < 0 or loopStart > src.num_frames - 1:
raise ValueError('loop start frame out of bounds: {}.'.format(loopStart))
if end < start or end > src.num_frames - 1:
raise ValueError('end frame out of bounds: {}.'.format(end))
if loopEnd < loopStart or loopEnd > src.num_frames - 1:
raise ValueError('loop end out of bounds: {}.'.format(loopEnd))
loop = core.std.Loop(src[loopStart:loopEnd + 1], 0)
span = end - start + 1
if start != 0:
final = src[:start] + loop[:span]
else:
final = loop[:span]
if end < src.num_frames - 1:
final = final + src[end + 1:]
if src.num_frames != final.num_frames:
raise ValueError(
'input / output framecount missmatch (got: {}; expected: {}).'.format(
final.num_frames, src.num_frames))
return final
def blank_it(src, start, end=None, color='black'):
""" Blanks a range of frames in a clip, by default to pure balck.
If no endframe is provided start frame will be used.
"""
core = vs.get_core()
if end is None:
end = start
e = core.std.BlankClip(src, color=color)
if start != 0:
z = src[:start] + e[start:end + 1]
else:
z = e[start:end + 1]
if end < src.num_frames - 1:
z = z + src[end + 1:]
if src.num_frames != z.num_frames:
raise ValueError(
'input / output framecount missmatch (got: {}; expected: {}).'.format(
z.num_frames, src.num_frames))
return z
def mkvcut(c, frag_tot, frag_req, base_name='frag', debug=False):
""" mkvcut +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Description:
Given a lossless video and an arbitrary number of segments of the same
compresed video, it returns the selected segemnt from the lossless video.
Dep:
l-smash-works
Use:
mkvcut (lossless, frag_tot, frag_req, <base_name>)
mkvcomp (losless, video_final)
Options:
frag_tot (-)
Número de fragmentos totales en los que está partido el vídeo
(mediante mkvmerge).
frag_req (-)
Fragmento que se desea reencodear.
base_name ("frag")
Nombre que se les dio a los fragmentos a la hora de cortarlos.
También se puede especificar aquí una ruta alternativa si estos
no se encuentran en el mismo directorio que el script.
Examples:
mkvcut(clip, 3, 1)
mkvcut(clip, 3, 2, "another_name")
mkvcut(clip, 7, 2, "another_dir/another_name")
"""
core = vs.get_core()
a = p = None
vsource = vsh.get_decoder()
if frag_req > frag_tot:
raise AssertionError(
'Requested fragment is out of range (req: {} tot: {}).'.format(frag_req, frag_tot))
for i in range(1, frag_req):
tmp = vsource(source=r'%s-%03d.mkv' % (base_name, i))
if a is None:
a = tmp
else:
a = a + tmp
for i in range(frag_req+1, frag_tot+1):
tmp = vsource(source=r'%s-%03d.mkv' % (base_name, i))
if p is None:
p = tmp
else:
p = p + tmp
if c is not None:
c_len = c.num_frames
else:
c_len = 0
a_len = a.num_frames
if p is not None:
p_len = p.num_frames
else:
p_len = 0
r = core.std.Trim(clip=c, first=a_len, last=(c_len-p_len)-1)
if c_len != a_len + r.num_frames + p_len:
raise AssertionError(
'Internal error: source video and returned video number of frames missmatch.')
if c.fps_num != r.fps_num or c.fps_den != r.fps_den:
raise AssertionError(
'Internal error: source video and returned video frame rate missmatch.')
if debug:
r = core.text.ClipInfo(clip=r)
return r
def mkv_comp(c, a):
core = vs.get_core()
w2 = int(c.width/2)
h2 = int(c.height/2)
vsource = vsh.get_decoder()
try:
a = vsource(clip=r'{}'.format(a))
except:
a = a
org = core.resize.Point(clip=c, width=w2, height=h2).text.ClipInfo().text.FrameNum(alignment=9)
new = core.resize.Point(clip=a, width=w2, height=h2).text.ClipInfo().text.FrameNum(alignment=9)
return core.std.StackHorizontal(clips=[org, new])
def overlay(c1, c2, x=0, y=0, mask=None, opacity=1.0, mode='blend', processing=None, matrix=None):
""" TODO
- check x, y offsets logic against avisynth ones.
"""
core = vs.get_core()
bd = c1.format.bits_per_sample
max_ = (2 ** bd) - 1
if matrix is None:
matrix = '709'
mode = mode.lower()
modes = [
'blend',
'add',
'substract',
'difference',
'multiply',
'divide',
'lighten',
'darken'
]
if mode not in modes:
raise ValueError('"{}" is not a valid mode (valid modes: {}).'.format(mode, ', '.join(modes)))
if mask is None:
if isinstance(c2, list):
clipb = c2[0]
mask = c2[1]
else:
raise TypeError('No alpha clip supplied via "c2" or "mask" parameter.')
else:
clipb = c2
mask = mask
if c1.format.id != clipb.format.id:
raise TypeError('Both clips should be in the same format.')
clipa = c1
clipb = vsh.fit(clipa, clipb)
mask = vsh.fit(clipa, mask)
if clipa.num_frames > clipb.num_frames:
clipb = core.std.DuplicateFrames(clip=clipb,
frames=[clipb.num_frames-1] * (clipa.num_frames-clipb.num_frames))
if clipa.num_frames > mask.num_frames:
mask = core.std.DuplicateFrames(clip=mask,
frames=[mask.num_frames-1] * (clipa.num_frames-mask.num_frames))
if x != 0 or y != 0:
clips = vsh.move([clipb, mask], x, y)
clipb = clips[0]
mask = clips[1]
if processing is not None:
processing = processing.lower()
if processing == 'yuv':
if clipa.format.color_family != vs.YUV:
clipa = core.fmtc.resample(clipa, kernel="lanczos", css="444")
clipb = core.fmtc.resample(clipb, kernel="lanczos", css="444")
clipa = core.fmtc.matrix(clipa, mat=matrix, col_fam=vs.YUV)
clipb = core.fmtc.matrix(clipb, mat=matrix, col_fam=vs.YUV)
elif processing == 'rgb':
if clipa.format.color_family != vs.RGB:
clipa = core.fmtc.resample(clipa, kernel="lanczos", css="444")
clipb = core.fmtc.resample(clipb, kernel="lanczos", css="444")
clipa = core.fmtc.matrix(clipa, mat=matrix, col_fam=vs.RGB)
clipb = core.fmtc.matrix(clipb, mat=matrix, col_fam=vs.RGB)
else:
raise ValueError('Unsuported processing mode ("rgb" or "yuv", got: "{}").'.format(processing))
if clipb.format.bits_per_sample != mask.format.bits_per_sample:
mask = core.fmtc.bitdepth(mask, bits=clipb.format.bits_per_sample)
merg = core.std.MaskedMerge(clipa=clipb, clipb=clipa, mask=mask)
if mode != 'blend':
if mode == 'add':
merg = core.std.Expr(clips=[clipa, merg], expr=['x y + 255 min'.format(max_)])
merg = core.std.MaskedMerge(clipa=merg, clipb=clipa, mask=mask)
elif mode == 'substract':
merg = core.std.Expr(clips=[clipa, merg], expr=['x y - 0 max'])
merg = core.std.MaskedMerge(clipa=merg, clipb=clipa, mask=mask)
elif mode == 'difference':
merg = core.std.Expr(clips=[clipa, merg], expr=['x y - abs'])
merg = core.std.MaskedMerge(clipa=merg, clipb=clipa, mask=mask)
elif mode == 'multiply':
merg = core.std.Expr(clips=[clipa, merg], expr=['x y * {} /'.format(max_)])
merg = core.std.MaskedMerge(clipa=merg, clipb=clipa, mask=mask)
elif mode == 'divide':
merg = core.std.Expr(clips=[clipa, merg], expr=['{} x * y 1 + /'.format(max_ + 1)])
merg = core.std.MaskedMerge(clipa=merg, clipb=clipa, mask=mask)
elif mode == 'lighten':
merg = core.std.Expr(clips=[clipa, merg], expr=['x y max'])
merg = core.std.MaskedMerge(clipa=merg, clipb=clipa, mask=mask)
elif mode == 'darken':
merg = core.std.Expr(clips=[clipa, merg], expr=['x y min'])
merg = core.std.MaskedMerge(clipa=merg, clipb=clipa, mask=mask)
if opacity != 1:
merg = core.std.Merge(clipa=clipa, clipb=merg, weight=opacity)
return merg
def insertsign(src, ovr, start, end=None, x=0, y=0, opacity=1.0):
""" insertsign ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Description: Inserts an alpha video at the selected frames.
Options:
src: base video.
ovr: overlayed video, this should be a list with the overlayed video and an alpha mask.
start: frame at the one the overlay will start.
end: frame at the one the overlay will end.
x: move the overlay video in the x axis, accepts negative and positive values.
y: move the overlay video in the y axis, accepts negative and positive values.
opacity: blends the overlay video by the specified amount.
"""
core = vs.get_core()
if end is None:
end = start + ovr[0].num_frames - 1
if end >= src.num_frames:
end = src.num_frames - 1
if src.num_frames < end:
raise ValueError('Out of bounds requested end frame (requested: {}; last frame: {}).'.format(
end, src.num_frames))
e = overlay(c1=src[start:end + 1], c2=ovr[0], mask=ovr[1], x=x, y=y, opacity=opacity)
if start != 0:
z = src[:start] + e
else:
z = e
if end < src.num_frames - 1:
z = z + src[end + 1:]
if src.num_frames != z.num_frames:
raise ValueError('input / output framecount missmatch (got: {}; expected: {}).'.format(
z.num_frames, src.num_frames))
return z
@Selur
Copy link

Selur commented Feb 18, 2018

@theChaosCoder: starmask (line 256) uses Deen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment