Skip to content

Commit

Permalink
Add custom kernels
Browse files Browse the repository at this point in the history
Functionality is about the same as in Akarin's fork, but it's implemented in a different way internally.

Also added force/force_h/force_v paramenters to force sampling even if the resolution stays the same.

Only supported in the VapourSynth plugin.
  • Loading branch information
Frechdachs committed Apr 2, 2022
1 parent c4bb61d commit 2d8936f
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 47 deletions.
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,37 @@ The VapourSynth plugin itself supports every constant input format. If the forma
The included python wrapper, contrary to using the plugin directly, doesn't descale the chroma planes but scales them normally with `Spline36`.

```
descale.Debilinear(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, int opt=0)
descale.Debilinear(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, bool force, bool force_h, bool force_v, int opt=0)
descale.Debicubic(clip src, int width, int height, float b=0.0, float c=0.5, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, int opt=0)
descale.Debicubic(clip src, int width, int height, float b=0.0, float c=0.5, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, bool force, bool force_h, bool force_v, int opt=0)
descale.Delanczos(clip src, int width, int height, int taps=3, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, int opt=0)
descale.Delanczos(clip src, int width, int height, int taps=3, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, bool force, bool force_h, bool force_v, int opt=0)
descale.Despline16(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, int opt=0)
descale.Despline16(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, bool force, bool force_h, bool force_v, int opt=0)
descale.Despline36(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, int opt=0)
descale.Despline36(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, bool force, bool force_h, bool force_v, int opt=0)
descale.Despline64(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, int opt=0)
descale.Despline64(clip src, int width, int height, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, bool force, bool force_h, bool force_v, int opt=0)
descale.Descale(clip src, int width, int height, str kernel, int taps=3, float b=0.0, float c=0.0, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, int opt=0)
descale.Descale(clip src, int width, int height, str kernel, func custom_kernel, int taps=3, float b=0.0, float c=0.0, float src_left=0.0, float src_top=0.0, float src_width=width, float src_height=height, bool force, bool force_h, bool force_v, int opt=0)
```

The AviSynth+ plugin is used similarly, but without the `descale` namespace.
Custom kernels are only supported in the VapourSynth plugin.

### Custom kernels

```python
# Debilinear
core.descale.Descale(src, w, h, custom_kernel=lambda x: 1.0 - x, taps=1)

# Delanczos
import math
def sinc(x):
return 1.0 if x == 0 else math.sin(x * math.pi) / (x * math.pi)
taps = 3
core.descale.Descale(src, w, h, custom_kernel=lambda x: sinc(x) * sinc(x / taps), taps=taps)
```

## How does this work?

Expand Down
6 changes: 3 additions & 3 deletions descale.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def Despline64(src, width, height, yuv444=False, gray=False, chromaloc=None):
return Descale(src, width, height, kernel='spline64', taps=None, b=None, c=None, yuv444=yuv444, gray=gray, chromaloc=chromaloc)


def Descale(src, width, height, kernel='bilinear', taps=3, b=0.0, c=0.5, yuv444=False, gray=False, chromaloc=None):
def Descale(src, width, height, kernel=None, custom_kernel=None, taps=None, b=None, c=None, yuv444=False, gray=False, chromaloc=None):
src_f = src.format
src_cf = src_f.color_family
src_st = src_f.sample_type
Expand All @@ -31,10 +31,10 @@ def Descale(src, width, height, kernel='bilinear', taps=3, b=0.0, c=0.5, yuv444=
src_sh = src_f.subsampling_h

if src_cf == RGB and not gray:
rgb = to_rgbs(src).descale.Descale(width, height, kernel, taps, b, c)
rgb = to_rgbs(src).descale.Descale(width, height, kernel, custom_kernel, taps, b, c)
return rgb.resize.Point(format=src_f.id)

y = to_grays(src).descale.Descale(width, height, kernel, taps, b, c)
y = to_grays(src).descale.Descale(width, height, kernel, custom_kernel, taps, b, c)
y_f = core.register_format(GRAY, src_st, src_bits, 0, 0)
y = y.resize.Point(format=y_f.id)

Expand Down
13 changes: 11 additions & 2 deletions include/descale.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ typedef enum DescaleMode
DESCALE_MODE_LANCZOS = 3,
DESCALE_MODE_SPLINE16 = 4,
DESCALE_MODE_SPLINE36 = 5,
DESCALE_MODE_SPLINE64 = 6
DESCALE_MODE_SPLINE64 = 6,
DESCALE_MODE_CUSTOM = 7
} DescaleMode;


Expand All @@ -51,15 +52,23 @@ typedef enum DescaleOpt
} DescaleOpt;


typedef struct DescaleCustomKernel
{
double (*f)(double x, void *user_data);
void *user_data;
} DescaleCustomKernel;


// Optional struct members should be initialized to 0 if not used
typedef struct DescaleParams
{
enum DescaleMode mode;
int taps; // required if mode is LANCZOS
int taps; // required if mode is LANCZOS or CUSTOM
double param1; // required if mode is BICUBIC
double param2; // required if mode is BICUBIC
double shift; // optional
double active_dim; // always required; usually equal to dst_dim
DescaleCustomKernel custom_kernel; // required if mode is CUSTOM
} DescaleParams;


Expand Down
15 changes: 11 additions & 4 deletions meson.build
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
project('Descale', 'c',
default_options: ['buildtype=release', 'b_ndebug=if-release', 'c_std=c99'],
meson_version: '>=0.51.0',
version: '7'
version: '8'
)

add_global_arguments(['-D_XOPEN_SOURCE=700'], language: 'c')
Expand Down Expand Up @@ -47,12 +47,19 @@ if host_machine.system() == 'windows'
else
m_dep = cc.find_library('m', required: false)
p_dep = cc.find_library('pthread')
vs = dependency('vapoursynth').partial_dependency(compile_args: true, includes: true)
deps += [m_dep, p_dep, vs]
deps += [m_dep, p_dep]
if libtype in ['vapoursynth', 'both']
vs = dependency('vapoursynth').partial_dependency(compile_args: true, includes: true)
deps += [vs]
endif
if libtype in ['avisynth', 'both']
avs = dependency('avisynth')
deps += [avs]
endif
if libtype in ['vapoursynth', 'both']
installdir = join_paths(vs.get_pkgconfig_variable('libdir'), 'vapoursynth')
else
installdir = join_paths(vs.get_pkgconfig_variable('libdir'), 'avisynth')
installdir = join_paths(avs.get_pkgconfig_variable('libdir'), 'avisynth')
endif
endif

Expand Down
10 changes: 7 additions & 3 deletions src/avsplugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,7 @@ static AVS_Value AVSC_CC avs_descale_create(AVS_ScriptEnvironment *env, AVS_Valu
b = avs_defined(v) ? avs_as_float(v) : 0.0;
v = avs_array_elt(args, idx++);
c = avs_defined(v) ? avs_as_float(v) : 0.5;
}
else {
} else {
b = 0.0;
c = 0.5;
}
Expand All @@ -263,6 +262,11 @@ static AVS_Value AVSC_CC avs_descale_create(AVS_ScriptEnvironment *env, AVS_Valu
bool process_h = dst_width != src_width || shift_h != 0.0 || active_width != (double)dst_width;
bool process_v = dst_height != src_height || shift_v != 0.0 || active_height != (double)dst_height;

if (!process_h && !process_v) {
v = avs_new_value_clip(clip);
goto done;
}

v = avs_array_elt(args, idx++);
int opt = avs_defined(v) ? avs_as_int(v) : 0;
enum DescaleOpt opt_enum;
Expand All @@ -277,7 +281,7 @@ static AVS_Value AVSC_CC avs_descale_create(AVS_ScriptEnvironment *env, AVS_Valu
if (bytes_per_pixel != 4) {
AVS_Value c2, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11;
c1 = avs_new_value_clip(clip);
//avs_release_clip(clip); // This is apparently wrong, leaving it uncommented crashes sometimes
avs_release_clip(clip);
a1 = avs_new_value_int(32);
AVS_Value convert_args[] = {c1, a1};
c2 = avs_invoke(env, "ConvertBits", avs_new_value_array(convert_args, 2), NULL);
Expand Down
19 changes: 12 additions & 7 deletions src/descale.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ static inline double cube(double x)
}


static double calculate_weight(enum DescaleMode mode, int support, double distance, double b, double c)
static double calculate_weight(enum DescaleMode mode, int support, double distance, double b, double c, struct DescaleCustomKernel *ck)
{
distance = fabs(distance);

Expand Down Expand Up @@ -221,6 +221,8 @@ static double calculate_weight(enum DescaleMode mode, int support, double distan
} else {
return 0.0;
}
} else if (mode == DESCALE_MODE_CUSTOM) {
return ck->f(distance, ck->user_data);
}

return 0.0;
Expand All @@ -242,7 +244,7 @@ static double round_halfup(double x)

// Most of this is taken from zimg
// https://github.com/sekrit-twc/zimg/blob/ce27c27f2147fbb28e417fbf19a95d3cf5d68f4f/src/zimg/resize/filter.cpp#L227
static void scaling_weights(enum DescaleMode mode, int support, int src_dim, int dst_dim, double param1, double param2, double shift, double active_dim, double **weights)
static void scaling_weights(enum DescaleMode mode, int support, int src_dim, int dst_dim, double param1, double param2, double shift, double active_dim, struct DescaleCustomKernel *ck, double **weights)
{
*weights = calloc(src_dim * dst_dim, sizeof (double));
double ratio = (double)dst_dim / active_dim;
Expand All @@ -254,7 +256,7 @@ static void scaling_weights(enum DescaleMode mode, int support, int src_dim, int
double begin_pos = round_halfup(pos - support) + 0.5;
for (int j = 0; j < 2 * support; j++) {
double xpos = begin_pos + j;
total += calculate_weight(mode, support, xpos - pos, param1, param2);
total += calculate_weight(mode, support, xpos - pos, param1, param2, ck);
}
for (int j = 0; j < 2 * support; j++) {
double xpos = begin_pos + j;
Expand All @@ -269,7 +271,7 @@ static void scaling_weights(enum DescaleMode mode, int support, int src_dim, int
real_pos = xpos;

int idx = (int)floor(real_pos);
(*weights)[i * src_dim + idx] += calculate_weight(mode, support, xpos - pos, param1, param2) / total;
(*weights)[i * src_dim + idx] += calculate_weight(mode, support, xpos - pos, param1, param2, ck) / total;
}
}
}
Expand Down Expand Up @@ -561,18 +563,21 @@ static struct DescaleCore *create_core(int src_dim, int dst_dim, struct DescaleP
support = 2;
} else if (params->mode == DESCALE_MODE_LANCZOS) {
support = params->taps;
if (support == 0)
return NULL;
} else if (params->mode == DESCALE_MODE_SPLINE16) {
support = 2;
} else if (params->mode == DESCALE_MODE_SPLINE36) {
support = 3;
} else if (params->mode == DESCALE_MODE_SPLINE64) {
support = 4;
} else if (params->mode == DESCALE_MODE_CUSTOM) {
support = params->taps;
} else {
return NULL;
}

if (support == 0)
return NULL;

core.src_dim = src_dim;
core.dst_dim = dst_dim;
core.bandwidth = support * 4 - 1;
Expand All @@ -582,7 +587,7 @@ static struct DescaleCore *create_core(int src_dim, int dst_dim, struct DescaleP
double *multiplied_weights;
double *lower;

scaling_weights(params->mode, support, dst_dim, src_dim, params->param1, params->param2, params->shift, params->active_dim, &weights);
scaling_weights(params->mode, support, dst_dim, src_dim, params->param1, params->param2, params->shift, params->active_dim, &params->custom_kernel, &weights);
transpose_matrix(src_dim, dst_dim, weights, &transposed_weights);

core.weights_left_idx = calloc(ceil_n(dst_dim, 8), sizeof (int));
Expand Down
Loading

0 comments on commit 2d8936f

Please sign in to comment.