kevinm
29th November 2004, 04:42
Hi experts,
First let me acknowledge the amazing work you guys are doing but developing some of the amazing functions which I am using in my script below.
My question:
I have been stitching together many useful functions which I have gathered from this forum. I started off with Xesdeen's 'Poorman's NTSC to PAL conversion script. Then, seeking to further improve the conversion I read about a number of things I needed to fix or improve upon, so I began to add the following functions to the base script:
Reinterpolate411
Convolution3d
limitedSharpen
MVbob
I am at the point where I have managed to get the script to run but it is inceardibly slow. It seems that MVbob is the main culprit, however I have a number of color space conversions which I would like to try to minimize. I have read that there are some YV12 versions of Convolution3d for example but I am not sure of the consequences of using YV12 vs YUY2
It seems to me that it has to be a good thing to reduce the number of color space conversions but what is the best space to work in?
Before I added MVbob I was able to do everything in YUY2 but it seems I have no choice with MVbob but to use YV12.
I don't mind admitting that I am struggling a little bit with all this, I find these scripts terribly complex and it was some relief after many hours of debugging that I actually got it to run.
I wonder if one of you experts would be so kind as to look at my script (below) and suggest any changes which would give me the speed increase which I am looking for,
thanks,
Kevin
PluginPath = "c:\AVISynth25\Plugins\"
LoadPlugin(PluginPath + "warpsharp.dll")
LoadPlugin(PluginPath + "MPEGDecoder.dll")
LoadPlugin(PluginPath + "SmoothDeinterlacer.dll")
LoadPlugin(PluginPath + "mpasource.dll")
LoadPlugin(PluginPath + "MPEG2Dec3.dll")
LoadPlugin(PluginPath + "ReInterpolate411.dll")
LoadPlugin(PluginPath + "convolution3d.dll")
LoadPlugin(PluginPath + "MaskTools.dll")
LoadPlugin(PluginPath + "kerneldeint.dll")
LoadPlugin(PluginPath + "dgbob.dll")
LoadPlugin(PluginPath + "Decomb521.dll")
LoadPlugin(PluginPath + "SmoothDeinterlacer.dll")
LoadPlugin(PluginPath + "UnDot.dll")
LoadPlugin(PluginPath + "TomsMoComp.dll")
LoadPlugin(PluginPath + "MVTools.dll")
##########################################################################################
##########################################################################################
##
## The NTSC to PAL conversion script
##
##########################################################################################
##########################################################################################
# Codec used to read AVI Type2 video input ..
Input = AVISource("G:\WinDV\Tape5\tape5_ntsc_2.04-08-15_13-45.00.avi") # Have to use Type2
# Note, the color space at this point is RGB24
# Trim the clip
Trim(Input, 1, 200)
ConvertToYUY2(interlaced=true)
Input = Reinterpolate411() # Fix chroma sampling bug
InputTopFieldFirst = false
OutputFrameRate = 25
OutputWidth = 720
OutputHeight = 576
OutputTopFieldFirst = false
ConversionType = 0
Input = Input.ConvertToYV12(interlaced=true) # Need to be in YV12 colorspace for mvanalyse to work!
vpro = Input.mvbob()
vinfps = Input.framerate < OutputFrameRate ? \
vpro.BilinearResize(OutputWidth, OutputHeight) : \
vpro
vfps = ConversionType == 2 ? \
vinfps.ConvertFPS(OutputFrameRate * 2, zone = 80) : \
ConversionType == 1 ? \
vinfps.ConvertFPS(OutputFrameRate * 2) : \
vinfps.ChangeFPS(OutputFrameRate * 2)
voutfps = OutputFrameRate <= Input.framerate ? \
vfps.BilinearResize(OutputWidth, OutputHeight) : \
vfps
vfields = voutfps.SeparateFields()
# Perform some limited sharpening in the fields ..
#
vfields = LimitedSharpen(vfields, smode=3,wide=true,Lmode=2,overshoot=17,strength=100,soft=true)
vfields = vfields.ConvertToYUY2()
odd=vfields.SelectOdd.Convolution3D(1, 6, 10, 6, 8, 2.8, 0)
evn=vfields.SelectEven.Convolution3D(1, 6, 10, 6, 8, 2.8, 0)
odd=vfields.SelectOdd
evn=vfields.SelectEven
vfields=Interleave(evn,odd)
vlace = OutputTopFieldFirst ? \
vfields.SelectEvery(4, 1, 2) : \
vfields.SelectEvery(4, 0, 3)
vout = vlace.Weave()
vout = Info(vout)
return(vout)
################################################################################################
################################################################################################
##
## The following are some useful functions from the Doom9 forum ..
##
################################################################################################
################################################################################################
################################################################################################
#
# LimitedSharpen()
#
# A multi-purpose sharpener by Didée
#
################################################################################################
function LimitedSharpen( clip clp,
\ float "ss_x", float "ss_y",
\ int "dest_x", int "dest_y",
\ int "Smode" , int "strength", int "radius",
\ int "Lmode", bool "wide", int "overshoot",
\ bool "soft", int "edgemode", bool "special",
\ int "exborder" )
{
ox = clp.width
oy = clp.height
ss_x = default( ss_x, 1.5 )
ss_y = default( ss_y, 1.5 )
dest_x = default( dest_x, ox )
dest_y = default( dest_y, oy )
Smode = default( Smode, 3 )
strength = Smode==1
\ ? default( strength, 160 )
\ : default( strength, 100 )
strength = Smode==2&&strength>100 ? 100 : strength
radius = default( radius, 2 )
Lmode = default( Lmode, 1 )
wide = default( wide, false )
overshoot= default( overshoot, 1)
overshoot= overshoot<0 ? 0 : overshoot
soft = default( soft, false )
edgemode = default( edgemode, 0 )
special = default( special, false )
exborder = default( exborder, 0)
#radius = round( radius*(ss_x+ss_y)/2) # If it's you, Mug Funky - feel free to activate it again
xxs=round(ox*ss_x/8)*8
yys=round(oy*ss_y/8)*8
smx=exborder==0?dest_x:round(dest_x/Exborder/4)*4
smy=exborder==0?dest_y:round(dest_y/Exborder/4)*4
clp.isYV12() ? clp : clp.converttoyv12()
ss_x != 1.0 || ss_y != 1.0 ? last.lanczosresize(xxs,yys) : last
tmp = last
edge = logic( tmp.DEdgeMask(0,255,0,255,"5 10 5 0 0 0 -5 -10 -5", divisor=2)
\ ,tmp.DEdgeMask(0,255,0,255,"5 0 -5 10 0 -10 5 0 -5", divisor=2)
\ ,"max").levels(0,0.86,128,0,255,false)
bright_limit = (soft == true) ? tmp.blur(1.0) : tmp
dark_limit = bright_limit.inpand()
bright_limit = bright_limit.expand()
dark_limit = (wide==false) ? dark_limit : dark_limit .inflate.deflate.inpand()
bright_limit = (wide==false) ? bright_limit : bright_limit.deflate.inflate.expand()
minmaxavg = special==false
\ ? yv12lutxy(bright_limit,dark_limit,yexpr="x y + 2 /")
\ : maskedmerge(dark_limit,bright_limit,tmp,Y=3,U=-128,V=-128,useMMX=true)
Str=string(float(strength)/100.0)
normsharp = Smode==1 ? unsharpmask(strength,radius,0)
\ : Smode==2 ? sharpen(float(strength)/100.0)
\ : yv12lutxy(tmp,minmaxavg,yexpr="x x y - "+Str+" * +")
OS = string(overshoot)
Lmode == 1 ? yv12lutxy( bright_limit, normsharp, yexpr="y x "+OS+" + < y x "+OS+" + ?")
\ : yv12lutxy( bright_limit, normsharp, yexpr="y x "+OS+" + < y x y x - "+OS+" - 1 2 / ^ + "+OS+" + ?")
Lmode == 1 ? yv12lutxy( dark_limit, last, yexpr="y x "+OS+" - > y x "+OS+" - ?")
\ : yv12lutxy( dark_limit, last, yexpr="y x "+OS+" - > y x x y - "+OS+" - 1 2 / ^ - "+OS+" - ?")
edgemode==0 ? NOP
\ : edgemode==1
\ ? MaskedMerge(tmp,last,edge.inflate.inflate.blur(1.0),Y=3,U=1,V=1,useMMX=true)
\ : MaskedMerge(last,tmp,edge.inflate.inflate.blur(1.0),Y=3,U=1,V=1,useMMX=true)
(ss_x != 1.0 || ss_y != 1.0)
\ || (dest_x != ox || dest_y != oy) ? lanczosresize(dest_x,dest_y) : last
ex=blankclip(last,width=smx,height=smy,color=$FFFFFF).addborders(2,2,2,2).coloryuv(levels="TV->PC")
\.blur(1.3).inpand().blur(1.3).bicubicresize(dest_x,dest_y,1.0,.0)
tmp=clp.lanczosresize(dest_x,dest_y)
clp.isYV12() ? ( exborder==0 ? tmp.mergeluma(last)
\ : maskedmerge(tmp,last,ex,Y=3,U=1,V=1,useMMX=true) )
\ : ( exborder==0 ? tmp.mergeluma(last.converttoyuy2())
\ : tmp.mergeluma( maskedmerge(tmp.converttoyv12(),last,ex,Y=3,U=1,V=1,useMMX=true)
\ .converttoyuy2()) )
return last
}
##################################################################################################
#
# 'MVbob by 'scharfis_brain
#
# See the following link for discussion on 'MVbob' ..
#
# http://forum.doom9.org/showthread.php?s=&threadid=84725&perpage=20&highlight=mvbob&pagenumber=2
#
##################################################################################################
function MVbob(clip c,int "blksize", int "pel", int "lambda", int "thy", int "thc", int "bobth", bool "predenoise", bool "showmask")
{
#Helper functions:
function tmcstupid(clip c)
{ input=c.converttoyuy2(interlaced=true).separatefields.tomsmocomp(1,-1,0)
a = getparity(input) ? input.selectodd : input.selecteven
b = getparity(input) ? input.selecteven : input.selectodd
a=stackvertical(a.crop(0,0,0,1-a.height),a.crop(0,0,0,-1))
output = getparity(input) ? interleave(b,a) : interleave(a,b)
output.assumeframebased().converttoyv12()
}
#disable all scene detection, because it is self-correcting
sc=255
showmask=default(showmask,false)
# luma and chroma thresholds for correcting false detected motion
thy=default(thy,20)
thc=default(thc,10)
# threshold of kerneldeint
bobth=default(bobth,8)
#denoise the video for kerneldeint (better static areas for noisy video)
predenoise=default(predenoise,false)
blksize=default(blksize,4)
scd=(blksize==8)? 300 : round(300/4)
pel=default(pel,2)
#I decided lambda=0 being better, cause it stupidly trys to catch everything. errors are corrected afterwards.
lambda=default(lambda,0)
#determine clip Fieldorder
order=(c.getparity==true)? 1:0
# create clip for motion analysis and hole-filling
bobx=predenoise ? c.temporalsoften(2,5,7) : c
bobx=bobx.kernelbob(order=order,threshold=bobth).undot()
bobd=bobx.verticalreduceby2()
#bobd=bobd.lanczos4resize(bobx.width,bobx.height)
bobd=bobd.tomsmocomp(-1,-1,0).undot()
# create clip for motion compensation
fields=c.tmcstupid().undot()
# define clip for hole filling
fields1=bobx
# create motion vectors
mvf=bobd.mvanalyse(blksize=blksize,pel=pel,isb=false,compensate=false,search=3,searchparam=10)
mvb=bobd.mvanalyse(blksize=blksize,pel=pel,isb=true, compensate=false,search=3,searchparam=10)
# detect mismatched areas of motion compensation
bobdf=bobd.mvcompensate(mvf,mode=1,thscd1=scd,thSCD2=sc)
bobdb=bobd.mvcompensate(mvb,mode=1,thscd1=scd,thSCD2=sc)
difff=interleave(bobdf,bobd).motionmask(thy1=thy,thy2=thy,thc1=thc,thc2=thc,thSD=sc).selectodd()
diffb=interleave(bobdb,bobd).motionmask(thy1=thy,thy2=thy,thc1=thc,thc2=thc,thSD=sc).selectodd()
diff=logic(difff,diffb,"OR")
# do the deinterlacing
even1=c.separatefields().selecteven()
odd1a=fields.mvcompensate(mvf,mode=1,thscd1=scd,thSCD2=sc)
odd1a=maskedmerge(odd1a,fields1,difff,y=3,u=3,v=3).selecteven()
odd1b=fields.mvcompensate(mvb,mode=1,thscd1=scd,thSCD2=sc)
odd1b=maskedmerge(odd1b,fields1,diffb,y=3,u=3,v=3).selecteven()
odd1=mergeluma(odd1a,odd1b,0.5).mergechroma(odd1b,0.5)
odd1=(order==1) ? odd1.separatefields().selecteven() : odd1.separatefields().selectodd()
even2=c.separatefields().selectodd()
odd2a=fields.mvcompensate(mvf,mode=1,thscd1=scd,thSCD2=sc)
odd2a=maskedmerge(odd2a,fields1,difff,y=3,u=3,v=3).selectodd()
odd2b=fields.mvcompensate(mvb,mode=1,thscd1=scd,thSCD2=sc)
odd2b=maskedmerge(odd2b,fields1,diffb,y=3,u=3,v=3).selectodd()
odd2=mergeluma(odd2a,odd2b,0.5).mergechroma(odd2b,0.5)
odd2=(order==1) ? odd2.separatefields().selectodd() : odd2.separatefields().selecteven()
even=interleave(even1,odd1)
even=even.weave()
odd=interleave(even2,odd2)
odd=odd.weave()
# output
interleave(even,odd)
analysis=maskedmerge(last.levels(0,1,255,0,200),diff,diff,y=3,u=3,v=3)
showmask ? analysis : last
}
First let me acknowledge the amazing work you guys are doing but developing some of the amazing functions which I am using in my script below.
My question:
I have been stitching together many useful functions which I have gathered from this forum. I started off with Xesdeen's 'Poorman's NTSC to PAL conversion script. Then, seeking to further improve the conversion I read about a number of things I needed to fix or improve upon, so I began to add the following functions to the base script:
Reinterpolate411
Convolution3d
limitedSharpen
MVbob
I am at the point where I have managed to get the script to run but it is inceardibly slow. It seems that MVbob is the main culprit, however I have a number of color space conversions which I would like to try to minimize. I have read that there are some YV12 versions of Convolution3d for example but I am not sure of the consequences of using YV12 vs YUY2
It seems to me that it has to be a good thing to reduce the number of color space conversions but what is the best space to work in?
Before I added MVbob I was able to do everything in YUY2 but it seems I have no choice with MVbob but to use YV12.
I don't mind admitting that I am struggling a little bit with all this, I find these scripts terribly complex and it was some relief after many hours of debugging that I actually got it to run.
I wonder if one of you experts would be so kind as to look at my script (below) and suggest any changes which would give me the speed increase which I am looking for,
thanks,
Kevin
PluginPath = "c:\AVISynth25\Plugins\"
LoadPlugin(PluginPath + "warpsharp.dll")
LoadPlugin(PluginPath + "MPEGDecoder.dll")
LoadPlugin(PluginPath + "SmoothDeinterlacer.dll")
LoadPlugin(PluginPath + "mpasource.dll")
LoadPlugin(PluginPath + "MPEG2Dec3.dll")
LoadPlugin(PluginPath + "ReInterpolate411.dll")
LoadPlugin(PluginPath + "convolution3d.dll")
LoadPlugin(PluginPath + "MaskTools.dll")
LoadPlugin(PluginPath + "kerneldeint.dll")
LoadPlugin(PluginPath + "dgbob.dll")
LoadPlugin(PluginPath + "Decomb521.dll")
LoadPlugin(PluginPath + "SmoothDeinterlacer.dll")
LoadPlugin(PluginPath + "UnDot.dll")
LoadPlugin(PluginPath + "TomsMoComp.dll")
LoadPlugin(PluginPath + "MVTools.dll")
##########################################################################################
##########################################################################################
##
## The NTSC to PAL conversion script
##
##########################################################################################
##########################################################################################
# Codec used to read AVI Type2 video input ..
Input = AVISource("G:\WinDV\Tape5\tape5_ntsc_2.04-08-15_13-45.00.avi") # Have to use Type2
# Note, the color space at this point is RGB24
# Trim the clip
Trim(Input, 1, 200)
ConvertToYUY2(interlaced=true)
Input = Reinterpolate411() # Fix chroma sampling bug
InputTopFieldFirst = false
OutputFrameRate = 25
OutputWidth = 720
OutputHeight = 576
OutputTopFieldFirst = false
ConversionType = 0
Input = Input.ConvertToYV12(interlaced=true) # Need to be in YV12 colorspace for mvanalyse to work!
vpro = Input.mvbob()
vinfps = Input.framerate < OutputFrameRate ? \
vpro.BilinearResize(OutputWidth, OutputHeight) : \
vpro
vfps = ConversionType == 2 ? \
vinfps.ConvertFPS(OutputFrameRate * 2, zone = 80) : \
ConversionType == 1 ? \
vinfps.ConvertFPS(OutputFrameRate * 2) : \
vinfps.ChangeFPS(OutputFrameRate * 2)
voutfps = OutputFrameRate <= Input.framerate ? \
vfps.BilinearResize(OutputWidth, OutputHeight) : \
vfps
vfields = voutfps.SeparateFields()
# Perform some limited sharpening in the fields ..
#
vfields = LimitedSharpen(vfields, smode=3,wide=true,Lmode=2,overshoot=17,strength=100,soft=true)
vfields = vfields.ConvertToYUY2()
odd=vfields.SelectOdd.Convolution3D(1, 6, 10, 6, 8, 2.8, 0)
evn=vfields.SelectEven.Convolution3D(1, 6, 10, 6, 8, 2.8, 0)
odd=vfields.SelectOdd
evn=vfields.SelectEven
vfields=Interleave(evn,odd)
vlace = OutputTopFieldFirst ? \
vfields.SelectEvery(4, 1, 2) : \
vfields.SelectEvery(4, 0, 3)
vout = vlace.Weave()
vout = Info(vout)
return(vout)
################################################################################################
################################################################################################
##
## The following are some useful functions from the Doom9 forum ..
##
################################################################################################
################################################################################################
################################################################################################
#
# LimitedSharpen()
#
# A multi-purpose sharpener by Didée
#
################################################################################################
function LimitedSharpen( clip clp,
\ float "ss_x", float "ss_y",
\ int "dest_x", int "dest_y",
\ int "Smode" , int "strength", int "radius",
\ int "Lmode", bool "wide", int "overshoot",
\ bool "soft", int "edgemode", bool "special",
\ int "exborder" )
{
ox = clp.width
oy = clp.height
ss_x = default( ss_x, 1.5 )
ss_y = default( ss_y, 1.5 )
dest_x = default( dest_x, ox )
dest_y = default( dest_y, oy )
Smode = default( Smode, 3 )
strength = Smode==1
\ ? default( strength, 160 )
\ : default( strength, 100 )
strength = Smode==2&&strength>100 ? 100 : strength
radius = default( radius, 2 )
Lmode = default( Lmode, 1 )
wide = default( wide, false )
overshoot= default( overshoot, 1)
overshoot= overshoot<0 ? 0 : overshoot
soft = default( soft, false )
edgemode = default( edgemode, 0 )
special = default( special, false )
exborder = default( exborder, 0)
#radius = round( radius*(ss_x+ss_y)/2) # If it's you, Mug Funky - feel free to activate it again
xxs=round(ox*ss_x/8)*8
yys=round(oy*ss_y/8)*8
smx=exborder==0?dest_x:round(dest_x/Exborder/4)*4
smy=exborder==0?dest_y:round(dest_y/Exborder/4)*4
clp.isYV12() ? clp : clp.converttoyv12()
ss_x != 1.0 || ss_y != 1.0 ? last.lanczosresize(xxs,yys) : last
tmp = last
edge = logic( tmp.DEdgeMask(0,255,0,255,"5 10 5 0 0 0 -5 -10 -5", divisor=2)
\ ,tmp.DEdgeMask(0,255,0,255,"5 0 -5 10 0 -10 5 0 -5", divisor=2)
\ ,"max").levels(0,0.86,128,0,255,false)
bright_limit = (soft == true) ? tmp.blur(1.0) : tmp
dark_limit = bright_limit.inpand()
bright_limit = bright_limit.expand()
dark_limit = (wide==false) ? dark_limit : dark_limit .inflate.deflate.inpand()
bright_limit = (wide==false) ? bright_limit : bright_limit.deflate.inflate.expand()
minmaxavg = special==false
\ ? yv12lutxy(bright_limit,dark_limit,yexpr="x y + 2 /")
\ : maskedmerge(dark_limit,bright_limit,tmp,Y=3,U=-128,V=-128,useMMX=true)
Str=string(float(strength)/100.0)
normsharp = Smode==1 ? unsharpmask(strength,radius,0)
\ : Smode==2 ? sharpen(float(strength)/100.0)
\ : yv12lutxy(tmp,minmaxavg,yexpr="x x y - "+Str+" * +")
OS = string(overshoot)
Lmode == 1 ? yv12lutxy( bright_limit, normsharp, yexpr="y x "+OS+" + < y x "+OS+" + ?")
\ : yv12lutxy( bright_limit, normsharp, yexpr="y x "+OS+" + < y x y x - "+OS+" - 1 2 / ^ + "+OS+" + ?")
Lmode == 1 ? yv12lutxy( dark_limit, last, yexpr="y x "+OS+" - > y x "+OS+" - ?")
\ : yv12lutxy( dark_limit, last, yexpr="y x "+OS+" - > y x x y - "+OS+" - 1 2 / ^ - "+OS+" - ?")
edgemode==0 ? NOP
\ : edgemode==1
\ ? MaskedMerge(tmp,last,edge.inflate.inflate.blur(1.0),Y=3,U=1,V=1,useMMX=true)
\ : MaskedMerge(last,tmp,edge.inflate.inflate.blur(1.0),Y=3,U=1,V=1,useMMX=true)
(ss_x != 1.0 || ss_y != 1.0)
\ || (dest_x != ox || dest_y != oy) ? lanczosresize(dest_x,dest_y) : last
ex=blankclip(last,width=smx,height=smy,color=$FFFFFF).addborders(2,2,2,2).coloryuv(levels="TV->PC")
\.blur(1.3).inpand().blur(1.3).bicubicresize(dest_x,dest_y,1.0,.0)
tmp=clp.lanczosresize(dest_x,dest_y)
clp.isYV12() ? ( exborder==0 ? tmp.mergeluma(last)
\ : maskedmerge(tmp,last,ex,Y=3,U=1,V=1,useMMX=true) )
\ : ( exborder==0 ? tmp.mergeluma(last.converttoyuy2())
\ : tmp.mergeluma( maskedmerge(tmp.converttoyv12(),last,ex,Y=3,U=1,V=1,useMMX=true)
\ .converttoyuy2()) )
return last
}
##################################################################################################
#
# 'MVbob by 'scharfis_brain
#
# See the following link for discussion on 'MVbob' ..
#
# http://forum.doom9.org/showthread.php?s=&threadid=84725&perpage=20&highlight=mvbob&pagenumber=2
#
##################################################################################################
function MVbob(clip c,int "blksize", int "pel", int "lambda", int "thy", int "thc", int "bobth", bool "predenoise", bool "showmask")
{
#Helper functions:
function tmcstupid(clip c)
{ input=c.converttoyuy2(interlaced=true).separatefields.tomsmocomp(1,-1,0)
a = getparity(input) ? input.selectodd : input.selecteven
b = getparity(input) ? input.selecteven : input.selectodd
a=stackvertical(a.crop(0,0,0,1-a.height),a.crop(0,0,0,-1))
output = getparity(input) ? interleave(b,a) : interleave(a,b)
output.assumeframebased().converttoyv12()
}
#disable all scene detection, because it is self-correcting
sc=255
showmask=default(showmask,false)
# luma and chroma thresholds for correcting false detected motion
thy=default(thy,20)
thc=default(thc,10)
# threshold of kerneldeint
bobth=default(bobth,8)
#denoise the video for kerneldeint (better static areas for noisy video)
predenoise=default(predenoise,false)
blksize=default(blksize,4)
scd=(blksize==8)? 300 : round(300/4)
pel=default(pel,2)
#I decided lambda=0 being better, cause it stupidly trys to catch everything. errors are corrected afterwards.
lambda=default(lambda,0)
#determine clip Fieldorder
order=(c.getparity==true)? 1:0
# create clip for motion analysis and hole-filling
bobx=predenoise ? c.temporalsoften(2,5,7) : c
bobx=bobx.kernelbob(order=order,threshold=bobth).undot()
bobd=bobx.verticalreduceby2()
#bobd=bobd.lanczos4resize(bobx.width,bobx.height)
bobd=bobd.tomsmocomp(-1,-1,0).undot()
# create clip for motion compensation
fields=c.tmcstupid().undot()
# define clip for hole filling
fields1=bobx
# create motion vectors
mvf=bobd.mvanalyse(blksize=blksize,pel=pel,isb=false,compensate=false,search=3,searchparam=10)
mvb=bobd.mvanalyse(blksize=blksize,pel=pel,isb=true, compensate=false,search=3,searchparam=10)
# detect mismatched areas of motion compensation
bobdf=bobd.mvcompensate(mvf,mode=1,thscd1=scd,thSCD2=sc)
bobdb=bobd.mvcompensate(mvb,mode=1,thscd1=scd,thSCD2=sc)
difff=interleave(bobdf,bobd).motionmask(thy1=thy,thy2=thy,thc1=thc,thc2=thc,thSD=sc).selectodd()
diffb=interleave(bobdb,bobd).motionmask(thy1=thy,thy2=thy,thc1=thc,thc2=thc,thSD=sc).selectodd()
diff=logic(difff,diffb,"OR")
# do the deinterlacing
even1=c.separatefields().selecteven()
odd1a=fields.mvcompensate(mvf,mode=1,thscd1=scd,thSCD2=sc)
odd1a=maskedmerge(odd1a,fields1,difff,y=3,u=3,v=3).selecteven()
odd1b=fields.mvcompensate(mvb,mode=1,thscd1=scd,thSCD2=sc)
odd1b=maskedmerge(odd1b,fields1,diffb,y=3,u=3,v=3).selecteven()
odd1=mergeluma(odd1a,odd1b,0.5).mergechroma(odd1b,0.5)
odd1=(order==1) ? odd1.separatefields().selecteven() : odd1.separatefields().selectodd()
even2=c.separatefields().selectodd()
odd2a=fields.mvcompensate(mvf,mode=1,thscd1=scd,thSCD2=sc)
odd2a=maskedmerge(odd2a,fields1,difff,y=3,u=3,v=3).selectodd()
odd2b=fields.mvcompensate(mvb,mode=1,thscd1=scd,thSCD2=sc)
odd2b=maskedmerge(odd2b,fields1,diffb,y=3,u=3,v=3).selectodd()
odd2=mergeluma(odd2a,odd2b,0.5).mergechroma(odd2b,0.5)
odd2=(order==1) ? odd2.separatefields().selectodd() : odd2.separatefields().selecteven()
even=interleave(even1,odd1)
even=even.weave()
odd=interleave(even2,odd2)
odd=odd.weave()
# output
interleave(even,odd)
analysis=maskedmerge(last.levels(0,1,255,0,200),diff,diff,y=3,u=3,v=3)
showmask ? analysis : last
}