Log in

View Full Version : How to use QTGMC correctly now?


Jukus
15th November 2025, 23:08
Since QTGMC was taken from
https://github.com/HomeOfVapourSynthEvolution/havsfunc/blob/master/havsfunc/havsfunc.py#L1044
and it's suggested to use
https://github.com/Jaded-Encoding-Thaumaturgy/vs-jetpack/blob/main/vsdeinterlace/qtgmc.py
but I either have different errors or freezing
In short, write how to use QTGMC now

orchid
16th November 2025, 00:18
JET doesn't use doom9, you probably won't get an answer. Support is generally over the Discord server linked in the README.

Z2697
16th November 2025, 01:48
Dig it out from commit history, or tags.

_Al_
16th November 2025, 02:37
They do not need to use doom9 forum,
but they do not bother to put some basic help, usage, into their scripts. I absolutely do not get that.

orchid
16th November 2025, 02:50
They do not need to use doom9 forum,
but they do not bother to put some basic help, usage, into their scripts. I absolutely do not get that.

The script literally has a basic usage in the docstrings, along with having an entire docs website set up. I do not know what you mean.

_Al_
16th November 2025, 03:17
The script literally has a basic usage in the docstrings, along with having an entire docs website set up. I do not know what you mean.
This is why vapoursynth will never take avisynth, video guys are not coders.
I need to give email to someone to get a docs? Also because their scripts got "pythonized", meaning,
no more classic function:
new_clip = QTGMC(old_clip),
but:
new_clip = QTempGaussMC(clip).deinterlace()

It needs to be really explained, with all possible arguments, so a video guy will get a grip, what is going on. I know, there is "mapping", a https://gist.github.com/emotion3459/33bd2b2a2c21afc6497f65adaf7f0b02 from old things to new ones, but this is not enough for a video dude. Again, video guys are not coders.

orchid
16th November 2025, 03:25
This is why vapoursynth will never take avisynth, video guys are not coders.
I need to give email to someone to get a docs? Also because their scripts got "pythonized", meaning,
no more classic function:
new_clip = QTGMC(old_clip),
but:
new_clip = QTempGaussMC(clip).deinterlace()

It needs to be really explained, with all possible arguments, so a video guy will get a grip, what is going on. I know, there is "mapping", a https://gist.github.com/emotion3459/33bd2b2a2c21afc6497f65adaf7f0b02 from old things to new ones, but this is not enough for a video dude. Again, video guys are not coders.


I don't know what you are talking about. I never mentioned email. There is example usage in the script that you can simply copy and paste. Everything is documented.

_Al_
16th November 2025, 03:33
you said this:
having an entire docs website set up
so post a link here to those docs

orchid
16th November 2025, 03:42
you said this:

so post a link here to those docs

https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/
It's literally linked first thing in the github repo description.

_Al_
16th November 2025, 03:47
Are you serious? That help is on Jet discord server, if clicking that link, where e-mail is needed to provide.

orchid
16th November 2025, 03:50
Are you serious? That help is on Jet discord server, if clicking that link, where e-mail is needed to provide.

What are you talking about? The site contains all the documentation for every single filter. None of it is on Discord.

_Al_
16th November 2025, 03:58
orchid - I finally got it, noticing and clicking that "API" link,
Thank you for your patience :-)

https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/api/vsaa/deinterlacers/

qtgmc is here:
https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/api/vsdeinterlace/qtgmc/

Selur
16th November 2025, 07:14
As a side note, there is also the QTGMC I use in Hybrid: https://github.com/Selur/VapoursynthScriptsInHybrid/blob/master/qtgmc.py

LightArrowsEXE
16th November 2025, 08:50
Popping in to say that we do write extensive documentation. Our API docs are available here (https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/), and are updated regularly. Furthermore, our documentation is also easily available in any halfway-decent IDE. See for example:

https://i.imgur.com/Dnyxg88.png

I'm not quite sure why _Al_ is flaming us over their own learned helplessness. As orchid pointed out multiple times, documentation exists and is readily accessible. I'm also not entirely sure what the hang-up is concerning having to give emails. If you want to ask support on Doom9, you must also provide and verify an email, just like on Discord. Furthermore, if you want to avoid Discord, the Issues tracker (https://github.com/Jaded-Encoding-Thaumaturgy/vs-jetpack/issues) on our repositories is an additional place to ask for support if absolutely necessary (though we would prefer you stick to actual problems with our implementations rather than make it a support forum).

We are always open for suggestions on areas we can improve on, and you can leave an issue (https://github.com/Jaded-Encoding-Thaumaturgy/vs-jetpack/issues) or contact us on Discord if there's any problems. Very few of us actively browse Doom9, so those two are the best places to contact us.

As a side note, there is also the QTGMC I use in Hybrid: https://github.com/Selur/VapoursynthScriptsInHybrid/blob/master/qtgmc.py

This appears to me like it's just a copy-paste of an older havsfunc.QTGMC version, which has some known bugs (some dating back to original mods that added HBD support at minimum) and is less performant than our implementation at equivalent settings.

If possible, I would recommend updating them. If you're afraid of alienating older users, it's a good idea to write a wrapper yourself that takes all the old parameters and maps them to the correct method of our class. A list of all havsfunc.QTGMC <=> jetpack.QTempGaussMC mappings can be found here (https://gist.github.com/emotion3459/33bd2b2a2c21afc6497f65adaf7f0b02). If you're going this route though, I would also warn users that it's probably a good idea to learn the JET syntax instead and eventually phase out this wrapper in favour of the implementation it's wrapped around.

Since QTGMC was taken from
https://github.com/HomeOfVapourSynthEvolution/havsfunc/blob/master/havsfunc/havsfunc.py#L1044
and it's suggested to use
https://github.com/Jaded-Encoding-Thaumaturgy/vs-jetpack/blob/main/vsdeinterlace/qtgmc.py
but I either have different errors or freezing
In short, write how to use QTGMC now

The minimum call for QTGMC in the current stable version of jetpack (v0.8.5) is the following:


deint = (
QTempGaussMC(clip)
.prefilter()
.analyze()
.denoise()
.basic()
.source_match()
.lossless()
.sharpen()
.back_blend()
.sharpen_limit()
.final()
.motion_blur()
.deinterlace()
)


In later versions, this will be changed to:


deint = QTempGaussMC(clip).deinterlace()


You will still be able to access all the methods called in the current version even on newer versions, as the intention is to make it easier to modify values for specific steps of the QTGMC filterchain, as opposed to having a massive API that's difficult to maintain, update, and call as a user.

For further information, the docstrings of every method has information about what each parameter does:

https://i.imgur.com/0bNived.png

This is easily accessible in most IDEs by hovering over the method. If you hold shift and right-click, it will also take you to that specific code if you want to explore what it does internally:

https://i.imgur.com/uDbwiU6.png

If you can't access this directly from your script, we highly recommend you install a proper IDE. This will make writing scripts much easier. We typically recommend Visual Studio Code (https://code.visualstudio.com/download) for beginners.

Selur
16th November 2025, 09:38
As a side note, there is also the QTGMC I use in Hybrid: https://github.com/Selur/Vapoursynth...aster/qtgmc.py
This appears to me like it's just a copy-paste of an older havsfunc.QTGMC version, which has some known bugs (some dating back to original mods that added HBD support at minimum) and is less performant than our implementation at equivalent settings.
It was based on havsfunc.qtgmc, but got modified over the years.
s less performant than our implementation at equivalent settings.
What settings did you test that would be equivalent between the options? I'd like to reproduce this.

LightArrowsEXE
16th November 2025, 11:53
What settings did you test that would be equivalent between the options? I'd like to reproduce this.

Sorry for the delay. Here are tests with your specific mod versus the git latest version of JET.

The tl;dr:


JET has slightly higher fps at equivalent settings (despite additional complexity and many, many more checks).
The Rep0/1/2 stages have a bug in all HBD implementations (AVS included) of QTGMC besides JET. This results in a higher quality (sharper and more stable image) in our implementation compared to other iterations of QTGMC. See this comparison (https://slow.pics/c/VUwgaa2o) for example.
While JET looks more complex in this example, remember that it's a lot easier to modify individual values and thus control specific steps of the process, and you typically would not be expected to change these settings like this for regular usage anyway. Most users would simply run `.deinterlace()`.


Additionally worth nothing is that anything labelled "N/A" in this mapping gist (https://gist.github.com/emotion3459/33bd2b2a2c21afc6497f65adaf7f0b02) are parameters that havsfunc/selur mod do not expose, and are hardcoded values instead. These may further allow for speed/quality increases not available in other implementations.

Code ran:

Selur mod:


from qtgmc import QTGMC as selur_qtgmc

clip = core.bs.VideoSource(...)
clip = vstools.initialize_clip(clip.std.SetFieldBased(2))

# disable noise restores to remove external denoisers from the equation, set precise since its hardcoded in JET
deint1 = selur_qtgmc(clip, GrainRestore=0, NoiseRestore=0, Precise=True)


JET:


from vsdeinterlace import QTempGaussMC
from vsdenoise import MVToolsPreset, AnalyzeArgs, MotionMode, SearchMode
from vsaa import NNEDI3

clip = core.bs.VideoSource(...)
clip = vstools.initialize_clip(clip.std.SetFieldBased(2))

# mvtools preset to match havsfunc/selur (JET normally uses its own motion analysis settings)
analysis_preset = MVToolsPreset(
analyze_args=AnalyzeArgs(
search=SearchMode.HEXAGON,
searchparam=2,
truemotion=MotionMode.SAD,
lambda_=400,
pnew=25,
global_=True,
),
)

jet_qtgmc = QTempGaussMC(clip)
jet_qtgmc.analyze(preset=analysis_preset, refine=0) # set preset, disable refine (its disabled in selur/havsfunc)
jet_qtgmc.basic(bobber=NNEDI3(nsize=1, qual=1, nns=1, pscrn=2)) # reduce nnedi3 settings to match selur/havsfunc
jet_qtgmc.sharpen(strength=1.5) # raise sharpening strength to match selur/havsfunc

deint2 = jet_qtgmc.deinterlace()



Performance:

Selur mod: Output 5001 frames in 16.33 seconds (306.24 fps)


vspipe --filter-time -o 1 -p -e 5000 '.\New VapourSynth Python Script.vpy' --
Script evaluation done in 0.51 seconds
Output 5001 frames in 16.33 seconds (306.24 fps)


JET: Output 5001 frames in 16.01 seconds (312.45 fps)


vspipe --filter-time -o 2 -p -e 5000 '.\New VapourSynth Python Script.vpy' --
Script evaluation done in 0.50 seconds
Output 5001 frames in 16.01 seconds (312.45 fps)

Selur
16th November 2025, 12:17
Nice, thanks for the illustration. :)

_Al_
16th November 2025, 16:40
I'm not quite sure why _Al_ is flaming us over their own learned helplessness.
It is all good. Simply did not notice that API TAB on your website link that was posted many times, I don't know why.
Pretty stupid from me.

So thank you guys, Thanks for explanations too!

Jukus
16th November 2025, 17:50
How can I change this code to make it work with Jet?
QTGMC(clip, Preset='Very Slow', Sharpness=0.4, FPSDivisor=1, TFF=True)

LightArrowsEXE
17th November 2025, 09:06
How can I change this code to make it work with Jet?
QTGMC(clip, Preset='Very Slow', Sharpness=0.4, FPSDivisor=1, TFF=True)

Deciphering which exact values "Very Slow" maps to in havsfunc's code is rather annoying, so instead I'm going to give you a "close enough" approximation, if that's all right with you.


deint = (
QTempGaussMC(clip, tff=True) # Note that you should not have to set `tff` if your clip is already tagged appropriately, as it will automatically get it from the frameprops.
.prefilter()
.analyze()
.denoise()
.basic()
.source_match()
.lossless()
.sharpen(strength=0.4) # This is one of those params that get scaled very weirdly in havsfunc, so you will need to tweak this as necessary yourself.
.back_blend(mode=QTempGaussMC.BackBlendMode.PRELIMIT)
.sharpen_limit()
.final(tr=2)
.motion_blur()
.deinterlace()
)


If you're on git latest (or for future readers, version >0.8.5), the following simplification should achieve an identical result:


deint = (
QTempGaussMC(clip, tff=True) # Note that you should not have to set `tff` if your clip is already tagged appropriately, as it will automatically get it from the frameprops.
.sharpen(strength=0.4) # This is one of those params that get scaled very weirdly in havsfunc, so you will need to tweak this as necessary yourself.
.back_blend(mode=QTempGaussMC.BackBlendMode.PRELIMIT)
.sharpen_limit(radius=1)
.final(tr=2)
.deinterlace()
)


Note that fps_divisor (or FPSDivisor in havsfunc) is already set to 1 by default. If you want to change that, you need to add the following method call before `.deinterlace()`:


.motion_blur(fps_divisor=2)


Information like this can be easily found in our documentation (https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/api/vsdeinterlace/qtgmc/#vsdeinterlace.qtgmc.QTempGaussMC.motion_blur(fps_divisor)) if you want to experiment further.

Jukus
17th November 2025, 15:34
Failed to evaluate the script:
Python exception: Bob: Function does not take argument(s) named src_top, src_left, filter_param_a, filter_param_b

Traceback (most recent call last):
File "src/cython/vapoursynth.pyx", line 3378, in vapoursynth._vpy_evaluate
File "src/cython/vapoursynth.pyx", line 3379, in vapoursynth._vpy_evaluate
File "/tmp/1/script.vpy", line 49, in
#v = core.vivtc.VDecimate(v) #, cycle=5
File "/usr/lib/python3.13/site-packages/vsdeinterlace/qtgmc.py", line 1279, in deinterlace
self._apply_prefilter()
~~~~~~~~~~~~~~~~~~~~~^^
File "/usr/lib/python3.13/site-packages/vsdeinterlace/qtgmc.py", line 870, in _apply_prefilter
self.draft = Catrom().bob(self.clip, tff=self.tff) if self.input_type == self.InputType.INTERLACE else self.clip
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/vskernels/abstract/base.py", line 126, in _wrapped
returned = method(self, *args, **init_kwargs | kwargs)
File "/usr/lib/python3.13/site-packages/vskernels/abstract/base.py", line 1111, in bob
return self.bob_function(clip, **self.get_bob_args(clip, tff=clip_fieldbased.is_tff(), **kwargs))
~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/site-packages/vstools/vs_proxy/proxy.py", line 848, in __call__
return proxy_utils.get_vs_function(self)(*args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "src/cython/vapoursynth.pyx", line 3082, in vapoursynth.Function.__call__
vapoursynth.Error: Bob: Function does not take argument(s) named src_top, src_left, filter_param_a, filter_param_b

LightArrowsEXE
17th November 2025, 15:36
This error is likely caused due to an outdated resize2 install. Please update that plugin and try again.

Jukus
17th November 2025, 15:43
That's right, I managed to launch it
I would still like to see presets in the future
Thanks

Jukus
17th November 2025, 18:21
I found that it worked but the encoding speed dropped by 2 times, compared to QTGMC from havsfunc

LightArrowsEXE
18th November 2025, 10:08
I found that it worked but the encoding speed dropped by 2 times, compared to QTGMC from havsfunc

There were some improvements made on the git latest version that also greatly increases speed. You can try that (make sure to update the dependencies and vspreview too if you decide to go that route), or wait for the new version release for the speed increases.

Jukus
18th November 2025, 21:47
Still more than 2 times slower

Z2697
19th November 2025, 16:06
This thing is just embarrassing to even look at.

Jukus
19th November 2025, 16:57
This thing is just embarrassing to even look at.
What do you mean?

LightArrowsEXE
19th November 2025, 18:38
Still more than 2 times slower

Could you post the output of the following vspipe call?


vspipe --filter-time -p -e 5000 '.\your_script.vpy' --


As you can see from our own tests, there should not be such a drastic speed difference. This leads me to suspect you're falling back on CPU filtering in places where GPU filtering might be faster. If you don't have it installed, try installing SNEEDIF (https://github.com/Jaded-Encoding-Thaumaturgy/vapoursynth-SNEEDIF) and check if your speeds get better with the above command again. It might also be a good idea to ensure you have the latest versions of all our dependencies installed (https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/#dependencies), including the optional ones.

Jukus
19th November 2025, 19:10
cript evaluation done in 0.32 seconds
Output 5001 frames in 105.18 seconds (47.55 fps)
Filtername Filter mode Time (%) Time (s)
znedi3 parallel 1175.95 1236.83
Degrain2 parallel 49.10 51.64
Analyse parallel 39.01 41.03
Analyse parallel 38.93 40.95
Analyse parallel 38.43 40.42
Analyse parallel 38.14 40.12
Degrain1 parallel 28.89 30.39
Degrain1 parallel 28.75 30.24
Recalculate parallel 20.47 21.53
Recalculate parallel 19.94 20.97
Recalculate parallel 17.91 18.84
Recalculate parallel 17.83 18.75
Compensate parallel 12.29 12.93
Compensate parallel 12.17 12.80
Custom parallel 5.00 5.26
Custom parallel 4.64 4.88
Super parallel 4.43 4.66
VideoSource unordered 3.33 3.50
Super parallel 3.21 3.38
Super parallel 3.21 3.37
Super parallel 3.18 3.34
Super parallel 2.93 3.08
AverageFrames parallel 2.87 3.02
Expr parallel 2.63 2.77
AverageFrames parallel 1.99 2.10
Expr parallel 1.64 1.73
Bob parallel 1.64 1.72
Expr parallel 1.63 1.72
Expr parallel 1.58 1.66
Convolution parallel 1.56 1.64
Expr parallel 1.47 1.55
Expr parallel 1.43 1.51
Expr parallel 1.27 1.34
Inflate parallel 0.65 0.68
Deflate parallel 0.65 0.68
Deflate parallel 0.64 0.67
Inflate parallel 0.64 0.67
Merge parallel 0.43 0.45
MakeDiff parallel 0.40 0.42
MakeDiff parallel 0.27 0.28
Maximum parallel 0.23 0.24
Maximum parallel 0.22 0.23
Maximum parallel 0.22 0.23
Maximum parallel 0.22 0.23
Maximum parallel 0.22 0.23
MakeDiff parallel 0.21 0.22
SeparateFields parallel 0.21 0.22
Minimum parallel 0.21 0.22
Minimum parallel 0.20 0.21
Minimum parallel 0.20 0.21
Minimum parallel 0.19 0.20
MakeDiff parallel 0.19 0.20
Minimum parallel 0.18 0.19
Minimum parallel 0.17 0.18
Minimum parallel 0.17 0.18
Minimum parallel 0.17 0.18
Minimum parallel 0.17 0.18
Maximum parallel 0.17 0.18
Maximum parallel 0.17 0.17
Maximum parallel 0.17 0.17
Minimum parallel 0.16 0.17
Maximum parallel 0.16 0.17
Minimum parallel 0.16 0.17
Maximum parallel 0.16 0.17
PlaneStats parallel 0.16 0.17
Maximum parallel 0.16 0.16
PropExpr parallel 0.05 0.05
ClipToProp parallel 0.03 0.03
ClipToProp parallel 0.03 0.03
ClipToProp parallel 0.03 0.03
SetFrameProp parallel 0.02 0.02
ClipToProp parallel 0.02 0.02
ClipToProp parallel 0.02 0.02
PropToClip parallel 0.00 0.00
PropToClip parallel 0.00 0.00
PropToClip parallel 0.00 0.00
PropToClip parallel 0.00 0.00
PropToClip parallel 0.00 0.00
Splice parallel 0.00 0.00
Trim parallel 0.00 0.00
PropToClip parallel 0.00 0.00
Trim parallel 0.00 0.00
Trim parallel 0.00 0.00
Trim parallel 0.00 0.00
<Destroyed> <unknown> 0.00 0.00

Maybe your QTGMC requires Win+Nvidia+CUDA? My config: Arch Linux + Ryzen 5700G

LightArrowsEXE
19th November 2025, 19:16
It's clear from your filter graph that znedi3 is the cause of the slowdown. I believe the AUR should have opencl plugins for nnedi3, so please install those and try again.

Jukus
19th November 2025, 19:48
I installed https://aur.archlinux.org/packages/vapoursynth-plugin-nnedi3cl-git but nothing changed, I guess OpenCL just doesn't work. I have opencl-mesa installed, although there is also rocm-opencl-runtime to choose from.

Z2697
19th November 2025, 21:26
What do you mean?

vsjetpack

Selur
20th November 2025, 14:26
"vsjetpack" personally I like the idea of it, but I'll probably wait for another 1/2 year or so for it to hopefully settle a bit and to not get 'abandoned' like the previous vs-.. repositories over at https://github.com/orgs/Jaded-Encoding-Thaumaturgy/repositories. :)

Cu Selur

Z2697
20th November 2025, 17:42
to hopefully settle a bit

Yeah sure that will definitely happen.

virgin: havsfunc.QTGMC(clip,TFF=True)

chad:
deint = (
QTempGaussMC(clip, tff=True) # Note that you should not have to set `tff` if your clip is already tagged appropriately, as it will automatically get it from the frameprops.
.prefilter()
.analyze()
.denoise()
.basic()
.source_match()
.lossless()
.sharpen(strength=0.4) # This is one of those params that get scaled very weirdly in havsfunc, so you will need to tweak this as necessary yourself.
.back_blend(mode=QTempGaussMC.BackBlendMode.PRELIMIT)
.sharpen_limit()
.final(tr=2)
.motion_blur()
.deinterlace()
)

orchid
21st November 2025, 00:01
Yeah sure that will definitely happen.

virgin: havsfunc.QTGMC(clip,TFF=True)

chad:
deint = (
QTempGaussMC(clip, tff=True) # Note that you should not have to set `tff` if your clip is already tagged appropriately, as it will automatically get it from the frameprops.
.prefilter()
.analyze()
.denoise()
.basic()
.source_match()
.lossless()
.sharpen(strength=0.4) # This is one of those params that get scaled very weirdly in havsfunc, so you will need to tweak this as necessary yourself.
.back_blend(mode=QTempGaussMC.BackBlendMode.PRELIMIT)
.sharpen_limit()
.final(tr=2)
.motion_blur()
.deinterlace()
)

Not sure if you're being intentionally disingenuous or what.
It's already been stated that in git latest the simplest call is just
QTempGaussMC(clip).deinterlace()
Which is as simple as can be.

Your comment is both off-topic and very weird.

orchid
21st November 2025, 00:04
I installed https://aur.archlinux.org/packages/vapoursynth-plugin-nnedi3cl-git but nothing changed, I guess OpenCL just doesn't work. I have opencl-mesa installed, although there is also rocm-opencl-runtime to choose from.


analysis_preset = MVToolsPreset(
analyze_args=AnalyzeArgs(
search=SearchMode.HEXAGON,
searchparam=2,
truemotion=MotionMode.SAD,
lambda_=400,
pnew=25,
global_=True,
),
)

jet_qtgmc = QTempGaussMC(clip)
jet_qtgmc.analyze(preset=analysis_preset, refine=0)
jet_qtgmc.basic(bobber=NNEDI3(nsize=1, qual=1, nns=2, pscrn=None))
jet_qtgmc.sharpen(strength=0.8)
jet_qtgmc.final(tr=2)
deint2 = jet_qtgmc.deinterlace()


This should match the havsfunc call you posted earlier. Make sure you are on latest git if benchmarking. Speed is much faster than havsfunc for me.

Selur
22nd November 2025, 09:06
Speed is much faster than havsfunc for me.
Did you use nnedi3cl in both (havs vs jetpack), or is the speed boost mainly due to switching to nnedi3cl?

Also how to get vs-jetpack to use nnedi3cl ? I thought vs-jetpack switched to sneedif ? (or was that for aa only?)

quilosaq
23rd November 2025, 15:10
Hi! This is my first post.

...
deint = (
QTempGaussMC(clip, tff=True) # Note that you should not have to set `tff` if your clip is already tagged appropriately, as it will automatically get it from the frameprops.
.prefilter()
.analyze()
.denoise()
.basic()
.source_match()
.lossless()
.sharpen(strength=0.4) # This is one of those params that get scaled very weirdly in havsfunc, so you will need to tweak this as necessary yourself.
.back_blend(mode=QTempGaussMC.BackBlendMode.PRELIMIT)
.sharpen_limit()
.final(tr=2)
.motion_blur()
.deinterlace()
)
...I tried running your code and got an error. Perhaps there's a mistake in.sharpen(strength=0.4)and it should be.sharpen(strength=(1,0.4))?

Selur
23rd November 2025, 17:30
Strange, according to QTempGaussMC.sharpen (https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/api/vsdeinterlace/qtgmc/?h=q#vsdeinterlace.qtgmc.QTempGaussMC.sharpen)
sharpen(
*,
mode: SharpenMode | None = None,
strength: float | None = None,
clamp: float | tuple[float, float] = 1,
thin: float = 0
) -> Self
.sharpen(strength=0.4)
should work.
What does the error say?

quilosaq
24th November 2025, 00:25
Strange, according to QTempGaussMC.sharpen (https://jaded-encoding-thaumaturgy.github.io/vs-jetpack/api/vsdeinterlace/qtgmc/?h=q#vsdeinterlace.qtgmc.QTempGaussMC.sharpen)
sharpen(
*,
mode: SharpenMode | None = None,
strength: float | None = None,
clamp: float | tuple[float, float] = 1,
thin: float = 0
) -> Self...This function definition and all the API documentation correspond to the Git version. I am using v0.8.5. For that version, the definition, taken from the source code, is:
def sharpen(
self,
*,
mode: SharpMode | None = None,
strength: tuple[int, float] = (1, 1.0),
clamp: int | float | tuple[int | float, int | float] = 1,
thin: float = 0.0,
) -> Self:

Selur
24th November 2025, 16:42
Ah, I assumed you were using the git version. :)

quilosaq
25th November 2025, 18:35
Ah, I assumed you were using the git version. :)
I switched to the git version and .sharpen(strength=0.4) works correctly.
Thanks for your support.

Adub
25th November 2025, 19:28
@LightArrowsEXE

There were some improvements made on the git latest version that also greatly increases speed.

Out of curiosity, what's the source of the performance improvement over the original havsfunc implementation? Presumably it's using many of the same filters, with MVTools taking up a lot of the CPU time, so I'm surprised there's much of a speed difference? Or is it that various filters (like znedi3) have been upgraded to their hardware-accelerated counter parts?

LightArrowsEXE
25th November 2025, 19:45
@LightArrowsEXE
Out of curiosity, what's the source of the performance improvement over the original havsfunc implementation?

It's a combination of multiple factors. The biggest direct contributor will be a handful of faster plugins being used (zsmooth over rgvs, dfttest2 over dfttest, etc.), but a huge part of it is also more optimal code paths, trimming down a lot of unnecessary plugin calls, and merging expressions where reasonable.

Note however that no denoiser is being used in our example provided before, so that particular speed boost has no bearing on the comparison. Most of the speed improvements seen in that specific test are strictly Python-side optimisations and culling.

Adub
26th November 2025, 17:48
Got it! Thanks for the explanation, and nice work everyone on the improvements.

elcoyote
4th March 2026, 00:30
I was able to make this new QTGMC work on macOS Arm.

I've installed the "Essential" dependancies, but ZNEDI3 was missing and preventing to run a simple .deinterlace().

Shouldn't ZNEDI3 be listed in the essentials dependancies? Or is there something I don't understand?

Thanks!

orchid
5th March 2026, 15:42
The "Essentials" list is what plugins are required for basic functionality across vsjetpack. znedi3 is only required for a few, more specific functions making it fall under "Optional".

elcoyote
6th March 2026, 00:45
Oh, I see. ZNEDI3 seems to be the fallback to NNEDI3 when OpenCL is not found. On macOS, "self.opencl" seems to return false, so ZNEDI3 is de facto the default.

in deinterlacers.py:

def _deinterlacer_function(self) -> VSFunctionAllArgs:
return core.lazy.sneedif.NNEDI3 if self.opencl else core.lazy.znedi3.nnedi3

so... another macOS gotcha.