Mug Funky
29th July 2006, 05:28
okay, i re-read this thread:
http://forum.doom9.org/showthread.php?t=67161
a few days ago after being linked from the recent monty-python thread.
i remembered trying it out and seeing 30p pans get decimated as film, so i came up with this:
####
##
## NTSC tools 0.93, by Sal, aka Mug
##
## takes an NTSC clip, finds Film, 30p and 60i parts and gives them special treatment
## use it to convert to PAL with 4% speed-up (ie 23.976 to 25 fps)
##
####
function AutoPAL (clip c, bool "speedup", float "th_film", int "th_film2", int "th_prog", int "th_bob", float "tol", bool "show", int "mode", string "filter", bool "blend", int "deblocker", int "IVTCtype", int "precision")
{
speedup=default(speedup,false)
blend=default(blend,true)
th_film=default(th_film,.4)#.15)
th_film2=default(th_film2,5)
th_prog=default(th_prog,4)
th_bob=default(th_bob,8)
tol=default(tol,1.5)
show=default(show,false)
mode=default(mode,1)
filter=default(filter,"last")
deblocker=default(deblocker,0)
IVTCtype = default(IVTCtype,4) # 1 = telecide, 2 = tfm, 3 = tfm(pp=0), 4 = tdeint(mode=2), 5 = blindmatch ...formerly 2
precision = default(precision,1)
data=NTSCanalyse(c,th_film=th_film,th_prog=th_prog,th_film2=th_film2,tol=tol,precision=precision)
NTSCconvert(c,data,th_bob=th_bob,speedup=speedup,show=show,mode=mode,filter=filter,blend=blend,deblocker=deblocker, IVTCtype=IVTCtype)
c.height==576? deblocker==0? c : c.deblocker(quant=deblocker,ipp=true) : last
}
function NTSCanalyse (clip c, float "th_film", int "th_film2", int "th_prog", float "tol", int "precision", bool "show")
{
# output clip is teeny coloured clip in same space as input
# red = FILM
# green = progressive
# blue = interlaced
show=default(show,false)
order = c.getparity()==true? 1 : 0
global isfade=true
global filmnum=-4
global progtele=0
global th_film=default(th_film,.3)
global th_film2=default(th_film2,10)
#global th_prog=default(th_prog,2)
global th_prog=default(th_prog,30)
global tol=default(tol,.1)
global precision=default(precision,1)
#d = c.horizontalreduceby2().bob(1,0,height=c.height/2).converttoyv12()
d = c.bicubicresize(32*precision,c.height,1/3.,1/3.,16,0,c.width-32,c.height).separatefields().bicubicresize(32*precision,32*precision,1/3.,1/3.,0,8,32*precision,(c.height/2.)-16).converttoyv12()
global film_c = d
global film_d = d.selectevery(2,0)
global f01 = mt_lutxy(film_c.selecteven(),film_c.selectodd(),expr="x y - abs")#.mt_inpand(mode=mt_rectangle(0,2))
global f02 = mt_lutxy(film_c.selectevery(2,0), film_c.selectevery(2,2),expr="x y - abs")
global f13 = mt_lutxy(film_c.selectevery(2,1), film_c.selectevery(2,3),expr="x y - abs")
global b1f1 = mt_lutxy(film_c.selectevery(2,-1), film_c.selectevery(2,1),expr="x y - abs")
global b02 = mt_lutxy(film_c.selectevery(2,0), film_c.selectevery(2,-2),expr="x y - abs")
global f24 = mt_lutxy(film_c.selectevery(2,2), film_c.selectevery(2,4),expr="x y - abs")
global b13 = mt_lutxy(film_c.selectevery(2,-1), film_c.selectevery(2,-3),expr="x y - abs")
global b24 = mt_lutxy(film_c.selectevery(2,-2), film_c.selectevery(2,-4),expr="x y - abs")
global f35 = mt_lutxy(film_c.selectevery(2,3), film_c.selectevery(2,5),expr="x y - abs")
global b35 = mt_lutxy(film_c.selectevery(2,-3), film_c.selectevery(2,-5),expr="x y - abs")
global NTSCanalyse_red = blankclip(film_d,width=8,height=4,color=$ff0000)
global NTSCanalyse_green = blankclip(film_d,width=8,height=4,color=$00ff00)
global NTSCanalyse_blue = blankclip(film_d,width=8,height=4,color=$0000ff)
film_d1 = scriptclip(NTSCanalyse_blue,"isfilm==1? NTSCanalyse_red : isprog==1? NTSCanalyse_green : NTSCanalyse_blue")
#film_d2 = frameevaluate(film_d1,"isprog= f01.yplanemax(tol) <= th_prog ? 1 : 0")
film_d2 = frameevaluate(film_d1,"isprog= f01.yplanemax() <= th_prog ? 1 : 0")
film_d3 = frameevaluate(film_d2,"""
\ isfilm= filmnum!=current_frame? 0 : (b1f1.yplanemax() < th_film2) ? 1 :
\ (f02.yplanemax() < th_film2) && (b35.yplanemax() < th_film2) ? 1 :
\ (b02.yplanemax() < th_film2) && (f35.yplanemax() < th_film2) ? 1 :
\ (b13.yplanemax() < th_film2) && (f24.yplanemax() < th_film2) ? 1 :
\ (f13.yplanemax() < th_film2) && (b24.yplanemax() < th_film2) ? 1 :
\ (f24.yplanemax() < th_film2) && (b13.yplanemax() < th_film2) ? 1 :
\ (b24.yplanemax() < th_film2) && (f13.yplanemax() < th_film2) ? 1 : 0 """)
film_d4 = frameevaluate(film_d3,"""
\ filmnum= (b1f1.averageluma() < th_film) ? current_frame :
\ (f02.averageluma() < th_film) && (b35.averageluma() < th_film) ? current_frame :
\ (b02.averageluma() < th_film) && (f35.averageluma() < th_film) ? current_frame :
\ (b13.averageluma() < th_film) && (f24.averageluma() < th_film) ? current_frame :
\ (f13.averageluma() < th_film) && (b24.averageluma() < th_film) ? current_frame :
\ (f24.averageluma() < th_film) && (b13.averageluma() < th_film) ? current_frame :
\ (b24.averageluma() < th_film) && (f13.averageluma() < th_film) ? current_frame : filmnum """)
show==true? overlay(c,film_d4) : film_d4
}
function NTSCconvert (clip c, clip data, bool "speedup", int "th_bob", int "mode", bool "show", string "filter", bool "blend", int "deblocker",int "IVTCtype")
{
# mode 1 = blend non-film frames to 50i
# mode 2 = try to motion-compensate non-film frames to 25p or 50i
speedup=default(speedup,true)
th_bob=default(th_bob,2)
blend=default(blend,true)
mode=default(mode,1)
show=default(show,false)
filter = default(filter,"last")
deblocker = default(deblocker,0)
IVTCtype = default(IVTCtype,4) # 1 = telecide, 2 = tfm, 3 = tfm(pp=0), 4 = tdeint(mode=2)
outnum = speedup==true? 48000 : 50000
outden = speedup==true? 1001 : 1000
order = c.getparity()==true? 1 : 0
c = deblocker==0? c : c.deblocker(quant=deblocker,ipp=true)
d = c
#global bobbed = d.leakkernelbob(order=order,threshold=th_bob,sharp=true,twoway=true).assumeframebased()
global bobbed = d.tdeint(1,order,expand=4,mthreshl=th_bob)
NTSCconvert_60i = mode==1? bobbed.blendfps(outnum/float(outden),1.25).changefps(outnum,outden).resizetopal(false,false) : bobbed.salfps(outnum/float(outden),protection2=60).changefps(outnum,outden).resizetopal(false,false)
NTSCconvert_30p = mode==1? d.blendfps(outnum/float(outden),1.25).changefps(outnum/2,outden).resizetopal(false,false) : d.salfps(outnum/float(2*outden),protection2=50).resizetopal(false,false).changefps(outnum/2,outden)
IVTCtype==1? d.telecide(order=order,guide=1).decimate().resizetopal(false,false) :\
IVTCtype==2? d.tfm(order=order,pp=6,chroma=true).decimate().resizetopal(false,false) :\
IVTCtype==3? d.tfm(order=order,pp=0,chroma=false).decimate().resizetopal(false,false) :\
d.tdeint(2,-1,expand=4,tryweave=true,cthresh=3,mi=24,mthreshl=6).decimate().resizetopal(false,false)
eval(filter)
NTSCconvert_24pfilter = last
global NTSCconvert_24p = speedup==true?
\ NTSCconvert_24pfilter.changefps(outnum/2,outden) :
\ (blend==true)? NTSCconvert_24pfilter.blendfps(50,1.25).changefps(outnum,outden).interlace(order=1):
\ NTSCconvert_24pfilter.changefps(outnum,outden).interlace(order=1)
NTSCconvert_60i
eval(filter)
interlace(order=1)
global NTSCconvert_60i = last
#NTSCconvert_30p
#eval(filter)
#mode==1? last : last.interlace(order=1)
#global NTSCconvert_30p = last
#NTSCconvert_24p
#eval(filter)
#
#global NTSCconvert_24p = last
global NTSCconvert_data = data.assumetff().medianblurt(0,0,2).blendfps(outnum/float(outden*2)).changefps(outnum/2,outden)
#global NTSCconvert_data = data.changefps(outnum/2,outden)
global NTSCconvert_red = blankclip(NTSCconvert_data,color=$ff0000)
global NTSCconvert_green = blankclip(NTSCconvert_data,color=$00ff00)
global NTSCconvert_blue = blankclip(NTSCconvert_data,color=$0000ff)
global NTSCconvert_isred = mt_lutxy(NTSCconvert_red,NTSCconvert_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCconvert_isgreen = mt_lutxy(NTSCconvert_green,NTSCconvert_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCconvert_24p,"yplanemax(NTSCconvert_isred)==0 ? NTSCconvert_24p : NTSCconvert_60i")
#scriptclip(NTSCconvert_24p,"yplanemax(NTSCconvert_isred)==0 ? NTSCconvert_24p : yplanemax(NTSCconvert_isgreen)==0 ? NTSCconvert_30p : NTSCconvert_60i")
speedup==true? last.assumefps(25,true).SSRC(48000) : last
show==true? overlay(last,data.changefps(outnum/2,outden)) : last
assumetff()
c.height==576? c : last
}
function NTSCfilter (clip c, clip data, string filter, bool "show")
{
show=default(show,false)
order = c.getparity()==true? 1 : 0
bobbed = c.assumeframebased().leakkernelbob(order=order,threshold=2)
bobbed.selecteven()
eval(filter)
evn=last
bobbed.selectodd()
eval(filter)
odd=last
interleave(evn,odd)
interlace(order=order)
global NTSCfilter_60i = last
c
eval(filter)
global NTSCfilter_30p = last
c.tdeint(2,1,tryweave=true,cthresh=2,mi=24,mtnmode=1,mthreshl=2).decimate()
eval(filter)
changefps(c.framerate*2).interlace(order=order)
global NTSCfilter_24p = last
global NTSCfilter_data = data
global NTSCfilter_red = blankclip(NTSCfilter_data,color=$ff0000)
global NTSCfilter_green = blankclip(NTSCfilter_data,color=$00ff00)
global NTSCfilter_isred = mt_lutxy(NTSCfilter_red,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCfilter_isgreen = mt_lutxy(NTSCfilter_green,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCfilter_30p,"yplanemax(NTSCfilter_isred)==0 ? NTSCfilter_24p : yplanemax(NTSCfilter_isgreen)==0 ? NTSCfilter_30p : NTSCfilter_60i")
show==true? overlay(last,NTSCfilter_data) : last
}
function NTSC120 (clip c, clip data, bool "show")
{
show=default(show,false)
order = c.getparity()==true? 1 : 0
bobbed = c.tdeint(1,order,tryweave=true,cthresh=4,mi=24,mtnmode=1,mthreshl=8)#leakkernelbob(order=order,threshold=2)
global NTSCfilter_60i = bobbed.changefps(120000,1001)
global NTSCfilter_30p = c.changefps(120000,1001)
global NTSCfilter_24p = bobbed.decimate().changefps(120000,1001)
global NTSCfilter_data = data.changefps(120000,1001)
global NTSCfilter_red = blankclip(NTSCfilter_data,color=$ff0000)
global NTSCfilter_green = blankclip(NTSCfilter_data,color=$00ff00)
global NTSCfilter_isred = mt_lutxy(NTSCfilter_red,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCfilter_isgreen = mt_lutxy(NTSCfilter_green,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCfilter_30p,"yplanemax(NTSCfilter_isred)==0 ? NTSCfilter_24p : yplanemax(NTSCfilter_isgreen)==0 ? NTSCfilter_30p : NTSCfilter_60i")
show==true? overlay(last,NTSCfilter_data) : last
}
function NTSCtoFPS (clip c, clip data, int "num", int "den", bool "show")
{
show=default(show,false)
num=default(num,25000)
den=default(den,1000)
order = c.getparity()==true? 1 : 0
bobbed = c.tdeint(1,order,tryweave=true,cthresh=4,mi=24,mtnmode=1,mthreshl=8)#leakkernelbob(order=order,threshold=2)
matched = c.tfm(order=order,pp=6,micmatching=0).decimate()
global NTSCtoFPS_60i = bobbed.salfps(num/float(den),protection2=30,iterate=4)
global NTSCtoFPS_30p = c.salfps(num/float(den),protection2=30,iterate=4)
global NTSCtoFPS_24p = bobbed.decimate().salfps(num/float(den),protection2=30,iterate=4)
global NTSCtoFPS_data = data.changefps(num,den)
global NTSCtoFPS_red = blankclip(NTSCtoFPS_data,color=$ff0000)
global NTSCtoFPS_green = blankclip(NTSCtoFPS_data,color=$00ff00)
global NTSCtoFPS_isred = mt_lutxy(NTSCtoFPS_red,NTSCtoFPS_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCtoFPS_isgreen = mt_lutxy(NTSCtoFPS_green,NTSCtoFPS_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCtoFPS_30p,"yplanemax(NTSCtoFPS_isred)==0 ? NTSCtoFPS_24p : yplanemax(NTSCtoFPS_isgreen)==0 ? NTSCtoFPS_30p : NTSCtoFPS_60i")
show==true? overlay(last,NTSCtoFPS_data) : last
}
function resizetopal (clip c, bool "soft", bool "speedup")
{
soft=default(soft,false)
speedup=default(speedup,true)
soft==false? c.addborders(0,2,0,2).lanczosresize(c.width,576,0,2+(c.height-483.84)/2,c.width,483.84) : c.addborders(0,2,0,2).bicubicresize(c.width,576,1,0,0,2+(c.height-483.84)/2,c.width,483.84)
speedup==true? last.assumefps(25,true).SSRC(48000) : last
c.height==576? c : last
}
function interlace (clip interlace_c, int "order")
{
order=default(order,1)
interlace_d= interlace_c.framecount()%2==0? interlace_c : interlace_c.assumefps(interlace_c.framerate)++interlace_c.selectevery(interlace_c.framecount,interlace_c.framecount-1).assumefps(interlace_c.framerate)
order==1? interlace_d.assumeframebased().assumetff().separatefields().selectevery(4,0,3).weave() :
\ interlace_d.assumeframebased().assumebff().separatefields().selectevery(4,0,3).weave()
}
function deblocker (clip c,int "quant",int "th",int "radius", bool "deblock",bool "depump",bool "conv",bool "ipp",int "modh", int "modv")
{
quant=default(quant,8)
th=default(th,3)
radius=default(radius,8)
deblock=default(deblock,true)
depump=default(depump,false)
conv=default(conv,false)
ipp=default(ipp,false)
modh=default(modh,20)
modv=default(modv,40)
c = (c.width*c.height%256==0)? c : mod16(c)#.limiter()
blurd = (conv==true)?c.wideblur(4,conv): (depump==true)? c.bilinearresize(4*(c.width/8),4*(c.height/8)) : c.bilinearresize(4*(c.width/8),4*(c.height/8)).bicubicresize(c.width,c.height,1,0)
highpass=(conv==true)?mt_makediff(blurd,c,y=3,u=3,v=3): (depump==true)? mt_makediff(blurd.bicubicresize(c.width,c.height,1,0),c,y=3,u=3,v=3) : mt_makediff(blurd,c,y=3,u=3,v=3)
deblocked=(deblock==true) ? highpass.blindpp(quant=quant,cpu=4,ipp=ipp,moderate_h=modh,moderate_v=modv) : highpass
nopump=mt_makediff(blurd,deblocked,y=3,u=3,v=3)
depumped=blurd.temporalsoften(2,th,th,32,2)#.removedirt()
pump=(conv==true)?mt_makediff(depumped,deblocked,y=3,u=3,v=3):mt_makediff(depumped.bicubicresize(c.width,c.height,1,0),deblocked,y=3,u=3,v=3)
(depump==true) ? pump : nopump
(c.width*c.height%256==0)? last : unmod16(last)
}
function combblur(clip c, int threshold)
{
mt_merge(c.mt_convolution("1","1 2 1",y=3,u=3,v=3).mt_convolution("1","-1 6 -1",y=3,u=3,v=3),c,c.combmask(threshold,threshold,y=3,u=3,v=3).mt_expand(mode=mt_rectangle(0,1),y=3,u=3,v=3).mt_inflate(y=3,u=3,v=3),y=3,u=3,v=3)
}
now, it's not complete, but everything (i believe) is in place to make this a real ripper.
it probably needs to be optimised. while things are film it's quite fast (well, not really), but once things get 30p or 60i, things slow down a tad, especially when mocomp is on.
usage:
this is a client-server model, like mvtools and depan. this makes things less efficient, but it's all i could think of as a way to framerate-convert the results of film detection - make 3 different colours in a tiny 8x4 clip that represent the footage type, then changefps those to get to 48fps, then compare colours and treat the footage accordingly on the client end.
here's an example:
...source clip...
data=last.NTSCanalyse()
NTSCconvert(last,data) # or it could be last.NTSCconvert(data)
...filters...
or, since v0.91:
...source...
autoPAL()
to run filters:
...source...
data=last.ntscanalyse()
ntscfilter(last,data,"...filters...")
or:
...source...
autoPAL(speedup=true,filter="...filters...")
what you'll get is a 50i clip that's been sped up 4%, film style. audio is handled too, if there is any, so it should all be in sync.
requires:
-clouded's motionprotectedfps and motion package
-a nice deinterlacer like tdeint. field-matching is a good idea, as my script just works on the frames you give it.
-masktools v2
have fun y'all!
http://forum.doom9.org/showthread.php?t=67161
a few days ago after being linked from the recent monty-python thread.
i remembered trying it out and seeing 30p pans get decimated as film, so i came up with this:
####
##
## NTSC tools 0.93, by Sal, aka Mug
##
## takes an NTSC clip, finds Film, 30p and 60i parts and gives them special treatment
## use it to convert to PAL with 4% speed-up (ie 23.976 to 25 fps)
##
####
function AutoPAL (clip c, bool "speedup", float "th_film", int "th_film2", int "th_prog", int "th_bob", float "tol", bool "show", int "mode", string "filter", bool "blend", int "deblocker", int "IVTCtype", int "precision")
{
speedup=default(speedup,false)
blend=default(blend,true)
th_film=default(th_film,.4)#.15)
th_film2=default(th_film2,5)
th_prog=default(th_prog,4)
th_bob=default(th_bob,8)
tol=default(tol,1.5)
show=default(show,false)
mode=default(mode,1)
filter=default(filter,"last")
deblocker=default(deblocker,0)
IVTCtype = default(IVTCtype,4) # 1 = telecide, 2 = tfm, 3 = tfm(pp=0), 4 = tdeint(mode=2), 5 = blindmatch ...formerly 2
precision = default(precision,1)
data=NTSCanalyse(c,th_film=th_film,th_prog=th_prog,th_film2=th_film2,tol=tol,precision=precision)
NTSCconvert(c,data,th_bob=th_bob,speedup=speedup,show=show,mode=mode,filter=filter,blend=blend,deblocker=deblocker, IVTCtype=IVTCtype)
c.height==576? deblocker==0? c : c.deblocker(quant=deblocker,ipp=true) : last
}
function NTSCanalyse (clip c, float "th_film", int "th_film2", int "th_prog", float "tol", int "precision", bool "show")
{
# output clip is teeny coloured clip in same space as input
# red = FILM
# green = progressive
# blue = interlaced
show=default(show,false)
order = c.getparity()==true? 1 : 0
global isfade=true
global filmnum=-4
global progtele=0
global th_film=default(th_film,.3)
global th_film2=default(th_film2,10)
#global th_prog=default(th_prog,2)
global th_prog=default(th_prog,30)
global tol=default(tol,.1)
global precision=default(precision,1)
#d = c.horizontalreduceby2().bob(1,0,height=c.height/2).converttoyv12()
d = c.bicubicresize(32*precision,c.height,1/3.,1/3.,16,0,c.width-32,c.height).separatefields().bicubicresize(32*precision,32*precision,1/3.,1/3.,0,8,32*precision,(c.height/2.)-16).converttoyv12()
global film_c = d
global film_d = d.selectevery(2,0)
global f01 = mt_lutxy(film_c.selecteven(),film_c.selectodd(),expr="x y - abs")#.mt_inpand(mode=mt_rectangle(0,2))
global f02 = mt_lutxy(film_c.selectevery(2,0), film_c.selectevery(2,2),expr="x y - abs")
global f13 = mt_lutxy(film_c.selectevery(2,1), film_c.selectevery(2,3),expr="x y - abs")
global b1f1 = mt_lutxy(film_c.selectevery(2,-1), film_c.selectevery(2,1),expr="x y - abs")
global b02 = mt_lutxy(film_c.selectevery(2,0), film_c.selectevery(2,-2),expr="x y - abs")
global f24 = mt_lutxy(film_c.selectevery(2,2), film_c.selectevery(2,4),expr="x y - abs")
global b13 = mt_lutxy(film_c.selectevery(2,-1), film_c.selectevery(2,-3),expr="x y - abs")
global b24 = mt_lutxy(film_c.selectevery(2,-2), film_c.selectevery(2,-4),expr="x y - abs")
global f35 = mt_lutxy(film_c.selectevery(2,3), film_c.selectevery(2,5),expr="x y - abs")
global b35 = mt_lutxy(film_c.selectevery(2,-3), film_c.selectevery(2,-5),expr="x y - abs")
global NTSCanalyse_red = blankclip(film_d,width=8,height=4,color=$ff0000)
global NTSCanalyse_green = blankclip(film_d,width=8,height=4,color=$00ff00)
global NTSCanalyse_blue = blankclip(film_d,width=8,height=4,color=$0000ff)
film_d1 = scriptclip(NTSCanalyse_blue,"isfilm==1? NTSCanalyse_red : isprog==1? NTSCanalyse_green : NTSCanalyse_blue")
#film_d2 = frameevaluate(film_d1,"isprog= f01.yplanemax(tol) <= th_prog ? 1 : 0")
film_d2 = frameevaluate(film_d1,"isprog= f01.yplanemax() <= th_prog ? 1 : 0")
film_d3 = frameevaluate(film_d2,"""
\ isfilm= filmnum!=current_frame? 0 : (b1f1.yplanemax() < th_film2) ? 1 :
\ (f02.yplanemax() < th_film2) && (b35.yplanemax() < th_film2) ? 1 :
\ (b02.yplanemax() < th_film2) && (f35.yplanemax() < th_film2) ? 1 :
\ (b13.yplanemax() < th_film2) && (f24.yplanemax() < th_film2) ? 1 :
\ (f13.yplanemax() < th_film2) && (b24.yplanemax() < th_film2) ? 1 :
\ (f24.yplanemax() < th_film2) && (b13.yplanemax() < th_film2) ? 1 :
\ (b24.yplanemax() < th_film2) && (f13.yplanemax() < th_film2) ? 1 : 0 """)
film_d4 = frameevaluate(film_d3,"""
\ filmnum= (b1f1.averageluma() < th_film) ? current_frame :
\ (f02.averageluma() < th_film) && (b35.averageluma() < th_film) ? current_frame :
\ (b02.averageluma() < th_film) && (f35.averageluma() < th_film) ? current_frame :
\ (b13.averageluma() < th_film) && (f24.averageluma() < th_film) ? current_frame :
\ (f13.averageluma() < th_film) && (b24.averageluma() < th_film) ? current_frame :
\ (f24.averageluma() < th_film) && (b13.averageluma() < th_film) ? current_frame :
\ (b24.averageluma() < th_film) && (f13.averageluma() < th_film) ? current_frame : filmnum """)
show==true? overlay(c,film_d4) : film_d4
}
function NTSCconvert (clip c, clip data, bool "speedup", int "th_bob", int "mode", bool "show", string "filter", bool "blend", int "deblocker",int "IVTCtype")
{
# mode 1 = blend non-film frames to 50i
# mode 2 = try to motion-compensate non-film frames to 25p or 50i
speedup=default(speedup,true)
th_bob=default(th_bob,2)
blend=default(blend,true)
mode=default(mode,1)
show=default(show,false)
filter = default(filter,"last")
deblocker = default(deblocker,0)
IVTCtype = default(IVTCtype,4) # 1 = telecide, 2 = tfm, 3 = tfm(pp=0), 4 = tdeint(mode=2)
outnum = speedup==true? 48000 : 50000
outden = speedup==true? 1001 : 1000
order = c.getparity()==true? 1 : 0
c = deblocker==0? c : c.deblocker(quant=deblocker,ipp=true)
d = c
#global bobbed = d.leakkernelbob(order=order,threshold=th_bob,sharp=true,twoway=true).assumeframebased()
global bobbed = d.tdeint(1,order,expand=4,mthreshl=th_bob)
NTSCconvert_60i = mode==1? bobbed.blendfps(outnum/float(outden),1.25).changefps(outnum,outden).resizetopal(false,false) : bobbed.salfps(outnum/float(outden),protection2=60).changefps(outnum,outden).resizetopal(false,false)
NTSCconvert_30p = mode==1? d.blendfps(outnum/float(outden),1.25).changefps(outnum/2,outden).resizetopal(false,false) : d.salfps(outnum/float(2*outden),protection2=50).resizetopal(false,false).changefps(outnum/2,outden)
IVTCtype==1? d.telecide(order=order,guide=1).decimate().resizetopal(false,false) :\
IVTCtype==2? d.tfm(order=order,pp=6,chroma=true).decimate().resizetopal(false,false) :\
IVTCtype==3? d.tfm(order=order,pp=0,chroma=false).decimate().resizetopal(false,false) :\
d.tdeint(2,-1,expand=4,tryweave=true,cthresh=3,mi=24,mthreshl=6).decimate().resizetopal(false,false)
eval(filter)
NTSCconvert_24pfilter = last
global NTSCconvert_24p = speedup==true?
\ NTSCconvert_24pfilter.changefps(outnum/2,outden) :
\ (blend==true)? NTSCconvert_24pfilter.blendfps(50,1.25).changefps(outnum,outden).interlace(order=1):
\ NTSCconvert_24pfilter.changefps(outnum,outden).interlace(order=1)
NTSCconvert_60i
eval(filter)
interlace(order=1)
global NTSCconvert_60i = last
#NTSCconvert_30p
#eval(filter)
#mode==1? last : last.interlace(order=1)
#global NTSCconvert_30p = last
#NTSCconvert_24p
#eval(filter)
#
#global NTSCconvert_24p = last
global NTSCconvert_data = data.assumetff().medianblurt(0,0,2).blendfps(outnum/float(outden*2)).changefps(outnum/2,outden)
#global NTSCconvert_data = data.changefps(outnum/2,outden)
global NTSCconvert_red = blankclip(NTSCconvert_data,color=$ff0000)
global NTSCconvert_green = blankclip(NTSCconvert_data,color=$00ff00)
global NTSCconvert_blue = blankclip(NTSCconvert_data,color=$0000ff)
global NTSCconvert_isred = mt_lutxy(NTSCconvert_red,NTSCconvert_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCconvert_isgreen = mt_lutxy(NTSCconvert_green,NTSCconvert_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCconvert_24p,"yplanemax(NTSCconvert_isred)==0 ? NTSCconvert_24p : NTSCconvert_60i")
#scriptclip(NTSCconvert_24p,"yplanemax(NTSCconvert_isred)==0 ? NTSCconvert_24p : yplanemax(NTSCconvert_isgreen)==0 ? NTSCconvert_30p : NTSCconvert_60i")
speedup==true? last.assumefps(25,true).SSRC(48000) : last
show==true? overlay(last,data.changefps(outnum/2,outden)) : last
assumetff()
c.height==576? c : last
}
function NTSCfilter (clip c, clip data, string filter, bool "show")
{
show=default(show,false)
order = c.getparity()==true? 1 : 0
bobbed = c.assumeframebased().leakkernelbob(order=order,threshold=2)
bobbed.selecteven()
eval(filter)
evn=last
bobbed.selectodd()
eval(filter)
odd=last
interleave(evn,odd)
interlace(order=order)
global NTSCfilter_60i = last
c
eval(filter)
global NTSCfilter_30p = last
c.tdeint(2,1,tryweave=true,cthresh=2,mi=24,mtnmode=1,mthreshl=2).decimate()
eval(filter)
changefps(c.framerate*2).interlace(order=order)
global NTSCfilter_24p = last
global NTSCfilter_data = data
global NTSCfilter_red = blankclip(NTSCfilter_data,color=$ff0000)
global NTSCfilter_green = blankclip(NTSCfilter_data,color=$00ff00)
global NTSCfilter_isred = mt_lutxy(NTSCfilter_red,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCfilter_isgreen = mt_lutxy(NTSCfilter_green,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCfilter_30p,"yplanemax(NTSCfilter_isred)==0 ? NTSCfilter_24p : yplanemax(NTSCfilter_isgreen)==0 ? NTSCfilter_30p : NTSCfilter_60i")
show==true? overlay(last,NTSCfilter_data) : last
}
function NTSC120 (clip c, clip data, bool "show")
{
show=default(show,false)
order = c.getparity()==true? 1 : 0
bobbed = c.tdeint(1,order,tryweave=true,cthresh=4,mi=24,mtnmode=1,mthreshl=8)#leakkernelbob(order=order,threshold=2)
global NTSCfilter_60i = bobbed.changefps(120000,1001)
global NTSCfilter_30p = c.changefps(120000,1001)
global NTSCfilter_24p = bobbed.decimate().changefps(120000,1001)
global NTSCfilter_data = data.changefps(120000,1001)
global NTSCfilter_red = blankclip(NTSCfilter_data,color=$ff0000)
global NTSCfilter_green = blankclip(NTSCfilter_data,color=$00ff00)
global NTSCfilter_isred = mt_lutxy(NTSCfilter_red,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCfilter_isgreen = mt_lutxy(NTSCfilter_green,NTSCfilter_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCfilter_30p,"yplanemax(NTSCfilter_isred)==0 ? NTSCfilter_24p : yplanemax(NTSCfilter_isgreen)==0 ? NTSCfilter_30p : NTSCfilter_60i")
show==true? overlay(last,NTSCfilter_data) : last
}
function NTSCtoFPS (clip c, clip data, int "num", int "den", bool "show")
{
show=default(show,false)
num=default(num,25000)
den=default(den,1000)
order = c.getparity()==true? 1 : 0
bobbed = c.tdeint(1,order,tryweave=true,cthresh=4,mi=24,mtnmode=1,mthreshl=8)#leakkernelbob(order=order,threshold=2)
matched = c.tfm(order=order,pp=6,micmatching=0).decimate()
global NTSCtoFPS_60i = bobbed.salfps(num/float(den),protection2=30,iterate=4)
global NTSCtoFPS_30p = c.salfps(num/float(den),protection2=30,iterate=4)
global NTSCtoFPS_24p = bobbed.decimate().salfps(num/float(den),protection2=30,iterate=4)
global NTSCtoFPS_data = data.changefps(num,den)
global NTSCtoFPS_red = blankclip(NTSCtoFPS_data,color=$ff0000)
global NTSCtoFPS_green = blankclip(NTSCtoFPS_data,color=$00ff00)
global NTSCtoFPS_isred = mt_lutxy(NTSCtoFPS_red,NTSCtoFPS_data,yexpr="x y - abs",y=3,u=1,v=1)
global NTSCtoFPS_isgreen = mt_lutxy(NTSCtoFPS_green,NTSCtoFPS_data,yexpr="x y - abs",y=3,u=1,v=1)
scriptclip(NTSCtoFPS_30p,"yplanemax(NTSCtoFPS_isred)==0 ? NTSCtoFPS_24p : yplanemax(NTSCtoFPS_isgreen)==0 ? NTSCtoFPS_30p : NTSCtoFPS_60i")
show==true? overlay(last,NTSCtoFPS_data) : last
}
function resizetopal (clip c, bool "soft", bool "speedup")
{
soft=default(soft,false)
speedup=default(speedup,true)
soft==false? c.addborders(0,2,0,2).lanczosresize(c.width,576,0,2+(c.height-483.84)/2,c.width,483.84) : c.addborders(0,2,0,2).bicubicresize(c.width,576,1,0,0,2+(c.height-483.84)/2,c.width,483.84)
speedup==true? last.assumefps(25,true).SSRC(48000) : last
c.height==576? c : last
}
function interlace (clip interlace_c, int "order")
{
order=default(order,1)
interlace_d= interlace_c.framecount()%2==0? interlace_c : interlace_c.assumefps(interlace_c.framerate)++interlace_c.selectevery(interlace_c.framecount,interlace_c.framecount-1).assumefps(interlace_c.framerate)
order==1? interlace_d.assumeframebased().assumetff().separatefields().selectevery(4,0,3).weave() :
\ interlace_d.assumeframebased().assumebff().separatefields().selectevery(4,0,3).weave()
}
function deblocker (clip c,int "quant",int "th",int "radius", bool "deblock",bool "depump",bool "conv",bool "ipp",int "modh", int "modv")
{
quant=default(quant,8)
th=default(th,3)
radius=default(radius,8)
deblock=default(deblock,true)
depump=default(depump,false)
conv=default(conv,false)
ipp=default(ipp,false)
modh=default(modh,20)
modv=default(modv,40)
c = (c.width*c.height%256==0)? c : mod16(c)#.limiter()
blurd = (conv==true)?c.wideblur(4,conv): (depump==true)? c.bilinearresize(4*(c.width/8),4*(c.height/8)) : c.bilinearresize(4*(c.width/8),4*(c.height/8)).bicubicresize(c.width,c.height,1,0)
highpass=(conv==true)?mt_makediff(blurd,c,y=3,u=3,v=3): (depump==true)? mt_makediff(blurd.bicubicresize(c.width,c.height,1,0),c,y=3,u=3,v=3) : mt_makediff(blurd,c,y=3,u=3,v=3)
deblocked=(deblock==true) ? highpass.blindpp(quant=quant,cpu=4,ipp=ipp,moderate_h=modh,moderate_v=modv) : highpass
nopump=mt_makediff(blurd,deblocked,y=3,u=3,v=3)
depumped=blurd.temporalsoften(2,th,th,32,2)#.removedirt()
pump=(conv==true)?mt_makediff(depumped,deblocked,y=3,u=3,v=3):mt_makediff(depumped.bicubicresize(c.width,c.height,1,0),deblocked,y=3,u=3,v=3)
(depump==true) ? pump : nopump
(c.width*c.height%256==0)? last : unmod16(last)
}
function combblur(clip c, int threshold)
{
mt_merge(c.mt_convolution("1","1 2 1",y=3,u=3,v=3).mt_convolution("1","-1 6 -1",y=3,u=3,v=3),c,c.combmask(threshold,threshold,y=3,u=3,v=3).mt_expand(mode=mt_rectangle(0,1),y=3,u=3,v=3).mt_inflate(y=3,u=3,v=3),y=3,u=3,v=3)
}
now, it's not complete, but everything (i believe) is in place to make this a real ripper.
it probably needs to be optimised. while things are film it's quite fast (well, not really), but once things get 30p or 60i, things slow down a tad, especially when mocomp is on.
usage:
this is a client-server model, like mvtools and depan. this makes things less efficient, but it's all i could think of as a way to framerate-convert the results of film detection - make 3 different colours in a tiny 8x4 clip that represent the footage type, then changefps those to get to 48fps, then compare colours and treat the footage accordingly on the client end.
here's an example:
...source clip...
data=last.NTSCanalyse()
NTSCconvert(last,data) # or it could be last.NTSCconvert(data)
...filters...
or, since v0.91:
...source...
autoPAL()
to run filters:
...source...
data=last.ntscanalyse()
ntscfilter(last,data,"...filters...")
or:
...source...
autoPAL(speedup=true,filter="...filters...")
what you'll get is a 50i clip that's been sped up 4%, film style. audio is handled too, if there is any, so it should all be in sync.
requires:
-clouded's motionprotectedfps and motion package
-a nice deinterlacer like tdeint. field-matching is a good idea, as my script just works on the frames you give it.
-masktools v2
have fun y'all!