Skip to content

shaders

FSRCNNXShaderT module-attribute

FSRCNNXShader dataclass

FSRCNNXShader(
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None,
    chroma_loc: int | None = None,
    matrix: int | None = None,
    trc: int | None = None,
    linearize: int | None = None,
    sigmoidize: int | None = None,
    sigmoid_center: float | None = None,
    sigmoid_slope: float | None = None,
    antiring: float | None = None,
    filter_shader: str | None = None,
    clamp: float | None = None,
    blur: float | None = None,
    taper: float | None = None,
    radius: float | None = None,
    param1: float | None = None,
    param2: float | None = None
)

Bases: PlaceboShaderBase

Defaults FSRCNNX shaders shipped with vsscale.

antiring class-attribute instance-attribute

antiring: float | None = field(default=None, kw_only=True)

blur class-attribute instance-attribute

blur: float | None = field(default=None, kw_only=True)

chroma_loc class-attribute instance-attribute

chroma_loc: int | None = field(default=None, kw_only=True)

clamp class-attribute instance-attribute

clamp: float | None = field(default=None, kw_only=True)

filter_shader class-attribute instance-attribute

filter_shader: str | None = field(default=None, kw_only=True)

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kwargs instance-attribute

kwargs = kwargs

linearize class-attribute instance-attribute

linearize: int | None = field(default=None, kw_only=True)

matrix class-attribute instance-attribute

matrix: int | None = field(default=None, kw_only=True)

param1 class-attribute instance-attribute

param1: float | None = field(default=None, kw_only=True)

param2 class-attribute instance-attribute

param2: float | None = field(default=None, kw_only=True)

radius class-attribute instance-attribute

radius: float | None = field(default=None, kw_only=True)

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shader_file class-attribute instance-attribute

shader_file = FSRCNNX_x56

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

sigmoid_center class-attribute instance-attribute

sigmoid_center: float | None = field(default=None, kw_only=True)

sigmoid_slope class-attribute instance-attribute

sigmoid_slope: float | None = field(default=None, kw_only=True)

sigmoidize class-attribute instance-attribute

sigmoidize: int | None = field(default=None, kw_only=True)

taper class-attribute instance-attribute

taper: float | None = field(default=None, kw_only=True)

trc class-attribute instance-attribute

trc: int | None = field(default=None, kw_only=True)

x16 dataclass

x16(
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None,
    chroma_loc: int | None = None,
    matrix: int | None = None,
    trc: int | None = None,
    linearize: int | None = None,
    sigmoidize: int | None = None,
    sigmoid_center: float | None = None,
    sigmoid_slope: float | None = None,
    antiring: float | None = None,
    filter_shader: str | None = None,
    clamp: float | None = None,
    blur: float | None = None,
    taper: float | None = None,
    radius: float | None = None,
    param1: float | None = None,
    param2: float | None = None
)

Bases: PlaceboShaderBase

antiring class-attribute instance-attribute

antiring: float | None = field(default=None, kw_only=True)

blur class-attribute instance-attribute

blur: float | None = field(default=None, kw_only=True)

chroma_loc class-attribute instance-attribute

chroma_loc: int | None = field(default=None, kw_only=True)

clamp class-attribute instance-attribute

clamp: float | None = field(default=None, kw_only=True)

filter_shader class-attribute instance-attribute

filter_shader: str | None = field(default=None, kw_only=True)

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kwargs instance-attribute

kwargs = kwargs

linearize class-attribute instance-attribute

linearize: int | None = field(default=None, kw_only=True)

matrix class-attribute instance-attribute

matrix: int | None = field(default=None, kw_only=True)

param1 class-attribute instance-attribute

param1: float | None = field(default=None, kw_only=True)

param2 class-attribute instance-attribute

param2: float | None = field(default=None, kw_only=True)

radius class-attribute instance-attribute

radius: float | None = field(default=None, kw_only=True)

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shader_file class-attribute instance-attribute

shader_file = FSRCNNX_x16

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

sigmoid_center class-attribute instance-attribute

sigmoid_center: float | None = field(default=None, kw_only=True)

sigmoid_slope class-attribute instance-attribute

sigmoid_slope: float | None = field(default=None, kw_only=True)

sigmoidize class-attribute instance-attribute

sigmoidize: int | None = field(default=None, kw_only=True)

taper class-attribute instance-attribute

taper: float | None = field(default=None, kw_only=True)

trc class-attribute instance-attribute

trc: int | None = field(default=None, kw_only=True)

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

kernel_radius

kernel_radius() -> int
Source code
195
196
197
@inject_self.cached.property
def kernel_radius(self) -> int:
    return _default_kernel_radius(__class__, self)  # type: ignore

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    output, _ = expect_bits(clip, 16)

    fmt = get_video_format(output)

    if fmt.num_planes == 1:
        if width > output.width or height > output.height:
            output = output.resize.Point(format=vs.YUV444P16)
        else:
            for div in (4, 2):
                if width % div == 0 and height % div == 0:
                    blank = core.std.BlankClip(output, output.width // div, output.height // div, vs.GRAY16)
                    break
            else:
                blank = output.std.BlankClip(vs.GRAY16)

            output = join(output, blank, blank)

    kwargs |= {
        'shader': str(
            self.shader_file()
            if isinstance(self.shader_file, ShaderFile) else
            ShaderFile.CUSTOM(self.shader_file)  # type: ignore
        ),
        'chroma_loc': self.chroma_loc, 'matrix': self.matrix,
        'trc': self.trc, 'linearize': self.linearize,
        'sigmoidize': self.sigmoidize, 'sigmoid_center': self.sigmoid_center, 'sigmoid_slope': self.sigmoid_slope,
        'antiring': self.antiring, 'filter': self.filter_shader, 'clamp': self.clamp,
        'blur': self.blur, 'taper': self.taper, 'radius': self.radius,
        'param1': self.param1, 'param2': self.param2,
    } | kwargs | {
        'width': output.width * ceil(width / output.width),
        'height': output.height * ceil(height / output.height)
    }

    if not kwargs['filter']:
        kwargs['filter'] = 'box' if fmt.num_planes == 1 else 'ewa_lanczos'

    if not Path(kwargs['shader']).exists():
        try:
            kwargs['shader'] = str(ShaderFile.CUSTOM(kwargs['shader']))  # type: ignore
        except FileWasNotFoundError:
            ...

    output = output.placebo.Shader(**kwargs)

    return self._finish_scale(output, clip, width, height, shift)

x56 dataclass

x56(
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None,
    chroma_loc: int | None = None,
    matrix: int | None = None,
    trc: int | None = None,
    linearize: int | None = None,
    sigmoidize: int | None = None,
    sigmoid_center: float | None = None,
    sigmoid_slope: float | None = None,
    antiring: float | None = None,
    filter_shader: str | None = None,
    clamp: float | None = None,
    blur: float | None = None,
    taper: float | None = None,
    radius: float | None = None,
    param1: float | None = None,
    param2: float | None = None
)

Bases: PlaceboShaderBase

antiring class-attribute instance-attribute

antiring: float | None = field(default=None, kw_only=True)

blur class-attribute instance-attribute

blur: float | None = field(default=None, kw_only=True)

chroma_loc class-attribute instance-attribute

chroma_loc: int | None = field(default=None, kw_only=True)

clamp class-attribute instance-attribute

clamp: float | None = field(default=None, kw_only=True)

filter_shader class-attribute instance-attribute

filter_shader: str | None = field(default=None, kw_only=True)

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kwargs instance-attribute

kwargs = kwargs

linearize class-attribute instance-attribute

linearize: int | None = field(default=None, kw_only=True)

matrix class-attribute instance-attribute

matrix: int | None = field(default=None, kw_only=True)

param1 class-attribute instance-attribute

param1: float | None = field(default=None, kw_only=True)

param2 class-attribute instance-attribute

param2: float | None = field(default=None, kw_only=True)

radius class-attribute instance-attribute

radius: float | None = field(default=None, kw_only=True)

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shader_file class-attribute instance-attribute

shader_file = FSRCNNX_x56

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

sigmoid_center class-attribute instance-attribute

sigmoid_center: float | None = field(default=None, kw_only=True)

sigmoid_slope class-attribute instance-attribute

sigmoid_slope: float | None = field(default=None, kw_only=True)

sigmoidize class-attribute instance-attribute

sigmoidize: int | None = field(default=None, kw_only=True)

taper class-attribute instance-attribute

taper: float | None = field(default=None, kw_only=True)

trc class-attribute instance-attribute

trc: int | None = field(default=None, kw_only=True)

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

kernel_radius

kernel_radius() -> int
Source code
195
196
197
@inject_self.cached.property
def kernel_radius(self) -> int:
    return _default_kernel_radius(__class__, self)  # type: ignore

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    output, _ = expect_bits(clip, 16)

    fmt = get_video_format(output)

    if fmt.num_planes == 1:
        if width > output.width or height > output.height:
            output = output.resize.Point(format=vs.YUV444P16)
        else:
            for div in (4, 2):
                if width % div == 0 and height % div == 0:
                    blank = core.std.BlankClip(output, output.width // div, output.height // div, vs.GRAY16)
                    break
            else:
                blank = output.std.BlankClip(vs.GRAY16)

            output = join(output, blank, blank)

    kwargs |= {
        'shader': str(
            self.shader_file()
            if isinstance(self.shader_file, ShaderFile) else
            ShaderFile.CUSTOM(self.shader_file)  # type: ignore
        ),
        'chroma_loc': self.chroma_loc, 'matrix': self.matrix,
        'trc': self.trc, 'linearize': self.linearize,
        'sigmoidize': self.sigmoidize, 'sigmoid_center': self.sigmoid_center, 'sigmoid_slope': self.sigmoid_slope,
        'antiring': self.antiring, 'filter': self.filter_shader, 'clamp': self.clamp,
        'blur': self.blur, 'taper': self.taper, 'radius': self.radius,
        'param1': self.param1, 'param2': self.param2,
    } | kwargs | {
        'width': output.width * ceil(width / output.width),
        'height': output.height * ceil(height / output.height)
    }

    if not kwargs['filter']:
        kwargs['filter'] = 'box' if fmt.num_planes == 1 else 'ewa_lanczos'

    if not Path(kwargs['shader']).exists():
        try:
            kwargs['shader'] = str(ShaderFile.CUSTOM(kwargs['shader']))  # type: ignore
        except FileWasNotFoundError:
            ...

    output = output.placebo.Shader(**kwargs)

    return self._finish_scale(output, clip, width, height, shift)

x8 dataclass

x8(
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None,
    chroma_loc: int | None = None,
    matrix: int | None = None,
    trc: int | None = None,
    linearize: int | None = None,
    sigmoidize: int | None = None,
    sigmoid_center: float | None = None,
    sigmoid_slope: float | None = None,
    antiring: float | None = None,
    filter_shader: str | None = None,
    clamp: float | None = None,
    blur: float | None = None,
    taper: float | None = None,
    radius: float | None = None,
    param1: float | None = None,
    param2: float | None = None
)

Bases: PlaceboShaderBase

antiring class-attribute instance-attribute

antiring: float | None = field(default=None, kw_only=True)

blur class-attribute instance-attribute

blur: float | None = field(default=None, kw_only=True)

chroma_loc class-attribute instance-attribute

chroma_loc: int | None = field(default=None, kw_only=True)

clamp class-attribute instance-attribute

clamp: float | None = field(default=None, kw_only=True)

filter_shader class-attribute instance-attribute

filter_shader: str | None = field(default=None, kw_only=True)

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kwargs instance-attribute

kwargs = kwargs

linearize class-attribute instance-attribute

linearize: int | None = field(default=None, kw_only=True)

matrix class-attribute instance-attribute

matrix: int | None = field(default=None, kw_only=True)

param1 class-attribute instance-attribute

param1: float | None = field(default=None, kw_only=True)

param2 class-attribute instance-attribute

param2: float | None = field(default=None, kw_only=True)

radius class-attribute instance-attribute

radius: float | None = field(default=None, kw_only=True)

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shader_file class-attribute instance-attribute

shader_file = FSRCNNX_x8

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

sigmoid_center class-attribute instance-attribute

sigmoid_center: float | None = field(default=None, kw_only=True)

sigmoid_slope class-attribute instance-attribute

sigmoid_slope: float | None = field(default=None, kw_only=True)

sigmoidize class-attribute instance-attribute

sigmoidize: int | None = field(default=None, kw_only=True)

taper class-attribute instance-attribute

taper: float | None = field(default=None, kw_only=True)

trc class-attribute instance-attribute

trc: int | None = field(default=None, kw_only=True)

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

kernel_radius

kernel_radius() -> int
Source code
195
196
197
@inject_self.cached.property
def kernel_radius(self) -> int:
    return _default_kernel_radius(__class__, self)  # type: ignore

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    output, _ = expect_bits(clip, 16)

    fmt = get_video_format(output)

    if fmt.num_planes == 1:
        if width > output.width or height > output.height:
            output = output.resize.Point(format=vs.YUV444P16)
        else:
            for div in (4, 2):
                if width % div == 0 and height % div == 0:
                    blank = core.std.BlankClip(output, output.width // div, output.height // div, vs.GRAY16)
                    break
            else:
                blank = output.std.BlankClip(vs.GRAY16)

            output = join(output, blank, blank)

    kwargs |= {
        'shader': str(
            self.shader_file()
            if isinstance(self.shader_file, ShaderFile) else
            ShaderFile.CUSTOM(self.shader_file)  # type: ignore
        ),
        'chroma_loc': self.chroma_loc, 'matrix': self.matrix,
        'trc': self.trc, 'linearize': self.linearize,
        'sigmoidize': self.sigmoidize, 'sigmoid_center': self.sigmoid_center, 'sigmoid_slope': self.sigmoid_slope,
        'antiring': self.antiring, 'filter': self.filter_shader, 'clamp': self.clamp,
        'blur': self.blur, 'taper': self.taper, 'radius': self.radius,
        'param1': self.param1, 'param2': self.param2,
    } | kwargs | {
        'width': output.width * ceil(width / output.width),
        'height': output.height * ceil(height / output.height)
    }

    if not kwargs['filter']:
        kwargs['filter'] = 'box' if fmt.num_planes == 1 else 'ewa_lanczos'

    if not Path(kwargs['shader']).exists():
        try:
            kwargs['shader'] = str(ShaderFile.CUSTOM(kwargs['shader']))  # type: ignore
        except FileWasNotFoundError:
            ...

    output = output.placebo.Shader(**kwargs)

    return self._finish_scale(output, clip, width, height, shift)

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

kernel_radius

kernel_radius() -> int
Source code
195
196
197
@inject_self.cached.property
def kernel_radius(self) -> int:
    return _default_kernel_radius(__class__, self)  # type: ignore

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    output, _ = expect_bits(clip, 16)

    fmt = get_video_format(output)

    if fmt.num_planes == 1:
        if width > output.width or height > output.height:
            output = output.resize.Point(format=vs.YUV444P16)
        else:
            for div in (4, 2):
                if width % div == 0 and height % div == 0:
                    blank = core.std.BlankClip(output, output.width // div, output.height // div, vs.GRAY16)
                    break
            else:
                blank = output.std.BlankClip(vs.GRAY16)

            output = join(output, blank, blank)

    kwargs |= {
        'shader': str(
            self.shader_file()
            if isinstance(self.shader_file, ShaderFile) else
            ShaderFile.CUSTOM(self.shader_file)  # type: ignore
        ),
        'chroma_loc': self.chroma_loc, 'matrix': self.matrix,
        'trc': self.trc, 'linearize': self.linearize,
        'sigmoidize': self.sigmoidize, 'sigmoid_center': self.sigmoid_center, 'sigmoid_slope': self.sigmoid_slope,
        'antiring': self.antiring, 'filter': self.filter_shader, 'clamp': self.clamp,
        'blur': self.blur, 'taper': self.taper, 'radius': self.radius,
        'param1': self.param1, 'param2': self.param2,
    } | kwargs | {
        'width': output.width * ceil(width / output.width),
        'height': output.height * ceil(height / output.height)
    }

    if not kwargs['filter']:
        kwargs['filter'] = 'box' if fmt.num_planes == 1 else 'ewa_lanczos'

    if not Path(kwargs['shader']).exists():
        try:
            kwargs['shader'] = str(ShaderFile.CUSTOM(kwargs['shader']))  # type: ignore
        except FileWasNotFoundError:
            ...

    output = output.placebo.Shader(**kwargs)

    return self._finish_scale(output, clip, width, height, shift)

PlaceboShader dataclass

PlaceboShader(
    shader_file: str | Path,
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None,
    chroma_loc: int | None = None,
    matrix: int | None = None,
    trc: int | None = None,
    linearize: int | None = None,
    sigmoidize: int | None = None,
    sigmoid_center: float | None = None,
    sigmoid_slope: float | None = None,
    antiring: float | None = None,
    filter_shader: str | None = None,
    clamp: float | None = None,
    blur: float | None = None,
    taper: float | None = None,
    radius: float | None = None,
    param1: float | None = None,
    param2: float | None = None
)

Bases: PlaceboShaderBase

antiring class-attribute instance-attribute

antiring: float | None = field(default=None, kw_only=True)

blur class-attribute instance-attribute

blur: float | None = field(default=None, kw_only=True)

chroma_loc class-attribute instance-attribute

chroma_loc: int | None = field(default=None, kw_only=True)

clamp class-attribute instance-attribute

clamp: float | None = field(default=None, kw_only=True)

filter_shader class-attribute instance-attribute

filter_shader: str | None = field(default=None, kw_only=True)

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kwargs instance-attribute

kwargs = kwargs

linearize class-attribute instance-attribute

linearize: int | None = field(default=None, kw_only=True)

matrix class-attribute instance-attribute

matrix: int | None = field(default=None, kw_only=True)

param1 class-attribute instance-attribute

param1: float | None = field(default=None, kw_only=True)

param2 class-attribute instance-attribute

param2: float | None = field(default=None, kw_only=True)

radius class-attribute instance-attribute

radius: float | None = field(default=None, kw_only=True)

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shader_file instance-attribute

shader_file: str | Path

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

sigmoid_center class-attribute instance-attribute

sigmoid_center: float | None = field(default=None, kw_only=True)

sigmoid_slope class-attribute instance-attribute

sigmoid_slope: float | None = field(default=None, kw_only=True)

sigmoidize class-attribute instance-attribute

sigmoidize: int | None = field(default=None, kw_only=True)

taper class-attribute instance-attribute

taper: float | None = field(default=None, kw_only=True)

trc class-attribute instance-attribute

trc: int | None = field(default=None, kw_only=True)

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

kernel_radius

kernel_radius() -> int
Source code
195
196
197
@inject_self.cached.property
def kernel_radius(self) -> int:
    return _default_kernel_radius(__class__, self)  # type: ignore

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    output, _ = expect_bits(clip, 16)

    fmt = get_video_format(output)

    if fmt.num_planes == 1:
        if width > output.width or height > output.height:
            output = output.resize.Point(format=vs.YUV444P16)
        else:
            for div in (4, 2):
                if width % div == 0 and height % div == 0:
                    blank = core.std.BlankClip(output, output.width // div, output.height // div, vs.GRAY16)
                    break
            else:
                blank = output.std.BlankClip(vs.GRAY16)

            output = join(output, blank, blank)

    kwargs |= {
        'shader': str(
            self.shader_file()
            if isinstance(self.shader_file, ShaderFile) else
            ShaderFile.CUSTOM(self.shader_file)  # type: ignore
        ),
        'chroma_loc': self.chroma_loc, 'matrix': self.matrix,
        'trc': self.trc, 'linearize': self.linearize,
        'sigmoidize': self.sigmoidize, 'sigmoid_center': self.sigmoid_center, 'sigmoid_slope': self.sigmoid_slope,
        'antiring': self.antiring, 'filter': self.filter_shader, 'clamp': self.clamp,
        'blur': self.blur, 'taper': self.taper, 'radius': self.radius,
        'param1': self.param1, 'param2': self.param2,
    } | kwargs | {
        'width': output.width * ceil(width / output.width),
        'height': output.height * ceil(height / output.height)
    }

    if not kwargs['filter']:
        kwargs['filter'] = 'box' if fmt.num_planes == 1 else 'ewa_lanczos'

    if not Path(kwargs['shader']).exists():
        try:
            kwargs['shader'] = str(ShaderFile.CUSTOM(kwargs['shader']))  # type: ignore
        except FileWasNotFoundError:
            ...

    output = output.placebo.Shader(**kwargs)

    return self._finish_scale(output, clip, width, height, shift)

PlaceboShaderBase dataclass

PlaceboShaderBase(
    *,
    kernel: KernelT | None = None,
    scaler: ScalerT | None = None,
    shifter: KernelT | None = None,
    chroma_loc: int | None = None,
    matrix: int | None = None,
    trc: int | None = None,
    linearize: int | None = None,
    sigmoidize: int | None = None,
    sigmoid_center: float | None = None,
    sigmoid_slope: float | None = None,
    antiring: float | None = None,
    filter_shader: str | None = None,
    clamp: float | None = None,
    blur: float | None = None,
    taper: float | None = None,
    radius: float | None = None,
    param1: float | None = None,
    param2: float | None = None
)

Bases: PlaceboShaderMeta

Base placebo shader class.

antiring class-attribute instance-attribute

antiring: float | None = field(default=None, kw_only=True)

blur class-attribute instance-attribute

blur: float | None = field(default=None, kw_only=True)

chroma_loc class-attribute instance-attribute

chroma_loc: int | None = field(default=None, kw_only=True)

clamp class-attribute instance-attribute

clamp: float | None = field(default=None, kw_only=True)

filter_shader class-attribute instance-attribute

filter_shader: str | None = field(default=None, kw_only=True)

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kwargs instance-attribute

kwargs = kwargs

linearize class-attribute instance-attribute

linearize: int | None = field(default=None, kw_only=True)

matrix class-attribute instance-attribute

matrix: int | None = field(default=None, kw_only=True)

param1 class-attribute instance-attribute

param1: float | None = field(default=None, kw_only=True)

param2 class-attribute instance-attribute

param2: float | None = field(default=None, kw_only=True)

radius class-attribute instance-attribute

radius: float | None = field(default=None, kw_only=True)

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shader_file instance-attribute

shader_file: str | Path | ShaderFile

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

sigmoid_center class-attribute instance-attribute

sigmoid_center: float | None = field(default=None, kw_only=True)

sigmoid_slope class-attribute instance-attribute

sigmoid_slope: float | None = field(default=None, kw_only=True)

sigmoidize class-attribute instance-attribute

sigmoidize: int | None = field(default=None, kw_only=True)

taper class-attribute instance-attribute

taper: float | None = field(default=None, kw_only=True)

trc class-attribute instance-attribute

trc: int | None = field(default=None, kw_only=True)

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

kernel_radius

kernel_radius() -> int
Source code
195
196
197
@inject_self.cached.property
def kernel_radius(self) -> int:
    return _default_kernel_radius(__class__, self)  # type: ignore

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
@inject_self
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    output, _ = expect_bits(clip, 16)

    fmt = get_video_format(output)

    if fmt.num_planes == 1:
        if width > output.width or height > output.height:
            output = output.resize.Point(format=vs.YUV444P16)
        else:
            for div in (4, 2):
                if width % div == 0 and height % div == 0:
                    blank = core.std.BlankClip(output, output.width // div, output.height // div, vs.GRAY16)
                    break
            else:
                blank = output.std.BlankClip(vs.GRAY16)

            output = join(output, blank, blank)

    kwargs |= {
        'shader': str(
            self.shader_file()
            if isinstance(self.shader_file, ShaderFile) else
            ShaderFile.CUSTOM(self.shader_file)  # type: ignore
        ),
        'chroma_loc': self.chroma_loc, 'matrix': self.matrix,
        'trc': self.trc, 'linearize': self.linearize,
        'sigmoidize': self.sigmoidize, 'sigmoid_center': self.sigmoid_center, 'sigmoid_slope': self.sigmoid_slope,
        'antiring': self.antiring, 'filter': self.filter_shader, 'clamp': self.clamp,
        'blur': self.blur, 'taper': self.taper, 'radius': self.radius,
        'param1': self.param1, 'param2': self.param2,
    } | kwargs | {
        'width': output.width * ceil(width / output.width),
        'height': output.height * ceil(height / output.height)
    }

    if not kwargs['filter']:
        kwargs['filter'] = 'box' if fmt.num_planes == 1 else 'ewa_lanczos'

    if not Path(kwargs['shader']).exists():
        try:
            kwargs['shader'] = str(ShaderFile.CUSTOM(kwargs['shader']))  # type: ignore
        except FileWasNotFoundError:
            ...

    output = output.placebo.Shader(**kwargs)

    return self._finish_scale(output, clip, width, height, shift)

PlaceboShaderMeta dataclass

PlaceboShaderMeta(
    func: (
        _GeneriScaleNoShift | _GeneriScaleWithShift | Callable[..., VideoNode]
    ),
    **kwargs: Any
)

Bases: GenericScaler

Source code
71
72
73
74
75
def __init__(
    self, func: _GeneriScaleNoShift | _GeneriScaleWithShift | Callable[..., vs.VideoNode], **kwargs: Any
) -> None:
    self.func = func
    self.kwargs = kwargs

func instance-attribute

func = func

kernel class-attribute instance-attribute

kernel: KernelT | None = field(default=None, kw_only=True)

Base kernel to be used for certain scaling/shifting/resampling operations. Must be specified and defaults to catrom

kwargs instance-attribute

kwargs = kwargs

scale_function instance-attribute

scale_function: GenericVSFunction

Scale function called internally when scaling

scaler class-attribute instance-attribute

scaler: ScalerT | None = field(default=None, kw_only=True)

Scaler used for scaling operations. Defaults to kernel.

shader_file instance-attribute

shader_file: str | Path | ShaderFile

shifter class-attribute instance-attribute

shifter: KernelT | None = field(default=None, kw_only=True)

Kernel used for shifting operations. Defaults to kernel.

ensure_obj classmethod

ensure_obj(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> BaseScalerT
Source code
186
187
188
189
190
191
192
193
@classmethod
def ensure_obj(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> BaseScalerT:
    return _base_ensure_obj(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

ensure_scaler

ensure_scaler(scaler: ScalerT) -> Scaler
Source code
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def ensure_scaler(self, scaler: ScalerT) -> Scaler:
    from dataclasses import is_dataclass, replace

    scaler_obj = Scaler.ensure_obj(scaler, self.__class__)

    if is_dataclass(scaler_obj):
        from inspect import Signature  #type: ignore[unreachable]

        kwargs = dict[str, ScalerT]()

        init_keys = Signature.from_callable(scaler_obj.__init__).parameters.keys()

        if 'kernel' in init_keys:
            kwargs.update(kernel=self.kernel or scaler_obj.kernel)

        if 'scaler' in init_keys:
            kwargs.update(scaler=self.scaler or scaler_obj.scaler)

        if 'shifter' in init_keys:
            kwargs.update(shifter=self.shifter or scaler_obj.shifter)

        if kwargs:
            scaler_obj = replace(scaler_obj, **kwargs)

    return scaler_obj

from_param classmethod

from_param(
    scaler: str | type[BaseScalerT] | BaseScalerT | None = None,
    /,
    func_except: FuncExceptT | None = None,
) -> type[BaseScalerT]
Source code
177
178
179
180
181
182
183
184
@classmethod
def from_param(
    cls: type[BaseScalerT], scaler: str | type[BaseScalerT] | BaseScalerT | None = None, /,
    func_except: FuncExceptT | None = None
) -> type[BaseScalerT]:
    return _base_from_param(
        cls, (mro := cls.mro())[mro.index(BaseScaler) - 1], scaler, cls._err_class, [], func_except
    )

get_clean_kwargs

get_clean_kwargs(*funcs: Callable[..., Any] | None) -> KwargsT
Source code
199
200
def get_clean_kwargs(self, *funcs: Callable[..., Any] | None) -> KwargsT:
    return _clean_self_kwargs(funcs, self)

get_implemented_funcs

get_implemented_funcs() -> tuple[Callable[..., Any], ...]
Source code
270
271
def get_implemented_funcs(self) -> tuple[Callable[..., Any], ...]:
    return (self.scale, self.multi)

get_scale_args

get_scale_args(
    clip: VideoNode,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None,
    height: int | None = None,
    *funcs: Callable[..., Any],
    **kwargs: Any
) -> KwargsT
Source code
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
@inject_kwargs_params
def get_scale_args(
    self, clip: vs.VideoNode, shift: tuple[TopShift, LeftShift] = (0, 0),
    width: int | None = None, height: int | None = None,
    *funcs: Callable[..., Any], **kwargs: Any
) -> KwargsT:
    return (
        dict(
            src_top=shift[0],
            src_left=shift[1]
        )
        | self.get_clean_kwargs(*funcs)
        | dict(width=width, height=height)
        | kwargs
    )

kernel_radius

kernel_radius() -> int
Source code
195
196
197
@inject_self.cached.property
def kernel_radius(self) -> int:
    return _default_kernel_radius(__class__, self)  # type: ignore

multi

multi(
    clip: VideoNode,
    multi: float = 2,
    shift: tuple[TopShift, LeftShift] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@inject_self.cached
def multi(
    self, clip: vs.VideoNode, multi: float = 2, shift: tuple[TopShift, LeftShift] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    assert check_variable_resolution(clip, self.multi)

    dst_width, dst_height = ceil(clip.width * multi), ceil(clip.height * multi)

    if max(dst_width, dst_height) <= 0.0:
        raise CustomValueError(
            'Multiplying the resolution by "multi" must result in a positive resolution!', self.multi, multi
        )

    return self.scale(clip, dst_width, dst_height, shift, **kwargs)

pretty_string

pretty_string() -> str
Source code
202
203
204
205
206
207
208
209
210
211
212
213
214
@inject_self.cached.property
def pretty_string(self) -> str:
    attrs = {}

    if hasattr(self, 'b'):
        attrs.update(b=self.b, c=self.c)
    elif hasattr(self, 'taps'):
        attrs['taps'] = self.taps

    if hasattr(self, 'kwargs'):
        attrs.update(self.kwargs)

    return f"{self.__class__.__name__}{' (' + ', '.join(f'{k}={v}' for k, v in attrs.items()) + ')' if attrs else ''}"

scale

scale(
    clip: VideoNode,
    width: int | None = None,
    height: int | None = None,
    shift: tuple[float, float] = (0, 0),
    **kwargs: Any
) -> VideoNode
Source code
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
def scale(  # type: ignore
    self, clip: vs.VideoNode, width: int | None = None, height: int | None = None,
    shift: tuple[float, float] = (0, 0), **kwargs: Any
) -> vs.VideoNode:
    width, height = self._wh_norm(clip, width, height)

    kwargs = self.kwargs | kwargs

    output = None

    if shift != (0, 0):
        try:
            output = self.func(clip, width, height, shift, **kwargs)
        except BaseException:
            try:
                output = self.func(clip, width=width, height=height, shift=shift, **kwargs)
            except BaseException:
                pass

    if output is None:
        try:
            output = self.func(clip, width, height, **kwargs)
        except BaseException:
            output = self.func(clip, width=width, height=height, **kwargs)

    return self._finish_scale(output, clip, width, height, shift)

ShaderFile

Bases: ShaderFileBase

Default shader files shipped with vsscale.

CUSTOM class-attribute instance-attribute

CUSTOM = 'custom'

FSRCNNX_x16 class-attribute instance-attribute

FSRCNNX_x16 = 'FSRCNNX_x2_16-0-4-1.glsl'

FSRCNNX_x56 class-attribute instance-attribute

FSRCNNX_x56 = 'FSRCNNX_x2_56-16-4-1.glsl'

FSRCNNX_x8 class-attribute instance-attribute

FSRCNNX_x8 = 'FSRCNNX_x2_8-0-4-1.glsl'

SSIM_DOWNSCALER class-attribute instance-attribute

SSIM_DOWNSCALER = 'SSimDownscaler.glsl'

SSIM_SUPERSAMPLER class-attribute instance-attribute

SSIM_SUPERSAMPLER = 'SSimSuperRes.glsl'

value instance-attribute

value: str

__call__

__call__() -> Path
__call__(file_name: str | Path) -> Path
__call__(file_name: str | Path | MissingT = MISSING) -> Path

Get a path from the shader member, name or path.

Source code
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
def __call__(self, file_name: str | Path | MissingT = MISSING) -> Path:
    """Get a path from the shader member, name or path."""

    if self is not ShaderFile.CUSTOM:
        file_name = self.value

    if file_name is MISSING:  # type: ignore
        raise TypeError("ShaderFile.__call__() missing 1 required positional argument: 'file_name'")

    file_name, cwd = Path(file_name), Path.cwd()

    assets_dirs = [
        file_name,
        cwd / file_name,
        cwd / '.shaders' / file_name,
        cwd / '_shaders' / file_name,
        cwd / '.assets' / file_name,
        cwd / '_assets' / file_name
    ]

    for asset_dir in assets_dirs:
        if asset_dir.is_file():
            return asset_dir

    mpv_dir = get_user_data_dir().parent / 'Roaming' / 'mpv' / 'shaders' / file_name

    if mpv_dir.is_file():
        return mpv_dir

    raise FileWasNotFoundError(f'"{file_name}" could not be found!', str(ShaderFile.CUSTOM))