Skip to content

ivtc

IVTCycles

Bases: list[int], CustomEnum

cycle_05 class-attribute instance-attribute

cycle_05 = [
    [0, 1, 3, 4],
    [0, 1, 2, 4],
    [0, 1, 2, 3],
    [1, 2, 3, 4],
    [0, 2, 3, 4],
]

cycle_08 class-attribute instance-attribute

cycle_08 = [
    [0, 3, 4, 6],
    [0, 2, 5, 6],
    [0, 2, 4, 7],
    [0, 2, 4, 7],
    [1, 2, 4, 6],
]

cycle_10 class-attribute instance-attribute

cycle_10 = [
    [0, 3, 6, 8],
    [0, 2, 5, 8],
    [0, 2, 4, 7],
    [2, 4, 6, 9],
    [1, 4, 6, 8],
]

length property

length: int

pattern_length property

pattern_length: int

decimate

decimate(clip: VideoNode, pattern: int = 0) -> VideoNode
Source code
65
66
67
def decimate(self, clip: vs.VideoNode, pattern: int = 0) -> vs.VideoNode:
    assert 0 <= pattern < self.length
    return clip.std.SelectEvery(self.pattern_length, self.value[pattern])

VFMMode

Bases: CustomIntEnum

Enum representing different matching modes for VFM.

The mode determines the strategy used for matching fields and frames. Higher modes generally offer better matching in complex scenarios but may introduce more risk of jerkiness or duplicate frames.

THREE_WAY_MATCH class-attribute instance-attribute

THREE_WAY_MATCH = 4

3-way match (p/c/n).

THREE_WAY_MATCH_FOURTH_FIFTH class-attribute instance-attribute

THREE_WAY_MATCH_FOURTH_FIFTH = 5

3-way match + 4th/5th matches on combed (p/c/n + u/b). Highest risk of jerkiness but best at finding good matches.

TWO_WAY_MATCH class-attribute instance-attribute

TWO_WAY_MATCH = 0

2-way match (p/c). Safest option, but may output combed frames in cases of bad edits or blended fields.

TWO_WAY_MATCH_THIRD_COMBED class-attribute instance-attribute

TWO_WAY_MATCH_THIRD_COMBED = 1

2-way match + 3rd match on combed (p/c + n). Default mode.

TWO_WAY_MATCH_THIRD_FOURTH_FIFTH class-attribute instance-attribute

TWO_WAY_MATCH_THIRD_FOURTH_FIFTH = 3

2-way match + 3rd match on combed + 4th/5th matches if still combed (p/c + n + u/b).

TWO_WAY_MATCH_THIRD_SAME_ORDER class-attribute instance-attribute

TWO_WAY_MATCH_THIRD_SAME_ORDER = 2

2-way match + 3rd match (same order) on combed (p/c + u).

jivtc

jivtc(
    src: VideoNode,
    pattern: int,
    tff: bool = True,
    chroma_only: bool = True,
    postprocess: VSFunctionKwArgs = deblend,
    postdecimate: IVTCycles | None = cycle_05,
    ivtc_cycle: IVTCycles = cycle_10,
    final_ivtc_cycle: IVTCycles = cycle_08,
    **kwargs: Any
) -> VideoNode

This function should only be used when a normal ivtc or ivtc + bobber leaves chroma blend to a every fourth frame. You can disable chroma_only to use in luma as well, but it is not recommended.

Parameters:

  • src

    (VideoNode) –

    Source clip. Has to be 60i.

  • pattern

    (int) –

    First frame of any clean-combed-combed-clean-clean sequence.

  • tff

    (bool, default: True ) –

    Set top field first (True) or bottom field first (False).

  • chroma_only

    (bool, default: True ) –

    Decide whether luma too will be processed.

  • postprocess

    (VSFunctionKwArgs, default: deblend ) –

    Function to run after second decimation. Should be either a bobber or a deblender.

  • postdecimate

    (IVTCycles | None, default: cycle_05 ) –

    If the postprocess function doesn't decimate itself, put True.

Returns:

  • VideoNode

    Inverse Telecined clip.

Source code
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def jivtc(
    src: vs.VideoNode, pattern: int, tff: bool = True, chroma_only: bool = True,
    postprocess: VSFunctionKwArgs = deblend, postdecimate: IVTCycles | None = IVTCycles.cycle_05,
    ivtc_cycle: IVTCycles = IVTCycles.cycle_10, final_ivtc_cycle: IVTCycles = IVTCycles.cycle_08,
    **kwargs: Any
) -> vs.VideoNode:
    """
    This function should only be used when a normal ivtc or ivtc + bobber leaves chroma blend to a every fourth frame.
    You can disable chroma_only to use in luma as well, but it is not recommended.

    :param src:             Source clip. Has to be 60i.
    :param pattern:         First frame of any clean-combed-combed-clean-clean sequence.
    :param tff:             Set top field first (True) or bottom field first (False).
    :param chroma_only:     Decide whether luma too will be processed.
    :param postprocess:     Function to run after second decimation. Should be either a bobber or a deblender.
    :param postdecimate:    If the postprocess function doesn't decimate itself, put True.

    :return:                Inverse Telecined clip.
    """

    InvalidFramerateError.check(jivtc, src, (30000, 1001))

    ivtced = core.std.SeparateFields(src, tff=tff).std.DoubleWeave()
    ivtced = ivtc_cycle.decimate(ivtced, pattern)

    pprocess = postprocess(src if postdecimate else ivtced, **kwargs)

    if postdecimate:
        pprocess = postdecimate.decimate(pprocess, pattern)

    inter = core.std.Interleave([ivtced, pprocess])
    final = final_ivtc_cycle.decimate(inter, pattern)

    final = join(ivtced, final) if chroma_only else final

    return FieldBased.ensure_presence(final, FieldBased.PROGRESSIVE)

sivtc

sivtc(
    clip: VideoNode,
    pattern: int = 0,
    tff: bool | FieldBasedT = True,
    ivtc_cycle: IVTCycles = cycle_10,
) -> VideoNode

Simplest form of a fieldmatching function.

This is essentially a stripped-down JIVTC offering JUST the basic fieldmatching and decimation part. As such, you may need to combine multiple instances if patterns change throughout the clip.

Parameters:

  • clip

    (VideoNode) –

    Clip to process.

  • pattern

    (int, default: 0 ) –

    First frame of any clean-combed-combed-clean-clean sequence.

  • tff

    (bool | FieldBasedT, default: True ) –

    Top-Field-First.

Returns:

  • VideoNode

    IVTC'd clip.

Source code
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
def sivtc(
    clip: vs.VideoNode, pattern: int = 0, tff: bool | FieldBasedT = True, ivtc_cycle: IVTCycles = IVTCycles.cycle_10
) -> vs.VideoNode:
    """
    Simplest form of a fieldmatching function.

    This is essentially a stripped-down JIVTC offering JUST the basic fieldmatching and decimation part.
    As such, you may need to combine multiple instances if patterns change throughout the clip.

    :param clip:        Clip to process.
    :param pattern:     First frame of any clean-combed-combed-clean-clean sequence.
    :param tff:         Top-Field-First.

    :return:            IVTC'd clip.
    """

    tff = FieldBased.from_param(tff).field

    ivtc = clip.std.SeparateFields(tff=tff).std.DoubleWeave()
    ivtc = ivtc_cycle.decimate(ivtc, pattern)

    return FieldBased.PROGRESSIVE.apply(ivtc)

vdecimate

vdecimate(clip: VideoNode, weight: float = 0.0, **kwargs: Any) -> VideoNode

Perform frame decimation using VDecimate.

This function uses VIVTC's VDecimate plugin to remove duplicate frames from telecined content. It's recommended to use the vfm function before running this.

Parameters:

  • clip

    (VideoNode) –

    Input clip to decimate.

  • weight

    (float, default: 0.0 ) –

    Weight for frame blending. If > 0, blends duplicate frames before dropping one. Default: 0.0 (frames are dropped, not blended).

  • kwargs

    (Any, default: {} ) –

    Additional keyword arguments to pass to VDecimate. For a list of parameters, see the VIVTC documentation.

Returns:

  • VideoNode

    Decimated clip with duplicate frames removed or blended.

Source code
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
def vdecimate(clip: vs.VideoNode, weight: float = 0.0, **kwargs: Any) -> vs.VideoNode:
    """
    Perform frame decimation using VDecimate.

    This function uses VIVTC's VDecimate plugin to remove duplicate frames from telecined content.
    It's recommended to use the vfm function before running this.

    :param clip:            Input clip to decimate.
    :param weight:          Weight for frame blending. If > 0, blends duplicate frames before dropping one.
                            Default: 0.0 (frames are dropped, not blended).
    :param kwargs:          Additional keyword arguments to pass to VDecimate.
                            For a list of parameters, see the VIVTC documentation.

    :return:                Decimated clip with duplicate frames removed or blended.
    """

    func = FunctionUtil(clip, vdecimate, None, (vs.YUV, vs.GRAY), (8, 16))

    vdecimate_kwargs = dict[str, Any]()

    if block := kwargs.pop('block', None):
        if isinstance(block, int):
            vdecimate_kwargs |= dict(blockx=block, blocky=block)
        else:
            vdecimate_kwargs |= dict(blockx=block[0], blocky=block[1])

    if not kwargs.get('clip2', None) and func.work_clip.format is not clip.format:
        vdecimate_kwargs |= dict(clip2=clip)

    dryrun = kwargs.pop('dryrun', False)

    if dryrun or weight:
        stats = func.work_clip.vivtc.VDecimate(dryrun=True, **(vdecimate_kwargs | kwargs))

        if dryrun:
            return func.return_clip(stats)

        clip = kwargs.pop('clip2', clip)

        avg = clip.std.AverageFrames(weights=[0, 1 - weight, weight])
        splice = find_prop_rfs(clip, avg, "VDecimateDrop", "==", 1, stats)
        vdecimate_kwargs |= dict(clip2=splice)

    decimate = func.work_clip.vivtc.VDecimate(**(vdecimate_kwargs | kwargs))

    return func.return_clip(decimate)

vfm

vfm(
    clip: VideoNode,
    tff: FieldBasedT | None = None,
    mode: VFMMode = TWO_WAY_MATCH_THIRD_COMBED,
    postprocess: VideoNode | VSFunctionNoArgs | None = None,
    **kwargs: Any
) -> VideoNode

Perform field matching using VFM.

This function uses VIVTC's VFM plugin to detect and match pairs of fields in telecined content.

You can pass a post-processing clip or function that will act on leftover combed frames. If you pass a clip, it will replace combed frames with that clip. If you pass a function, it will run that function on your input clip and replace combed frames with it.

Example usage:

.. code-block:: python

# Run vsaa.Nnedi3 on combed frames
>>> vfm(clip, postprocess=lambda x: Nnedi3().interpolate(x, double_y=False))

Parameters:

  • clip

    (VideoNode) –

    Input clip to field matching telecine on.

  • tff

    (FieldBasedT | None, default: None ) –

    Field order of the input clip. If None, it will be automatically detected.

  • mode

    (VFMMode, default: TWO_WAY_MATCH_THIRD_COMBED ) –

    VFM matching mode. For more information, see :py:class:VFMMode. Default: VFMMode.TWO_WAY_MATCH_THIRD_COMBED.

  • postprocess

    (VideoNode | VSFunctionNoArgs | None, default: None ) –

    Optional function or clip to process combed frames. If a function is passed, it should take a clip as input and return a clip as output. If a clip is passed, it will be used as the postprocessed clip.

  • kwargs

    (Any, default: {} ) –

    Additional keyword arguments to pass to VFM. For a list of parameters, see the VIVTC documentation.

Returns:

  • VideoNode

    Field matched clip with progressive frames.

Source code
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
def vfm(
    clip: vs.VideoNode, tff: FieldBasedT | None = None,
    mode: VFMMode = VFMMode.TWO_WAY_MATCH_THIRD_COMBED,
    postprocess: vs.VideoNode | VSFunctionNoArgs | None = None,
    **kwargs: Any
) -> vs.VideoNode:
    """
    Perform field matching using VFM.

    This function uses VIVTC's VFM plugin to detect and match pairs of fields in telecined content.

    You can pass a post-processing clip or function that will act on leftover combed frames.
    If you pass a clip, it will replace combed frames with that clip. If you pass a function,
    it will run that function on your input clip and replace combed frames with it.

    Example usage:

    .. code-block:: python

        # Run vsaa.Nnedi3 on combed frames
        >>> vfm(clip, postprocess=lambda x: Nnedi3().interpolate(x, double_y=False))

    :param clip:            Input clip to field matching telecine on.
    :param tff:             Field order of the input clip.
                            If None, it will be automatically detected.
    :param mode:            VFM matching mode. For more information, see :py:class:`VFMMode`.
                            Default: VFMMode.TWO_WAY_MATCH_THIRD_COMBED.
    :param postprocess:     Optional function or clip to process combed frames.
                            If a function is passed, it should take a clip as input and return a clip as output.
                            If a clip is passed, it will be used as the postprocessed clip.
    :param kwargs:          Additional keyword arguments to pass to VFM.
                            For a list of parameters, see the VIVTC documentation.

    :return:                Field matched clip with progressive frames.
    """

    func = FunctionUtil(clip, vfm, None, (vs.YUV, vs.GRAY), 8)

    tff = FieldBased.from_param_or_video(tff, clip, False, func.func)

    vfm_kwargs = dict[str, Any](
        order=tff.is_tff, mode=mode
    )

    if block := kwargs.pop('block', None):
        if isinstance(block, int):
            vfm_kwargs |= dict(blockx=block, blocky=block)
        else:
            vfm_kwargs |= dict(blockx=block[0], blocky=block[1])

    if (y := kwargs.pop('y', None)) and not isinstance(y, int):
        vfm_kwargs |= dict(y0=y[0], y1=y[1])

    if not kwargs.get('clip2', None) and func.work_clip.format is not clip.format:
        vfm_kwargs |= dict(clip2=clip)

    fieldmatch = func.work_clip.vivtc.VFM(**(vfm_kwargs | kwargs))

    if postprocess:
        if callable(postprocess):
            postprocess = postprocess(kwargs.get('clip2', clip))

        fieldmatch = find_prop_rfs(fieldmatch, postprocess, "_Combed", "==", 1)

    return func.return_clip(fieldmatch)