meguIV: The Official Akiba-Online DVD Encoder (v1.0.1.1)

Rollyco

Team Tomoe
Oct 4, 2007
3,562
34
At the risk of jinxing it, after upgrading to SEt's MT Avisynth 2.6 I haven't experienced any mencoder.exe crashes. Woohoo! :grassdance:

If that continues, it'll be included in the upcoming meguIV 1.0.2.0.
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
At the risk of jinxing it, after upgrading to SEt's MT Avisynth 2.6 I haven't experienced any mencoder.exe crashes. Woohoo!

If that continues, it'll be included in the upcoming meguIV 1.0.2.0.
Excellent, looking forward to it! Are you planning to use QuickTGMC? There will be a new version tomorrow with an even faster "Draft" preset and support for progressive input (helpful to fix bad rips) amongst other things.

Did a couple of quick tests: SetMemoryMax (I dunno if you're planning to use it) - the need for memory depends on the TGMC settings - slower settings needing more. For example QTGMC-Slower can just get by on 256, but occasionally seems to run out of memory and slow down, especially if you add anything else to the script - 384 seems safer. QTGMC-Placebo needs around 512. Didn't test any others.

I've also been using SetMTMode(3,6) continuously now without problem for a good speed boost. Stresses the comp more than ever though - might be too much wear and tear for some...
 

Rollyco

Team Tomoe
Oct 4, 2007
3,562
34
Yes, it will include your QuickTGMC. The results of the "Slow" preset are just as good as the old TGMC preset to my eyes, but faster. I'm not sure how/if to include your faster QuickTGMC presets though. I admit the whole point of meguIV is a selfish one: to provide me with high-quality rips so that I don't have to encode things myself. Your "Medium" preset crosses that nebulous quality threshold of mine, below which I usually decide to get the DVDISO and rip it myself.

Then again, back when I had a crappy single core CPU, I certainly would have appreciated a good speedy one-click encoder. Maybe I can include all of the required .DLLs and offer some fast presets as a separate download for people to import if they so desire. Hm...

About setting threads to cores+1, I'm not sure how to programatically do that from within Avisynth.

I'm also not sure about including SetMemoryMax within the meguIV preset(s). I've been reading SEt's posts and my impression is that in MT builds of Avisynth, SetMemoryMax is a per-thread value.
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
I'm not sure how/if to include your faster QuickTGMC presets though. I admit the whole point of meguIV is a selfish one: to provide me with high-quality rips so that I don't have to encode things myself. Your "Medium" preset crosses that nebulous quality threshold of mine, below which I usually decide to get the DVDISO and rip it myself.
Some excellent content not using MeguIV - being badly ripped instead... I'd even take "Ultra Fast" over Handbrake. Make people aware of the faster MeguIV - may tempt some folk away from their crappy encoders. Then don't allow the use of [HQ] to those who rip below some threshold...?

Blu-ray. Have been playing with the meGUI source, most likely is possible to make one-click support blu-ray. But really need new presets for HD content.

About setting threads to cores+1, I'm not sure how to programatically do that from within Avisynth.
I'll bet there's a trick to doing it - I'll have a tinker...

SetMemoryMax is a per-thread value.
Doesn't appear that way from watching the memory used by mencoder, which is always around 1.3 to 1.6 * SetMemoryMax for me, whether I have 1 or 6 threads. Well, no matter, if it's all working now...
 

astrayred

Member
Mar 19, 2008
158
16
Excellent, looking forward to it! Are you planning to use QuickTGMC? There will be a new version tomorrow with an even faster "Draft" preset and support for progressive input (helpful to fix bad rips) amongst other things.

Did a couple of quick tests: SetMemoryMax (I dunno if you're planning to use it) - the need for memory depends on the TGMC settings - slower settings needing more. For example QTGMC-Slower can just get by on 256, but occasionally seems to run out of memory and slow down, especially if you add anything else to the script - 384 seems safer. QTGMC-Placebo needs around 512. Didn't test any others.

I've also been using SetMTMode(3,6) continuously now without problem for a good speed boost. Stresses the comp more than ever though - might be too much wear and tear for some...

Looking forward to the new version! And just in time too. I came across a video that seems to have mixed progressive and interlaced frames and it's driving me crazy as to how to fix it. It seems to me like I would need to deinterlace the interlaced parts, and double the FPS of the progressive parts. Unfortunately MVTools, which is the tool most often recommended for doubling FPS produces rubbish output. :/
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
I came across a video that seems to have mixed progressive and interlaced frames and it's driving me crazy as to how to fix it. It seems to me like I would need to deinterlace the interlaced parts, and double the FPS of the progressive parts.
You can handle your case with ordinary TGMC+SelectEven for 30fps output. If you're after 60fps output the progressive input verision of QTGMC won't help as it keeps the same frame-rate as the source - I'm not planning to add Motion Interpolation to QTGMC since that's a different task.

But it's not so hard to do 60fps in this situation - (this ISO had the same problem). If you know where to trim for the different interlaced and progressive areas, then a script like this will do it:
Code:
global MeGUI_darx = 16
global MeGUI_dary = 9
SetMTMode(3)
LoadPlugin("C:\Program Files\MeGUI\tools\dgindex\DGDecode.dll")
video=DGDecode_mpeg2source("C:\VID-001\VIDEO_TS\VTS_01_1.d2v")
SetMTMode(2)

video.trim(0,9999).DeInterlace() + video.trim(10000,14999).Interpolate() + video.trim(15000,0).DeInterlace()

function Deinterlace( clip Input, bool "FlipFields" )
{
	FlipFields = default( FlipFields, false )
	Input = (!FlipFields) ? Input : Input.ComplementParity()
	TGMC = Input.TempGaussMC_beta2( 2,1,1, EdiMode="nnedi2", SVthin=0.0 ) # or QuickTGMC
	return TGMC
}

function Interpolate( clip Input )
{
	Super = Input.MSuper( pel=2 )
	BVec = MAnalyse( Super, overlap=4, isb=true, search=3 )
	FVec = MAnalyse( Super, overlap=4, isb=false, search=3 )
	Flow = Input.MFlowFps( Super, BVec, FVec, num=0 )
	return Flow
}

You can automate the triming with combing-detection, but it's not perfect. Better to do it manually if there are only a few sections involved

Unfortunately MVTools, which is the tool most often recommended for doubling FPS produces rubbish output.
Not so, that script above uses it and MVTools is the very heart of TGMC too - it's an excellent plugin. Make sure you're using version 2 (plugin at bottom of page)
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
Latest QuickTGMC v2.2v2.3 is finished.

Main additions/changes:
- "Draft" preset - extremely high speed encoding designed for test rips
- Progressive input: use the TGMC algorithm for general denoising and stablization. Has special modes to re-rip material with lesser-quality deinterlacing (used on this rip (Junior material)).
- TGMC feature conversion complete
- Small speed-ups on some presets
- Sharpness settings normalized, default is now always 1.0 - which is roughly same regardless of setting

EDIT: Whoa, that was fast - version 2.3 upped so soon after 2.2? Had to fix a theoretical error with the new progressive modes. Added one more parameter I'd forgotten too...
 

astrayred

Member
Mar 19, 2008
158
16
Thanks for that script Vitreous. I must admit even after having TGMC'ed hundreds of videos I'm still pretty much a script kiddie. The finer points of TGMC remain out of reach for me.

I understand that MVTools is important to the operation of TGMC. The reason why I say it produces rubbish output when it comes to doubling FPS is because it produces funky artifacts with high motion scenes. I have tested this extensively. and the author of TGMC said so himself, now if only I could find his post where he said that...

So far, the best frame rate doubler I have found is MSU's Frame Rate Converter. Unfortunately this plugin hates multithreading and so the result is that it's really slow!
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
[MVTools] produces funky artifacts with high motion scenes...So far, the best frame rate doubler I have found is MSU's Frame Rate Converter
Yes, MVTools does suffer that problem - interpolating hi-speed or complex motion is virtually impossible. I've heard that one approach is to identify when motion is too complex and not try to interpolate, but blur instead. Maybe that's what the MSU plugin does - I've not heard of it before, thanks for the reference...
 

astrayred

Member
Mar 19, 2008
158
16
Yes, MVTools does suffer that problem - interpolating hi-speed or complex motion is virtually impossible. I've heard that one approach is to identify when motion is too complex and not try to interpolate, but blur instead. Maybe that's what the MSU plugin does - I've not heard of it before, thanks for the reference...

Did you give the MSU plugin a go?

BTW I don't know if its just me... But is anyone finding QTGMC 2.3 slower than previous versions? Previously I would get around 14 FPS easily with QuickTGMC(). Now I'm getting 11...
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
Previously I would get around 14 FPS easily with QuickTGMC(). Now I'm getting 11...
Which version and preset were you using before? Was there anything else significant in the script?

EDIT: Did some quick comparisons between 2.0, 2.1 and 2.3 (I'm assuming you weren't comparing with version 1.0). I can only detect a 1 or 2% slowdown in the versions after 2.0 caused by a deliberate tweak to improve the quality of the repair modes. Something I intended to return to. Doesn't explain your drop in speed - unless perhaps you have a very slow or low memory machine, in which case the effect might be greater (and the general increase in script length might be an issue too). In any case, try this version with the tweak removed:

[HIDE]
Code:
#------------------------------------------------------------------#
#                                                                  #
#                 QuickTGMC 2.3t, by Vitreous, 2010                #
#                                                                  #
# Deinterlacer using motion-compensated temporal gaussian blurring #
# Reworked version of TGMC geared for ease of use and speed tweaks #
#                                                                  #
#------------------------------------------------------------------#

# Version History:
# v2.3:  Added EdiExt (edeint in original TGMC)
#        Improved progressive input modes
# v2.2:  All rep values, SVThin and motion search settings supported
#        Better matching of Sbb
#        "Draft" preset
#        Support for progressive input (InputType)
#        Sharpness values/defaults normalized
# v2.1:  Supported most of the remaining core TGMC features:
#            EdiMode("NNEDI", "Yadif"), tr2(3), SLmode(3,4), SLRad, Sbb(2,3)
#        Added noise bypass (removal / restoration)
#        Added ShowSettings
# v2.0:  First fully featured version
#        Supported majority of core TGMC features
#        Additional speed tweaks:
#            NNSize, SrchClipPP, SubPel, Precise
#        Added Presets system and beginnings of Tunings
# v1.0:  First draft - high speed basic TGMC algorithm only

# Requires: 
#	MVTools2
#	RemoveGrain + Repair
#	MaskTools V2
#	AddGrainC (if using "Generate" mode for noise bypass)
#	Choice of: NNEDI2, NNEDI, EEDI2, Yadif or TDeInt+Yadif
#	[only TDeInt and AddGrainC beyond standard TGMC requirements]


#---------------------------------------

# Parameters
# """"""""""
#-Core Settings---
#	tr0          (0,1,2)         : Temporal gaussian blur radius used to create motion search clip
#	tr1          (0,1,2)         : Temporal smoothing radius used on interpolated clip to create inital output
#	tr2          (0,1,2,3)       : Temporal smoothing radius used for final stablization / denoising
#	rep0         (>= 0)          : Repair motion search clip  (0 = off) : only keep thin areas of difference from bob
#	rep1         (>= 0)          : Repair initial output clip (0 = off) : only keep thin areas of difference from edi
#	rep2         (>= 0)          : Repair final output clip   (0 = off) : --"--
#	                             : The rep values contain both 'ed' and 'od' settings for the function RemoveNonBobDiff at end of script, go there for details
#
#-Interpolation---
#	EdiMode      (string)        : Mode used for interpolation, choose from "NNEDI2", "NNEDI", "EEDI2", "Yadif" or "TDIYadif" (TDeInt+Yadif), otherwise uses Bob
#	NNSize       (0,1,2)         : Neural net size for NNEDI2
#	EdiQual      (1,2,3)         : Quality setting for NNEDI2, higher values for higher quality - but improvements are marginal
#	EdiMaxD      (>= 1)          : Spatial search distance for EEDI2
#	EdiExt       (clip)          : Provide externally created interpolated clip rather than use one of the above modes
#
#-Sharpness---
#	Sharpness    (>= 0.0)        : How much to resharpen the temporal gaussian blurred clip (default is always 1.0 unlike original TGMC)
#	SMode        (0,1,2)         : Resharpening mode: 0 = none, 1 = diff from 3x3 blur kernel, 2 = 3x3 kernel on vertical max/min average
#	SLMode       (0,1,2,3,4)     : Sharpness limiting: 0 = off, [1 = by spatial comparison, 2 = by temporal comparison] : done before 2nd temporal smooth
#	                             :                              [3 = by spatial comparison, 4 = by temporal comparison] : done after 2nd temporal smooth
#	SLRad        (>= 0)          : Temporal or spatial radius used with sharpness limiting (depends on SLMode). Temporal radius can only be 0,1 or 3
#	SOvs         (0..255)        : Amount of overshoot allowed with temporal sharpness limiting (SLMode == 2,4), i.e. allow some oversharpening
#	SVThin       (0.0...)        : How much to thin down 1-pixel wide lines that have been widened due to interpolation into neighboring field lines
#	Sbb          (0,1,2,3)       : Back blend (blurred) difference between pre & post sharpened clip (minor fidelity improvement) :
#	                             :   0 = Off, 1 = before sharpness limiting, 2 = after sharpness limiting, 3 = both
#
#-Noise Bypass---
#	NoiseBypass  (0,1,2)         : Noise bypass mode: 0 = disable, 1 = denoise source, storing the removed noise - add noise back at end of script, 
#	                             :                    2 = store noise found in source but don't remove it (let tgmc denoise) - add noise back at end of script
#	                             :                    Mode 1 softens if NoiseRemove is high & NoiseRestore is low, mode 2 sharpens if NoiseRestore is high
#	NoiseRemove  (0.0...1.0)     : How much noise/grain to extract from the source clip (before the TGMC process)
#	NoiseRestore (0.0...1.0...)  : How much of the removed noise/grain to restore (after the TGMC process), can be > 1.0 for strong effect
#	NoiseDeint   (string)        : When noise is taken from interlaced source, how to 'deinterlace' before restoring: "Bob", "DoubleWeave", "Copy" or "Generate"
#	                             :   "Bob" & "DoubleWeave" are standard, "Copy" doubles each noise line, "Generate" creates new noise lines by approximating
#	                             :   local variance. Any other value selects "DoubleWeave"
#	Sigma        (>= 0.0)        : Amount of noise known to be in the source - sensible values are 1.5 - 2.5 for DV. Must be high enough to find noticable noise
#	BT           (0...5)         : Block temporal size for noise removal (see FFT3DFilter docs)
#
#-Motion Search---
#	SrchClipPP   (0,1,2)         : Pre-processing for motion search clip, 0 = none, 1 = Gauss blur (spatial), 2 = Gauss + odd tweak from TGMC
#	SubPel       (1,2,4)         : Sub-pixel accuracy for motion analysis (1 = 1 pixel, 2 = 1/2 pixel, 4 = 1/4 pixel)
#	SubPelInterp (0,1,2)         : Interpolation used for sub-pixel motion analysis: 0 = bilinear (soft), 1 = bicubic (sharper), 2 = Weiner (sharpest)
#	Blocksize    (4,8,16,32)     : Size of blocks that are matched during motion analysis
#	Overlap      (< Blocksize/2) : How much to overlap motion analysis blocks (requires more blocks, but essential to smooth block edges in motion compenstion)
#	Search       (0...5)         : Search method used for matching motion blocks - see MVTools2 documentation for available algorithms
#	SearchParam  (0...)          : Parameter for search method chosen. For default search method (hexagon search) it is the search range
#	PelSearch    (0...)          : Search parameter (as above) for the finest sub-pixel level (see SubPel)
#	TrueMotion   (bool)          : Whether to use the 'truemotion' defaults from MAnalyse (see MVTools2 documentation)
#	Lambda       (0...)          : Motion vector field coherence - how much the motion analysis favors similar motion vectors for neighboring blocks
#	                             : Should be scaled by BlockSize*BlockSize/64
#	LSAD         (0...)          : How much to reduce need for vector coherence (i.e. Lambda above) if prediction of motion vector from neighbors is poor,
#	                             : typically in areas of complex motion. This value is scaled in MVTools (unlike Lambda)
#	PNew         (0...)          : Penalty for choosing a new motion vector for a block over an existing one - avoids chosing new vectors for minor gain
#	PLevel       (0,1,2)         : Mode for scaling lambda at different sub-pixel levels (?) - see MVTools2 documentation for choices
#	GlobalMotion (bool)          : Whether to estimate camera motion to assist in selecting block motion vectors
#	DCT          (0...10)        : Modes to use DCT (frequency analysis) as part of the block matching process - see MVTools2 documentation for choices
# 
#-Miscellaneous Features---
#	InputType    (0,1,2,3)       : Default = 0 for interlaced input. Values > 0 to accept progressive input - for stabilization and denoising (fps not changed)
#	                             : Mode 1 accepts plain progressive material. Modes 2 & 3 take deinterlaced material and recover / reweave half the fields
#	                             : to create interlaced material again. Mode 3 differs from mode 2 only in that it complements field parity of input
#	Border       (bool)          : Pad a little vertically while processing (doesn't affect output size) - use if there are artefacts on top and bottom edges
#	Precise      (bool)          : Set to false to use faster algorithms with *very* slight imprecision in places
#	Preset       (string)        : See below
#	Tuning       (string)        : See below
#	SafeMode     (bool)          : Avoid settings that potentially cause errors with other plugins
#	ShowSettings (bool)          : Display all the current parameter values - useful to find preset defaults


# Presets / Tunings
# """""""""""""""""
# The parameters "Preset" and "Tuning" set groups of parameters at once:
#	Preset : Choose from "Placebo","Very Slow","Slower","Slow","Medium","Fast","Faster","Very Fast","Super Fast","Ultra Fast" & "Draft". Default = "Slower"
#	Tuning : Choose from "None", "DV-SD", "DV-HD". Default is "None". 
# See table a short way into script below to see exact settings and to give an idea of how to tweak for speed / quality adjustments
# Manually entered parameters override presets/tunings
# Tunings are just an idea for development at the moment - need more variations for a range of source types
#
# To use Preset "Super Fast" / "Ultra Fast" (or EdiMode="TDIYadif" / "Yadif") you MUST follow the instructions by the Load_Stdcall_Plugin line below
#
# Default settings for script are:
#	QuickTGMC( Preset="Slower", Tuning="None" )
# which is closely equivalent to TempGaussMC_beta2( 2,2,1, EdiMode="nnedi2", SVthin=0.0, Border=false )


# Summary of differences from TGMC
# """"""""""""""""""""""""""""""""
# New speed tweaks:
#	EdiMode("TDIYadif"), NNSize, SrchClipPP, SubPel, Precise 
# New features:
#	Preset, Tuning, NoiseBypass, NoiseRemove, NoiseRestore, NoiseDeint, Sigma, BT, InputType, SafeMode, ShowSettings
#	Presets and tunings described above
#	Noise removal/restore settings provide a method to keep grain that is lost due to the TGMC algorithm's implicit denoising
#	Allows input of progressive or previously deinterlaced content using the InputType setting
# Unsupported:
#	lossless, pel2hr
# Variables in script, but not parameters
#	SCth1, SCth2, thSAD1, thSAD2
# Other notes:
#	Sharpness default is 1.0 regardless of settings - adjusted internally to give very roughly the same sharpness across settings / presets
#	SVThin defaults to 0, Border defaults to false
#	Draft mode supported as a preset - same purpose but different output
#	Parameter order same up to "EdiMode", a couple of 'lesser' parameters have had name changes for consistency
#	Output will never be pixel-identical to TGMC equivalent due to bug-fixes


function QuickTGMC( clip Input, int "tr0", int "tr1", int "tr2", int "rep0", int "rep1", int "rep2", string "EdiMode", int "NNSize", int "EdiQual", \
                    int "EdiMaxD", clip "EdiExt", float "Sharpness", int "SMode", int "SLMode", int "SLRad", int "SOvs", float "SVThin", int "Sbb", \
                    int "SrchClipPP", int "SubPel", int "SubPelInterp", int "BlockSize", int "Overlap", int "Search", int "SearchParam", int "PelSearch", \
                    bool "TrueMotion", int "Lambda", int "LSAD", int "PNew", int "PLevel", bool "GlobalMotion", int "DCT", int "NoiseBypass", \
                    float "NoiseRemove", float "NoiseRestore", string "NoiseDeint", float "Sigma", int "BT", int "InputType", bool "Border", bool "Precise", \
                    string "Preset", string "Tuning", bool "SafeMode", bool "ShowSettings" )
{
	#******** IMPORTANT: If using Preset="Super Fast" / "Ultra Fast", or EdiMode="TDIYadif" / "Yadif" provide the full path to
	#********            your yadif.dll plugin below (e.g. "C:\Program Files\AviSynth 2.5\plugins\yadif.dll"). Alternatively,
	#********            putting yadif.dll in the Windows\System32 folder and leaving this line alone may work for some
	Load_Stdcall_Plugin( "yadif.dll" )

	
	#---------------------------------------
	# Settings

	SafeMode = default( SafeMode, false )

	# Select preset / tuning
	Preset = default( Preset, "Slower" )
	pNum = (Preset == "Placebo"   ) ? 0 : \
	       (Preset == "Very Slow" ) ? 1 : \
	       (Preset == "Slower"    ) ? 2 : \
	       (Preset == "Slow"      ) ? 3 : \
	       (Preset == "Medium"    ) ? 4 : \
	       (Preset == "Fast"      ) ? 5 : \
	       (Preset == "Faster"    ) ? 6 : \
	       (Preset == "Very Fast" ) ? 7 : \
	       (Preset == "Super Fast") ? 8 : \
	       (Preset == "Ultra Fast") ? 9 : \
	       (Preset == "Draft"     ) ? 10 : 2
	Tuning = default( Tuning, "None" )
	tNum = (Tuning == "None"  ) ? 0 : \
	       (Tuning == "DV-SD" ) ? 1 : \
	       (Tuning == "DV-HD" ) ? 2 : 0
	
	# Tunings only affect blocksize in this version
	bs = Select( tNum,  16, 16, 32 )
	bs2 = (bs >= 16) ? 32 : bs*2
	ovf = (SafeMode) ? 2 : 4    # Overlap other than 1/2 blocksize sometimes causes crashes in MVTools (MT?)

	# Preset groups:                                     Placebo    V.Slow    Slower    Slow      Medium    Fast      Faster    V.Fast    S.Fast     U.Fast    Draft
	tr0          = default( tr0,          Select( pNum,  2,         2,        2,        2,        2,        2,        1,        1,        1,         1,        1       ))
	tr1          = default( tr1,          Select( pNum,  2,         2,        2,        1,        1,        1,        1,        1,        1,         1,        1       ))
	tr2          = default( tr2,          Select( pNum,  3,         2,        1,        1,        1,        0,        0,        0,        0,         0,        0       ))
	rep0         = default( rep0,         Select( pNum,  4,         4,        4,        4,        4,        4,        0,        0,        0,         0,        0       ))
	rep1         = default( rep1,         Select( pNum,  0,         0,        0,        0,        0,        0,        0,        0,        0,         0,        0       ))
	rep2         = default( rep2,         Select( pNum,  4,         4,        4,        4,        4,        4,        4,        4,        4,         0,        0       ))
	EdiMode      = default( EdiMode,      Select( pNum, "NNEDI2",  "NNEDI2", "NNEDI2", "NNEDI2", "NNEDI2", "NNEDI2", "NNEDI2", "NNEDI2", "TDIYadif","TDIYadif",""      ))
	NNSize       = default( NNSize,       Select( pNum,  2,         2,        1,        1,        0,        0,        0,        0,        0,         0,        0       ))
	SMode        = default( SMode,        Select( pNum,  2,         2,        2,        2,        2,        2,        2,        1,        2,         2,        0       ))
	SLMode       = default( SLMode,       Select( pNum,  2,         2,        2,        2,        2,        2,        2,        1,        1,         0,        0       ))
	SLRad        = default( SLRad,        Select( pNum,  3,         1,        1,        1,        1,        1,        1,        1,        1,         0,        0       ))
	Sbb          = default( Sbb,          Select( pNum,  3,         1,        1,        0,        0,        0,        0,        0,        0,         0,        0       ))
	NoiseBypass  = default( NoiseBypass,  Select( pNum,  2,         2,        0,        0,        0,        0,        0,        0,        0,         0,        0       ))
	NoiseDeint   = default( NoiseDeint,   Select( pNum, "Generate","Bob",     "",       "",       "",       "",       "",       "",       "",        "",       ""      ))
	BT           = default( BT,           Select( pNum,  5,         3,        3,        3,        3,        2,        1,        1,        1,         1,        1       ))
	SrchClipPP   = default( SrchClipPP,   Select( pNum,  2,         2,        2,        2,        2,        2,        1,        0,        0,         0,        0       ))
	SubPel       = default( SubPel,       Select( pNum,  4,         2,        2,        2,        1,        1,        1,        1,        1,         1,        1       ))
	Blocksize    = default( Blocksize,    Select( pNum,  bs,        bs,       bs,       bs,       bs,       bs,       bs2,      bs2,      bs2,       bs2,      bs2     ))
	Overlap      = default( Overlap,      Select( pNum,  bs/2,      bs/2,     bs/2,     bs/2,     bs/2,     bs/2,     bs2/2,    bs2/ovf,  bs2/ovf,   bs2/ovf,  bs2/ovf ))
	Search       = default( Search,       Select( pNum,  5,         4,        4,        4,        4,        4,        4,        4,        4,         4,        0       ))
	SearchParam  = default( SearchParam,  Select( pNum,  2,         2,        2,        2,        2,        2,        2,        1,        1,         1,        1       ))
	PelSearch    = default( PelSearch,    Select( pNum,  2,         2,        2,        2,        1,        1,        1,        1,        1,         1,        1       ))
	Precise      = default( Precise,      Select( pNum,  true,      true,     false,    false,    false,    false,    false,    false,    false,     false,    false   ))

	# Sharpness defaults. Sharpness parameter is normalized so default is always 1.0 and gives roughly same sharpness for all settings. Internally tweaked
	# based on temporal smooth settings, sharpening mode and sharpness limiting mode to give actual value used in algorithm below
	SMode      = (defined(Sharpness) && Sharpness == 0.0) ? 0 : SMode
	SLMode     = (SMode == 0 || SLRad <= 0) ? 0 : SLMode
	Sbb        = (SMode == 0) ? 0 : Sbb
	spatialSL  = (SLMode == 1 || SLMode == 3)
	temporalSL = (SLMode == 2 || SLMode == 4)
	Sharpness  = default( Sharpness, 1.0 )
	sharpMul   = (temporalSL) ? 2 : (spatialSL) ? 1.5 : 1  # Temporal sharpness limiting is most effective, so needs strongest sharpness
	sharpAdj   = Sharpness * (sharpMul * (0.2 + tr1*0.15 + tr2*0.25) + ((SMode == 1) ? 0.1 : 0)) # Normalize sharpness setting - see comment above
	SOvs       = default( SOvs, 0 )
	SVThin     = default( SVThin, 0.0 )

	# MVTools settings
	SubPelInterp = default( SubPelInterp, 2     )
	TrueMotion   = default( TrueMotion,   false )
	Lambda       = default( Lambda,       ((TrueMotion) ? 1000 : 100 ) * (BlockSize*BlockSize)/(8*8) ) 
	LSAD         = default( LSAD,          (TrueMotion) ? 1200 : 400 )
	PNew         = default( PNew,          (TrueMotion) ? 50   : 25  )
	PLevel       = default( PLevel,        (TrueMotion) ? 1    : 0   )
	GlobalMotion = default( GlobalMotion, true )
	DCT          = default( DCT,          0    )
	_thSAD1 = 10 * 8*8  # SAD threshold for motion block matching: for intial temporal smooth (over 8x8 block as required by MVTools)
	_thSAD2 =  4 * 8*8  # SAD threshold for motion block matching: stabilising temporal smooth (--"--)
	_thSCD1 = 180       # Scene change detection parameter
	_thSCD2 = 98        # --"--

	# Noise bypass settings
	NoiseRemove  = default( NoiseRemove,  Select( NoiseBypass, 0.0, 1.0, 1.0 ))
	NoiseRestore = default( NoiseRestore, Select( NoiseBypass, 0.0, 1.0, 0.4 )) # Mode 2 has strong sharpening effect - so reduce NoiseRestore
	Sigma        = default( Sigma, 2.0 )
	NoiseBypass  = (NoiseRemove <= 0.0) ? 0 : NoiseBypass
	NoiseRemove  = (NoiseBypass == 0) ? 0.0 : NoiseRemove
	NoiseRestore = (NoiseBypass == 0) ? 0.0 : NoiseRestore
	NoiseDeint   = (NoiseBypass == 0 || NoiseRestore <= 0.0) ? ""  : NoiseDeint

	# Other settings
	EdiQual      = default( EdiQual,      1     )  # Quality setting for NNEDI2
	EdiMaxD      = default( EdiMaxD,      8     )  # Search radius for EEDI2
	InputType    = default( InputType,    0     )
	Border       = default( Border,       false )
	ShowSettings = default( ShowSettings, false )
	maxT         = (tr1 > tr2) ? tr1 : tr2                           # Maximum temporal radius needed
	maxT         = (temporalSL && SLRad > 1 && maxT < 3) ? 3 : maxT  # --"--
	rgBlur       = (Precise) ? 11 : 12                               # Version of RemoveGrain blur to use
	epsilon      = 0.0001                                            # Error margin to avoid rounding problems

	
	#---------------------------------------
	# Pre-Processing
	
	w = Input.Width()
	h = Input.Height() 
	nullClip  = BlankClip( Input, Width=16, Height=16 ) 

	# Extract noise/grain from source, keep removed noise for restoring later. If NoiseBypass == 2, noise is extracted and stored, but not removed from 
	# the source - allowing the TGMC process to do the denoising (avoids effectively denoising twice)
	denoise = (NoiseRemove > 0.0)  ? Input.FFT3DFilter( sigma=Sigma, beta=1.0/NoiseRemove, bt=BT, interlaced=true, bw=48, bh=48, ow=16, oh=16 ) : Input
	noise   = (NoiseRestore > 0.0) ? mt_makediff( Input, denoise, U=3,V=3 ).mt_lut( "x 128 - " + string(NoiseRestore) + " * 128 +" ) : nullClip
	bypass  = (NoiseBypass == 1)   ? denoise : Input
	
	# Pad vertically during processing (to prevent artefacts at top & bottom edges)
	clip = (Border) ? bypass.PointResize( w,h+8, 0,-4,0,h+8+epsilon ) : bypass
	h = (Border) ? h+8 : h

										 
	#---------------------------------------
	# Motion Analysis

	# Bob the input as a starting point for motion search clip - simple upscale of current field, will not be very sharp (which helps stabilize motion search)
	bobbed = (InputType == 0) ? clip.Bob( 0,0.5 ) : \
	         (InputType == 1) ? clip : \
	                            clip.Blur( 0,1 )

	# Support already-deinterlaced progressive content - drop half the fields and reweave to get 1/2fps interlaced stream appropriate for TGMC processing
	ediInput = (InputType == 2) ? clip.SeparateFields().SelectEvery(4,0,3).Weave() : \
	           (InputType == 3) ? clip.ComplementParity().SeparateFields().SelectEvery(4,0,3).Weave() : \
			                      clip
								
	# Create interpolated image as starting point for output - typically will be sharper than the bob (except the hi-speed modes)
	edi = defined(EdiExt)         ? EdiExt.pointresize( w,h, 0,(EdiExt.Height()-h)/2, -0,h+epsilon ) : \
	      (InputType == 1)        ? ediInput : \
	      (EdiMode == "NNEDI2")   ? ediInput.NNEDI2( field=-2, nsize=NNSize, qual=EdiQual ) : \
	      (EdiMode == "NNEDI")    ? ediInput.NNEDI( field=-2 ) : \
	      (EdiMode == "EEDI2")    ? ediInput.SeparateFields().EEDI2( field=-2, maxd=EdiMaxD )  : \
	      (EdiMode == "Yadif")    ? ediInput.Yadif( mode=1 ) : \
	      (EdiMode == "TDIYadif") ? mt_average( ediInput.Yadif( mode=1 ), ediInput.TDeInt( mode=1 ) ) : \
	                                bobbed

	# Temporally gaussian blur the bobbed clip for better motion search. Although the bobbed clip is somewhat blurred, it will shimmer due to
	# the alternating fields, which makes motion analysis erratic. Blurring over a few frames makes for more stable motion vectors. The gaussian
	# blur means frames near the current one will be more prominent in the blur - making for more accuracy in the motion vectors
	ts1 = (tr0 > 0) ? bobbed.TemporalSoften( 1, 255,255, 28, 2 ) : nullClip
	ts2 = (tr0 > 1) ? bobbed.TemporalSoften( 2, 255,255, 28, 2 ) : nullClip
	tempGauss = (tr0 == 0) ? bobbed : \
	            (tr0 == 1) ? ts1.Merge( bobbed, 0.25 ) : \
	                         ts1.Merge( ts2, 0.357 ).Merge( bobbed, 0.125 )

	# Remove areas of difference between temporal blurred motion search clip and bob that are not due to bob-shimmer - improves motion search
	repair0 = (rep0 == 0) ? tempGauss : tempGauss.RemoveNonBobDiff( bobbed, rep0 )

	# Spatially gaussian blur (and tweak) motion search clip for more stable motion vectors - removing noise makes features easier to track
	spatialBlur = (SrchClipPP == 0) ? repair0 : repair0.RemoveGrain(rgBlur).GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=2 ).Merge( repair0, 0.1 )
	tweaked = (SrchClipPP == 2) ? mt_lutxy( repair0, bobbed, "x 3 + y < x 3 + x 3 - y > x 3 - y ? ?", U=3,V=3 ) : nullClip
	srchclip = (SrchClipPP < 2) ? spatialBlur : spatialBlur.mt_lutxy( tweaked, "x 7 + y < x 2 + x 7 - y > x 2 - x 51 * y 49 * + 100 / ? ?", U=3,V=3 )

	#-- Infix notation for odd tweak used above when SrchClipPP == 2 (taken from original TGMC - exact rationale unknown)
	#-- ((x+3)<y)?(x+3):(((x-3)>y)?(x-3):y)                   # Tweak = orig search clip nudged towards bob
	#-- ((x+7)<y)?(x+2):(((x-7)>y)?(x-2):((x*51)+(y*49))/100) # Nudge distant spatial blur values towards Tweak, roughly average nearer values (?)

	# Calculate forward and backward motion vectors from motion search clip
	srchSuper = (maxT > 0) ? srchClip.MSuper( pel=SubPel, sharp=SubPelInterp ) : nullClip
	bVec3 = (maxT > 2) ? srchSuper.MAnalyse( isb=true,  delta=3, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, pelsearch=PelSearch, \
	                                         truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, global=GlobalMotion, DCT=DCT ) : nullClip
	bVec2 = (maxT > 1) ? srchSuper.MAnalyse( isb=true,  delta=2, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, pelsearch=PelSearch, \
	                                         truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, global=GlobalMotion, DCT=DCT ) : nullClip
	bVec1 = (maxT > 0) ? srchSuper.MAnalyse( isb=true,  delta=1, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, pelsearch=PelSearch, \
	                                         truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, global=GlobalMotion, DCT=DCT ) : nullClip
	fVec1 = (maxT > 0) ? srchSuper.MAnalyse( isb=false, delta=1, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, pelsearch=PelSearch, \
	                                         truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, global=GlobalMotion, DCT=DCT ) : nullClip
	fVec2 = (maxT > 1) ? srchSuper.MAnalyse( isb=false, delta=2, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, pelsearch=PelSearch, \
	                                         truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, global=GlobalMotion, DCT=DCT ) : nullClip
	fVec3 = (maxT > 2) ? srchSuper.MAnalyse( isb=false, delta=3, blksize=BlockSize, overlap=Overlap, search=Search, searchparam=SearchParam, pelsearch=PelSearch, \
	                                         truemotion=TrueMotion, lambda=Lambda, lsad=LSAD, pnew=PNew, plevel=PLevel, global=GlobalMotion, DCT=DCT ) : nullClip

											 
	#---------------------------------------
	# Create Output

	# Create basic TGMC ouput: use motion vectors to blur interpolated image with motion-compensated previous and next frames. The interpolated image (edi)
	# may be a sharp high-quality image (e.g. using NNEDI2), but it will shimmer between frames due to the interpolator working on alternating fields.
	# Blurring with neighboring frames would remove the shimmer, but also create motion blur. By using motion compensated neighbors, features from the
	# current frame are blended with the same feature in the neighboring frames regardless of movement. This gives a much sharper result, whilst still
	# blurring out the shimmer. A gaussian blur ensures the current frame is most prominent in the result.
	ediSuper =  (tr1 > 0) ? edi.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1 ) : nullClip
	mdegrain1 = (tr1 > 0) ? edi.MDegrain1( ediSuper, bVec1, fVec1, thSAD=_thSAD1, thSCD1=_thSCD1, thSCD2=_thSCD2 ) : nullClip
	mdegrain2 = (tr1 > 1) ? edi.MDegrain1( ediSuper, bVec2, fVec2, thSAD=_thSAD1, thSCD1=_thSCD1, thSCD2=_thSCD2 ) : nullClip
	tgmc = (tr1 == 0) ? edi : \
	       (tr1 == 1) ? mdegrain1.Merge( edi, 0.25 ) : \
	                    mdegrain1.Merge( mdegrain2, 0.2 ).Merge( edi, 0.0625 )

	# For temporal sharpness limiting later: need the max/min value for each pixel over neighboring motion-compensated frames
	bComp1 = (temporalSL)              ? edi.MCompensate( ediSuper, bVec1, thSCD1=_thSCD1, thSCD2=_thSCD2 )         : nullClip
	fComp1 = (temporalSL)              ? edi.MCompensate( ediSuper, fVec1, thSCD1=_thSCD1, thSCD2=_thSCD2 )         : nullClip
	tMax =   (temporalSL)              ? edi.mt_logic( fComp1, "max", U=3,V=3 ).mt_logic( bComp1, "max", U=3,V=3 )  : nullClip
	tMin =   (temporalSL)              ? edi.mt_logic( fComp1, "min", U=3,V=3 ).mt_logic( bComp1, "min", U=3,V=3 )  : nullClip
	bComp3 = (SLRad > 1 && temporalSL) ? edi.MCompensate( ediSuper, bVec3, thSCD1=_thSCD1, thSCD2=_thSCD2 )         : nullClip
	fComp3 = (SLRad > 1 && temporalSL) ? edi.MCompensate( ediSuper, fVec3, thSCD1=_thSCD1, thSCD2=_thSCD2 )         : nullClip
	tMax =   (SLRad > 1 && temporalSL) ? tMax.mt_logic( fComp3, "max", U=3,V=3 ).mt_logic( bComp3, "max", U=3,V=3 ) : tMax
	tMin =   (SLRad > 1 && temporalSL) ? tMin.mt_logic( fComp3, "min", U=3,V=3 ).mt_logic( bComp3, "min", U=3,V=3 ) : tMin

	# Remove areas of difference between tgmc image and basic interpolated image that are not bob-shimmer fixes: repairs motion blur caused by temporal blur
	repair1 = (rep1 == 0) ? tgmc : tgmc.RemoveNonBobDiff( edi, rep1 )

	# Resharpen to counteract temporal blur (SMode >= 1: subtract difference from 3x3 blur, SMode == 2: replace with average of vertical min/max first)
	# If using Precise mode then reduce tiny overshoot in vertical min/max average
	vresharp = (SMode == 2) ? mt_average( repair1.mt_expand( mode="vertical", U=3,V=3 ), repair1.mt_inpand( mode="vertical", U=3,V=3 ), U=3,V=3 ) : nullClip
	vresharp = (Precise && SMode == 2) ? vresharp.mt_lutxy( repair1, "x y < x 1 + x y > x 1 - x ? ?", U=3,V=3 ) : vresharp  # (x<y)?(x+1):((x>y)?(x-1):x)
	resharp = (SMode == 0) ? repair1 : \
	          (SMode == 1) ? repair1.mt_lutxy( repair1.RemoveGrain(rgBlur), "x x y - "+ string(sharpAdj) + " * +", U=3,V=3 ) : \
	                         repair1.mt_lutxy( vresharp.RemoveGrain(rgBlur), "x x y - "+ string(sharpAdj) + " * +", U=3,V=3 )

	# Slightly thin down 1-pixel high horizontal edges that have been widened into neigboring field lines by the interpolator
	# E.g. shown horizontally, a field is: 0x4x0, the interpolator creates the missing lines: 02420 -> the line is widened over three pixels
	# First find horizontal edges that don't lie within the range defined by their vertical neighbors, i.e. the affected 1-pixel high edges
	# Blur edges and find pixels that change pre->post blur: the neighbor pixels to the horizontal edges - shift their luma away from the line luma
	SVThinSc = SVThin * 6.0 # 4 surely better for RemoveGrain(11)??
	vertMedD  = (SVthin == 0.0) ? nullClip : mt_lutxy( repair1, repair1.VerticalCleaner(mode=1), "y x - " + string(SVThinSc) + " * 128 +", U=1,V=1 ).Blur( 1,0 )
	neighborD = (SVthin == 0.0) ? nullClip : mt_lutxy( vertMedD, vertMedD.RemoveGrain( 11,-1 ), "y 128 - abs x 128 - abs > y 128 ?" )
	thin      = (SVthin == 0.0) ? resharp  : resharp.mt_adddiff( neighborD, U=2,V=2 )

	# Back blend the blurred difference between sharpened & unsharpened clip, before sharpness limiting (Sbb == 1,2). A small fidelity improvement
	backBlend1 = (Sbb == 1 || Sbb == 2) \
		? thin.mt_makediff( mt_makediff( thin, repair1, U=1,V=1 ).RemoveGrain( rgBlur, -1 ).GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=5 ), U=2,V=2 ) \
		: thin
		
	# Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original - before 2nd temporal smooth (SLMode == 1,2)
	sharpLimit1 = (SLMode == 1) ? ((SLrad < 2) ? backBlend1.Repair( edi, 1 ) : backBlend1.Repair( backBlend1.Repair( edi, 12 ), 1 )) : \
	              (SLMode == 2) ? backBlend1.mt_clamp( tMax,tMin, Sovs,Sovs, U=3,V=3 ) :\
				                  backBlend1
    
	# Back blend the blurred difference between sharpened & unsharpened clip, after sharpness limiting (Sbb == 3,4). A small fidelity improvement
	backBlend2 = (Sbb == 3 || Sbb == 4) \
		? sharpLimit1.mt_makediff( mt_makediff( sharpLimit1, repair1, U=1,V=1 ).GaussResize( w,h, 0,0, w+epsilon,h+epsilon, p=5 ), U=2,V=2 ) \
		: sharpLimit1

	# Second lighter temporal blur (linear, not Gaussian) for final denoising / stabilization
	stableSuper = (tr2 > 0) ? backBlend2.MSuper( pel=SubPel, sharp=SubPelInterp, levels=1 ) : nullClip
	stable  = (tr2 == 0) ? backBlend2 : \
	          (tr2 == 1) ? backBlend2.MDegrain1( stableSuper, bVec1, fVec1,                             thSAD=_thSAD2, thSCD1=_thSCD1, thSCD2=_thSCD2 ) : \
	          (tr2 == 2) ? backBlend2.MDegrain2( stableSuper, bVec1, fVec1, bVec2, fVec2,               thSAD=_thSAD2, thSCD1=_thSCD1, thSCD2=_thSCD2 ) : \
 	                       backBlend2.MDegrain3( stableSuper, bVec1, fVec1, bVec2, fVec2, bVec3, fVec3, thSAD=_thSAD2, thSCD1=_thSCD1, thSCD2=_thSCD2 )

	# Remove areas of difference between final output & basic interpolated image that are not bob-shimmer fixes: repairs motion blur caused by temporal smooth
	repair2 = (rep2 == 0) ? stable : stable.RemoveNonBobDiff( edi, rep2 )

	# Limit over-sharpening by clamping to neighboring (spatial or temporal) min/max values in original - after 2nd temporal smooth (SLMode == 1,2)
	sharpLimit2 = (SLMode == 3) ? ((SLrad < 2) ? repair2.Repair( edi, 1 ) : repair2.Repair( repair2.Repair( edi, 12 ), 1 )) : \
	              (SLMode == 4) ? repair2.mt_clamp( tMax,tMin, Sovs,Sovs, U=3,V=3 ) :\
				                  repair2

											 
	#---------------------------------------
	# Post-Processing

	# Crop off temporary vertical padding
	cropped = (Border) ? sharpLimit2.Crop( 0, 4, -0, -4 ) : sharpLimit2
	h = (Border) ? h-8 : h

	# 'Deinterlace' the noise extracted at beginning of script. Noise was extracted from interlaced source but will be added back to progressive, so create
	# the missing lines of noise. Methods include standard "Bob" and "DoubleWeave", "Copy" to duplicate each line, and the slowest method "Generate" that
	# creates new noise centered on a weighted local average, using the difference between local min & max as an estimate of local variance
	origNoise = (NoiseDeint == "Generate") ? noise.SeparateFields() : nullClip
	noiseMax =  (NoiseDeint == "Generate") ? origNoise.mt_expand( mode="square", U=3,V=3 ).mt_expand( mode="horizontal", U=3,V=3 ) : nullClip
	noiseMin =  (NoiseDeint == "Generate") ? origNoise.mt_inpand( mode="square", U=3,V=3 ).mt_inpand( mode="horizontal", U=3,V=3 ) : nullClip
	random =    (NoiseDeint == "Generate") ? BlankClip( origNoise, color_yuv=$808080 ).AddGrain( var=256 ) : nullClip
	varRandom = (NoiseDeint == "Generate") ? mt_makediff( noiseMax, noiseMin, U=3,V=3 ).mt_lutxy( random, "x 128 - y 128 - * 128 / 128 +", U=3,V=3 ) : nullClip
	newNoise =  (NoiseDeint == "Generate") ? origNoise.RemoveGrain(12).mt_adddiff( varRandom, U=3,V=3 ) : nullClip
	deintNoise = (NoiseBypass == 0)         ? nullClip : \
	             (InputType > 0)            ? noise : \
	             (NoiseDeint == "Bob")      ? noise.Bob() : \
	             (NoiseDeint == "Copy")     ? noise.SeparateFields.BilinearResize( w,h ) : \
	             (NoiseDeint == "Generate") ? Interleave( origNoise, newNoise ).Weave() : \
	                                          noise.DoubleWeave()
	addNoise = (NoiseRestore > 0.0) ? cropped.mt_adddiff( deintNoise, U=3,V=3 ) : cropped

	# Show settings and output
	Output = (!ShowSettings) ? addNoise : \
	                           addNoise.Subtitle( "tr0=" + string(tr0) + " tr1=" + string(tr1) + " tr2=" + string(tr2) + " rep0=" + string(rep0) + \
	                                              " rep1=" +  string(rep1) + " rep2=" + string(rep2) + """\nEdiMode="""" + EdiMode + """" NNSize=""" + \
	                                              string(NNSize) + " EdiQual=" + string(EdiQual) + " EdiMaxD=" + string(EdiMaxD) + "\nSharpness=" + \
	                                              string(Sharpness, "%.2f") + " SMode=" + string(SMode) + " SLMode=" + string(SLMode) + " SLRad=" + \
	                                              string(SLRad) + " SOvs=" +  string(SOvs) + " SVThin=" +  string(SVThin) + " Sbb=" + string(Sbb) + \
	                                              "\nSrchClipPP=" + string(SrchClipPP) + " SubPel=" + string(SubPel) + " SubPelInterp=" + \
	                                              string(SubPelInterp) + " BlockSize=" + string(BlockSize) + " Overlap=" + string(Overlap) + "\nSearch=" + \
	                                              string(Search) + " SearchParam=" + string(SearchParam) + " PelSearch=" + string(PelSearch) + \
	                                              " TrueMotion=" + string(TrueMotion) + "\nLambda=" + string(Lambda) + " LSAD=" + string(LSAD) + " PNew=" + \
	                                              string(PNew) + " PLevel=" + string(PLevel) +  + "\nGlobalMotion=" + string(GlobalMotion) +  + " DCT=" + \
	                                              string(DCT) + " NoiseBypass=" + string(NoiseBypass) + " NoiseRemove=" + string(NoiseRemove, "%.2f") + \
	                                              "\nNoiseRestore=" + string(NoiseRestore, "%.2f") + """ NoiseDeint="""" + NoiseDeint + """" Sigma=""" + \
	                                              string(Sigma, "%.2f") + " BT=" + string(BT, "%.2f") + "\nBorder=" + string(Border) + " Precise=" + \
	                                              string(Precise) + " SafeMode=" + string(SafeMode) + """\nPreset="""" + Preset + """ Tuning="""" + Tuning + \
	                                              """"""", lsp=10 )
	return Output
}


#---------------------------------------
# Helpers

# Taken from original TGMC - they are not actually equivalent to mt_XXflate, nor are they faster any more. However, they work well.
function TGMC_inflate(clip c,int"Y",int "U",int "V") {
mtY=default(Y, 3) mtU=default(U, 1) mtV=default(V, 1)
rgY=(mtY==3)?20:-1 rgU=(mtU==3)?20:-1 rgV=(mtV==3)?20:-1 
mt_logic(c,c.RemoveGrain(rgY,rgU,rgV),"max",Y=mtY,U=mtU,V=mtV) }

function TGMC_deflate(clip c,int"Y",int "U",int "V") {
mtY=default(Y, 3) mtU=default(U, 1) mtV=default(V, 1)
rgY=(mtY==3)?20:-1 rgU=(mtU==3)?20:-1 rgV=(mtV==3)?20:-1 
mt_logic(c,c.RemoveGrain(rgY,rgU,rgV),"min",Y=mtY,U=mtU,V=mtV) }

# Helper function: Compare processed clip with reference clip: only allow thin, horizontal areas of difference, i.e. bob shimmer
# Rough algorithm: Get difference, deflate vertically by a couple of pixels or so, then inflate again. Thin regions will be removed
#                  by this process. Restore remaining areas of difference back to as they were in reference clip.
function RemoveNonBobDiff( clip Input, clip Ref, int rep )
{
	# ed is the erosion distance - how much to deflate then reflate to remove thin areas of interest: 0 = minimum to 5 = maximum
	# od is over-dilation level  - extra inflation to ensure areas to restore back are fully caught:  0 = none to 3 = one full pixel
	# If rep < 10, then ed = rep and od = 0, otherwise ed = 10s digit and od = 1s digit (nasty method, but left in for compatibility with original TGMC)
	rep = default( rep, 1 )
	ed = (rep < 10) ? rep : rep/10  
	od = (rep < 10) ? 0   : rep%10  

	diff = mt_makediff( Ref, Input, U=3,V=3 )

	# Areas of positive difference                                                          # ed = 0 1 2 3 4 5
	choke1 =                        diff.  mt_inpand( mode="vertical", U=3,V=3 )            #      x x x x x x    1 pixel   \
	choke1 = (ed > 2)             ? choke1.mt_inpand( mode="vertical", U=3,V=3 ) : choke1   #      . . . x x x    1 pixel    | Deflate to remove thin areas
	choke1 = (ed != 0 && ed != 3) ? choke1.mt_deflate( U=3,V=3 )               : choke1   #      . x x . x x    a bit more |
	choke1 = (ed == 2 || ed == 5) ? choke1.RemoveGrain(4)                        : choke1   #      . . x . . x    & more(?) / [median - may actually inflate?!]
	
	choke1 =                        choke1.mt_expand( mode="vertical", U=3,V=3 )            #      x x x x x x    1 pixel  \
	choke1 = (ed > 1)             ? choke1.mt_expand( mode="vertical", U=3,V=3 ) : choke1   #      . . x x x x    1 pixel   | Reflate again
	choke1 = (ed > 4)             ? choke1.mt_expand( mode="vertical", U=3,V=3 ) : choke1   #      . . . . . x    1 pixel  /
	
	# Over-dilation - extra reflation up to 1 pixel
	choke1 = (od == 0)            ? choke1 : \
	         (od == 1)            ? choke1.mt_inflate( U=3,V=3 ) : \                      
	         (od == 2)            ? choke1.mt_inflate( U=3,V=3 ).mt_inflate( U=3,V=3 ) : \
	                                choke1.mt_expand( U=3,V=3 )
	
	# Areas of negative difference (similar to above)
	choke2 =                        diff.  mt_expand( mode="vertical", U=3,V=3 )
	choke2 = (ed > 2)             ? choke2.mt_expand( mode="vertical", U=3,V=3 ) : choke2
	choke2 = (ed != 0 && ed != 3) ? choke2.mt_inflate( U=3,V=3 )               : choke2
	choke2 = (ed == 2 || ed == 5) ? choke2.RemoveGrain(4)                        : choke2
	choke2 =                        choke2.mt_inpand( mode="vertical", U=3,V=3 )
	choke2 = (ed > 1)             ? choke2.mt_inpand( mode="vertical", U=3,V=3 ) : choke2
	choke2 = (ed > 4)             ? choke2.mt_inpand( mode="vertical", U=3,V=3 ) : choke2
	choke2 = (od == 0)            ? choke2 : \
	         (od == 1)            ? choke2.mt_deflate( U=3,V=3 ) : \  
	         (od == 2)            ? choke2.mt_deflate( U=3,V=3 ).mt_deflate( U=3,V=3 ) : \  
	                                choke2.mt_inpand( U=3,V=3 )
	
	# Combine above areas to find those areas of difference to restore
	restore = diff.mt_lutxy( choke1, "x 129 < x y 128 < 128 y ? ?", U=3,V=3 ).mt_lutxy( choke2, "x 127 > x y 128 > 128 y ? ?", U=3,V=3 )
	
	return Input.mt_adddiff( restore, U=3,V=3 )
}
[/HIDE]

I've also attached an archive of previous versions in case you want to regress.

Did you give the MSU plugin a go?
Not yet, many things on the go atm... Will certainly get round to it though.
 

astrayred

Member
Mar 19, 2008
158
16
@Vitreous: Thanks for the reply!

My machine is a Phenom II X4 955 overclocked to 3.6Ghz (but very stable) with 4GB of DDR RAM. It's not a 12GB Core i7 monster, but I don't think it can be classified as being low memory :p

In any case, I did a quick comparison of a 5000 frame test script between v2.0 and v2.3. 2.0 achieved an average of 14 FPS. v2.3 10.2 FPS. v2.3t 11.2 FPS.

To provide a bit more information, I'm encoding directly to x264 instead of pre-rendering. Not sure if this is important, but obviously the x264 settings are the same for all 3 test scenarios...
 

Rollyco

Team Tomoe
Oct 4, 2007
3,562
34
What preset?
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
I was wondering if the defaults were changed, but a quick glance at the changelog didn't mention anything major.
Ah, my bad too then. Since v2.2 the default preset has changed to "Slower", rather than "Slow". I mention it in the comments but didn't add it to the changelog (updated now).
Reason: going to release it more widely - wanted to more closely match TempGaussMC_beta2 defaults. In general I would recommend always using a preset.
 

astrayred

Member
Mar 19, 2008
158
16
Ah, my bad too then. Since v2.2 the default preset has changed to "Slower", rather than "Slow". I mention it in the comments but didn't add it to the changelog (updated now).
Reason: going to release it more widely - wanted to more closely match TempGaussMC_beta2 defaults. In general I would recommend always using a preset.

Ah I see. That clears everything up! :)
 

no__One

Active Member
May 27, 2007
947
175
At the risk of jinxing it, after upgrading to SEt's MT Avisynth 2.6 I haven't experienced any mencoder.exe crashes. Woohoo! :grassdance:

If that continues, it'll be included in the upcoming meguIV 1.0.2.0.

With all theses improvements, can't wait to test and stress it! :perfectplan::study:

Thanks a lot for your awesome App, I can't imagine to rip a JI DVD without meguIV. :stress:
 

no__One

Active Member
May 27, 2007
947
175
Ah, my bad too then. Since v2.2 the default preset has changed to "Slower", rather than "Slow". I mention it in the comments but didn't add it to the changelog (updated now).
Reason: going to release it more widely - wanted to more closely match TempGaussMC_beta2 defaults. In general I would recommend always using a preset.

Thanks a lot to Vitreous too. I can't imagine all tests and time consumming to improve TGMC / QuickTGMC... :petrfied:
 

Vitreous

°
Former Staff
Sep 13, 2009
2,033
591
About setting threads to cores+1, I'm not sure how to programatically do that from within Avisynth.
I'll bet there's a trick to doing it - I'll have a tinker...

EDIT: Rewrite from my first attempt at this...

Undocumented behaviour, but seems to work. I think this code sets the number of threads = number processors+2. Threads=cores+1 gives me a sizeable speed boost on 4 cores, +2 gives me little more again, beyond that doesn't help much. However, I don't have anything with less than 4 cores, so I'm not sure if these observations hold true in that case...
Code:
maxThreads = 8  # Won't hit this limit unless >6 cores, but max=6 may better suit hex-core?
numProcessors = GetMTMode(true)
numThreads = numProcessors + 2
numThreads = (numThreads > maxThreads) ? maxThreads : numThreads
SetMTMode( 3, numThreads )

#
# Load source, process etc.
#

Subtitle(string(numThreads)) # Use this line to check number of threads is as expected

EDIT2: And if you want a simpler unchecked version:
Code:
SetMTMode( 3, GetMTMode(true) + 2 )