#Helper functions:

	#revert PAL-DV to YV12 for quality reasons; needs yuy2 input (ie. canopus-dv-decoder)
	function reYV12(clip i)
	{	
		
		yx = i.converttoyv12().greyscale()
		x  = i.separatefields().assumeframebased().separatefields().selectevery(4, 0, 2).weave()
		ux = x.utoy().converttoyv12()
		vx = x.vtoy().converttoyv12()
		ytouv(ux, vx, yx)
	}
	

	#wrapping bob() ....
	function dumbbob(clip i, int "height")
	{
		i.bob(0, 1, height = height)
		getparity(i) ? assumetff() : assumebff()
	}

	#fast ELA-bob, se=0 by default => dumb bob
	function tomsbob(clip i, int "se")
	{	
		se = default(se, 0)
		interleave(i.tomsmocomp(-1, 0, 0),i.doubleweave().selectodd().tomsmocomp(-1, 0, 0))
		assumeframebased()
		getparity(i) ? assumetff() : assumebff()
	}

	#fast kernel bob, th=0 by default => dumb bob
	function krnlbob(clip i, int "th")
	{	
		th = default(th, 0)
		i.leakkernelbob(order = (getparity(i) ? 1 : 0), threshold = th)
		assumeframebased()
		getparity(i) ? assumetff() : assumebff()
	}

	#slow, but accurate EEDI-bob, always dumb ;)
	function eedibob(clip i)
	{
		getparity(i) ? i.separatefields().eedi2(field = 3) : i.separatefields().eedi2(field = 2)
		assumeframebased()
		getparity(i) ? assumetff() : assumebff()
	}

	#cut down progressive to interlaced
	function reinterlace(clip i, bool "enableyv12output")
	{	
		enableyv12output = default(enableyv12output,false)
		i = (isyv12(i) && enableyv12output) ? i : i.converttoyuy2()
		i.separatefields().selectevery(4, 0, 3).weave()
	}

	#Deinterlacer that avoids residual cobing with tricky motion at all cost.
	# with bobbing-overweights-weaving-technology-tm
	function securedeint(clip i, int "th", int "l", int "type")
	{	
		function staticmask(clip e, int th, int l)
		{	
			e0  = e.motionmask(thy1 = 0, thy2 = th, thc1 = 0, thc2 = round(th / 1.5), thSD = 255, u = 3, v = 3)
			#\.temporalsoften(6, 1, 1)
			e1  = e0.trim(1, 0)
			e2  = e0.trim(2, 0)
			e3  = e0.trim(3, 0)
			e4  = e0.trim(4, 0)
			e5  = e0.trim(5, 0)
			e6  = e0.trim(6, 0)
			e7  = e0.trim(7, 0)

			ea0 = logic(e0,  e1,  "OR", u = 3, v = 3)
			ea1 = logic(e2,  e3,  "OR", u = 3, v = 3)
			ea2 = logic(e4,  e5,  "OR", u = 3, v = 3)
			ea3 = logic(e6,  e7,  "OR", u = 3, v = 3)

			eb0 = logic(ea0, ea1, "OR", u = 3, v = 3)
			eb1 = logic(ea2, ea3, "OR", u = 3, v = 3)

			ec  = logic(eb0, eb1, "OR", u = 3, v = 3)

			(l==0) ? ec .duplicateframe(0).duplicateframe(0).duplicateframe(0) :\
			(l==1) ? eb0.duplicateframe(0) :\
			(l==2) ? ea0 : e0
		}

		th   = default(th, 6)
    		l    = default(l, 1)
		type = default(type, 3)

		i.converttoyv12(interlaced = true).separatefields()
		e = selecteven().staticmask(th, l)
		o = selectodd() .staticmask(th, l)
		m = interleave(e, o).undot().dumbbob() 
		m = merge(m.trim(1, 0), m, 0.5).binarize(u = 3,v = 3)

		b = (type==0) ? i.dumbbob() : (type==1) ? i.tomsbob() : (type==2) ? i.krnlbob() : i.eedibob()
		d=i.doubleweave()

		isyv12(i) ? maskedmerge(b, d, m, u = 3, v = 3) : overlay(b, d, mask = m.converttoyuy2(), greymask = false)

		assumeframebased()
		getparity(i) ? assumetff() : assumebff()
	}

	function mvconv(clip i, int "num", int "den", int "blk")
	{       
		blk = default(blk, 8)
		blk = (blk==8) ? 8 : 4

		tm=true
		#lm=10000

		rate= (defined(num) && defined (den)) ? -1 : framerate(i)
		i = isYV12(i) ? i : i.convertttoyv12()

		backward_vec = i.MVAnalyse(isb = true, blksize=blk, truemotion=tm, pel=2, idx=4)
		forward_vec = i.MVAnalyse(isb = false, blksize=blk, truemotion=tm, pel=2, idx=4)
		cropped = (blk==8) ? i.crop(4,4,-4,-4) : i.crop(2,2,-6,-6) 
		# by half of block size 8 
		backward_vec2 = cropped.MVAnalyse(isb = true, blksize=blk, truemotion=tm, pel=2, idx=3)
		forward_vec2 = cropped.MVAnalyse(isb = false, blksize=blk, truemotion=tm, pel=2, idx=3)
		

		o = (rate==50) ? i.MVFlowFps2(backward_vec,forward_vec,backward_vec2,forward_vec2,num=60000, den=1001,idx=4,idx2=3)  : \
		((rate>59.9) && (rate<60.01)) ? i.MVFlowFps2(backward_vec,forward_vec,backward_vec2,forward_vec2,num=50,idx=4,idx2=3) : \
		i.MVFlowFps2(backward_vec,forward_vec,backward_vec2,forward_vec2,num=num,den=den,idx=4,idx2=3)

		return o
	}


function MVbob(clip c,int "blksize", int "pel", int "th", int "ths", int "bobth", bool "quick")
{
	#internal helper function to find static areas (experimental)
	function static_o_matic(clip i, clip j, int thy, int thc)
	{
		a = isyv12(i) ? i.motionmask(thy1=0,thy2=thy,thc1=0,thc2=thc,thSD=255,y=3,u=3,v=3) \
			      : i.converttoyv12().motionmask(thy1=0,thy2=thy,thc1=0,thc2=thc,thSD=255,y=3,u=3,v=3)
	#	a=i.converttoyv12().motionmask(thy1=0,thy2=thy,thc1=0,thc2=thc,thSD=255,y=3,u=3,v=3)
		logic(a,a.trim(1,0),"OR",y=3,u=3,v=3)
		RemoveGrain(1) # undot()
		overlay (i,j, mask=last) 
		#MaskedMerge(i,j,last,U=3,V=3) # 
	}

#disable all scene detection of mvcompensate(), because mvbob() is self-correcting due to the corrector()
	sc=255 

# threshold for correcting failed compensated motion 
	th=default(th,8) 

# threshold for correcting static areas
	ths=default(ths,3)

# deinterlacing threshold for the motion vector analysis do not go much higher than 10
	bobth=default(bobth,6)

#denoise the video for the bobber (better static areas for noisy video, crappy)
	quick=default(quick,false)

#defaults for the mocomp
	blksize=default(blksize,8)
	scd=(blksize==8)? 300 : round(300/4)
	pel=default(pel,2)


#determine clip Fieldorder
	order=(c.getparity==true)? 1:0
	yv12 = isyv12(c)

	# bobx 	-> kerneldeinterlaced video, used for motion search

	# mvf   -> motion vectors forward
	# mvb   -> motion vectors backward

	# bobd 	-> blurred bobx for error checking (correcting false compensated blocks!)
	# bobdf -> forward  compensated bobd
	# bobdb -> backward compensated bobd

	# fields-> ELA-deinterlaced fields for motion compensated output and compensation correction
	# mcf   -> forward  compensated fields
	# mcb   -> backward compensated fields
	# cv    -> average of mcb and mcf

	# dpf   -> forward  compensated fields (global motion)
	# dpb   -> backward compensated fields (global motion)
	# dp    -> average of dpb and dpf

	# mc    -> corrected motion compensated result

# create clip for motion analysis and hole-filling
	bobc = quick ? 	c.securedeint(th=bobth, type=1) : c.securedeint(th=bobth, type=3)
	bobd = yv12 ? bobc : bobc.converttoyv12()
	bobd = bobd.removegrain(11)


# create clip for motion compensation
	fields = bobc
	fields= yv12 ? fields : fields.converttoyv12()

# create motion vectors
	mvf=bobd.mvanalyse(blksize=blksize,pel=pel,isb=false,chroma=true,idx=1,truemotion=true)
	mvb=bobd.mvanalyse(blksize=blksize,pel=pel,isb=true, chroma=true,idx=1,truemotion=true)

# create clips for mismatch detection
	bobdf=bobd.mvflow(mvf,idx=1).removegrain(11).removegrain(11)
	bobdb=bobd.mvflow(mvb,idx=1).removegrain(11).removegrain(11)
	bobdc=bobd.removegrain(11).removegrain(11)

# create the motion compensated clip that are passed through to the output
	mcf=fields.mvflow(mvf,idx=2)
	mcb=fields.mvflow(mvb,idx=2)
	cv=merge(mcf,mcb,0.5)

# detect mismatches of mvtools and replace them with motion adaptive bobbed areas
	mc=corrector(bobdc,fields,   bobdf,bobdb,  mcf,mcb,   mode=0,th=th)

# merge corrected output and raw output into one frame horizontally
	mc = quick ? mc : stackhorizontal(mc,cv) 

# select the correct lines 
	compensated_even= mc.selecteven().separatefields().selectodd() 
	compensated_odd = mc.selectodd() .separatefields().selecteven()

# ensure correct chroma format
	compensated_even=yv12 ? compensated_even : compensated_even.converttoyuy2()
	compensated_odd =yv12 ? compensated_odd  : compensated_odd .converttoyuy2()

# merge them with the original fields
	original_even=c.separatefields().selecteven()
	original_odd =c.separatefields().selectodd()

	even = quick ? interleave(original_even, compensated_even).weave() : interleave(stackhorizontal(original_even, original_even), compensated_even).weave()
	odd  = quick ? interleave(original_odd , compensated_odd ).weave() : interleave(stackhorizontal(original_odd , original_odd ), compensated_odd ).weave()


	interleave(even,odd)

#separate into corrected and raw video || correct static areas
	mc_corr = quick ? last : crop(last,0,0,width/2,0)
	mc_raw  = quick ? last : crop(last,width/2,0,0,0)
	quick ? last : static_o_matic(mc_raw,mc_corr,ths,ths)
	(order==1) ? last.assumetff() : last.assumebff()

}  


# needed plugins


