videoscale: support lanczos method for NV formats

Support lanczos scaling method for NV12 and NV21 formats.
Scale the 'Y' plane and scale 'NV' plane.
Implementation for submethods - int16, int32, float and double

https://bugzilla.gnome.org/show_bug.cgi?id=737400
This commit is contained in:
Ravi Kiran K N 2014-09-26 09:14:51 +05:30 committed by Luis de Bethencourt
parent 70d729aa8c
commit f16cf75194
3 changed files with 481 additions and 8 deletions

View file

@ -422,7 +422,7 @@ get_formats_filter (GstVideoScaleMethod method)
GST_STATIC_CAPS ("video/x-raw(ANY)," GST_STATIC_CAPS ("video/x-raw(ANY),"
"format = (string) { RGBx, xRGB, BGRx, xBGR, RGBA, " "format = (string) { RGBx, xRGB, BGRx, xBGR, RGBA, "
"ARGB, BGRA, ABGR, AYUV, ARGB64, AYUV64, " "ARGB, BGRA, ABGR, AYUV, ARGB64, AYUV64, "
"I420, YV12, Y444, Y42B, Y41B }"); "I420, YV12, Y444, Y42B, Y41B, NV12, NV21 }");
return gst_static_caps_get (&lanczos_filter); return gst_static_caps_get (&lanczos_filter);
} }
default: default:
@ -1396,6 +1396,15 @@ do_scale (GstVideoFilter * filter, VSImage dest[4], VSImage src[4])
vs_image_scale_4tap_Y (&dest[0], &src[0], videoscale->tmp_buf); vs_image_scale_4tap_Y (&dest[0], &src[0], videoscale->tmp_buf);
vs_image_scale_4tap_NV12 (&dest[1], &src[1], videoscale->tmp_buf); vs_image_scale_4tap_NV12 (&dest[1], &src[1], videoscale->tmp_buf);
break; break;
case GST_VIDEO_SCALE_LANCZOS:
vs_image_scale_lanczos_Y (&dest[0], &src[0], videoscale->tmp_buf,
videoscale->sharpness, videoscale->dither, videoscale->submethod,
videoscale->envelope, videoscale->sharpen);
vs_image_scale_lanczos_NV (&dest[1], &src[1], videoscale->tmp_buf,
videoscale->sharpness, videoscale->dither, videoscale->submethod,
videoscale->envelope, videoscale->sharpen);
break;
default: default:
goto unknown_mode; goto unknown_mode;
} }

View file

@ -125,6 +125,14 @@ G_GNUC_INTERNAL void vs_image_scale_lanczos_Y (const VSImage * dest,
double a, double a,
double sharpen); double sharpen);
G_GNUC_INTERNAL void vs_image_scale_lanczos_NV (const VSImage * dest,
const VSImage * src,
uint8_t * tmpbuf,
double sharpness,
gboolean dither,
int submethod,
double a,
double sharpen);
G_GNUC_INTERNAL void vs_image_scale_nearest_RGB565 (const VSImage * dest, G_GNUC_INTERNAL void vs_image_scale_nearest_RGB565 (const VSImage * dest,
const VSImage * src, const VSImage * src,

View file

@ -143,6 +143,10 @@
#define TMP_LINE_S32_AYUV(i) ((gint32 *)scale->tmpdata + (i)*4*(scale->dest->width)) #define TMP_LINE_S32_AYUV(i) ((gint32 *)scale->tmpdata + (i)*4*(scale->dest->width))
#define TMP_LINE_FLOAT_AYUV(i) ((float *)scale->tmpdata + (i)*4*(scale->dest->width)) #define TMP_LINE_FLOAT_AYUV(i) ((float *)scale->tmpdata + (i)*4*(scale->dest->width))
#define TMP_LINE_DOUBLE_AYUV(i) ((double *)scale->tmpdata + (i)*4*(scale->dest->width)) #define TMP_LINE_DOUBLE_AYUV(i) ((double *)scale->tmpdata + (i)*4*(scale->dest->width))
#define TMP_LINE_S32_NV(i) ((gint32 *)scale->tmpdata + (i)*2*(scale->dest->width))
#define TMP_LINE_S16_NV(i) ((gint16 *)scale->tmpdata + (i)*2*(scale->dest->width))
#define TMP_LINE_FLOAT_NV(i) ((float *)scale->tmpdata + (i)*2*(scale->dest->width))
#define TMP_LINE_DOUBLE_NV(i) ((double *)scale->tmpdata + (i)*2*(scale->dest->width))
#define PTR_OFFSET(a,b) ((void *)((char *)(a) + (b))) #define PTR_OFFSET(a,b) ((void *)((char *)(a) + (b)))
@ -212,6 +216,20 @@ static void vs_image_scale_lanczos_AYUV64_double (const VSImage * dest,
const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither, const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither,
double a, double sharpen); double a, double sharpen);
static void
vs_image_scale_lanczos_NV_int16 (const VSImage * dest, const VSImage * src,
uint8_t * tmpbuf, double sharpness, gboolean dither, double a,
double sharpen);
static void vs_image_scale_lanczos_NV_int32 (const VSImage * dest,
const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither,
double a, double sharpen);
static void vs_image_scale_lanczos_NV_float (const VSImage * dest,
const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither,
double a, double sharpen);
static void vs_image_scale_lanczos_NV_double (const VSImage * dest,
const VSImage * src, uint8_t * tmpbuf, double sharpness, gboolean dither,
double a, double sharpen);
static double static double
sinc (double x) sinc (double x)
{ {
@ -722,6 +740,60 @@ function (dest_type *dest, const gint32 *offsets, \
} \ } \
} }
#define RESAMPLE_HORIZ_NV(function, dest_type, tap_type, src_type, _n_taps, _shift) \
static void \
function (dest_type *dest, const gint32 *offsets, \
const tap_type *taps, const src_type *src, int n_taps, int shift, int n) \
{ \
int i; \
int k; \
dest_type sum1; \
dest_type sum2; \
const src_type *srcline; \
const tap_type *tapsline; \
int offset; \
if (_shift > 0) offset = (1<<_shift)>>1; \
else offset = 0; \
for (i = 0; i < n; i++) { \
srcline = src + 2*offsets[i]; \
tapsline = taps + i * _n_taps; \
sum1 = 0; \
sum2 = 0; \
for (k = 0; k < _n_taps; k++) { \
sum1 += srcline[k*2+0] * tapsline[k]; \
sum2 += srcline[k*2+1] * tapsline[k]; \
} \
dest[i*2+0] = (sum1 + offset) >> _shift; \
dest[i*2+1] = (sum2 + offset) >> _shift; \
} \
}
#define RESAMPLE_HORIZ_NV_FLOAT(function, dest_type, tap_type, src_type, _n_taps) \
static void \
function (dest_type *dest, const gint32 *offsets, \
const tap_type *taps, const src_type *src, int n_taps, int shift, int n) \
{ \
int i; \
int k; \
dest_type sum1; \
dest_type sum2; \
const src_type *srcline; \
const tap_type *tapsline; \
for (i = 0; i < n; i++) { \
srcline = src + 2*offsets[i]; \
tapsline = taps + i * _n_taps; \
sum1 = 0; \
sum2 = 0; \
for (k = 0; k < _n_taps; k++) { \
sum1 += srcline[k*2+0] * tapsline[k]; \
sum2 += srcline[k*2+1] * tapsline[k]; \
} \
dest[i*2+0] = sum1; \
dest[i*2+1] = sum2; \
} \
}
/* *INDENT-OFF* */ /* *INDENT-OFF* */
RESAMPLE_HORIZ_FLOAT (resample_horiz_double_u8_generic, double, double, RESAMPLE_HORIZ_FLOAT (resample_horiz_double_u8_generic, double, double,
guint8, n_taps) guint8, n_taps)
@ -734,6 +806,10 @@ RESAMPLE_HORIZ_AYUV_FLOAT (resample_horiz_float_ayuv_generic, float, float,
RESAMPLE_HORIZ_AYUV_FLOAT (resample_horiz_double_ayuv_generic_s16, double, double, RESAMPLE_HORIZ_AYUV_FLOAT (resample_horiz_double_ayuv_generic_s16, double, double,
guint16, n_taps) guint16, n_taps)
RESAMPLE_HORIZ_NV_FLOAT (resample_horiz_double_nv_generic, double, double,
guint8, n_taps)
RESAMPLE_HORIZ_NV_FLOAT (resample_horiz_float_nv_generic, float, float,
guint8, n_taps)
RESAMPLE_HORIZ (resample_horiz_int32_int32_u8_generic, gint32, gint32, RESAMPLE_HORIZ (resample_horiz_int32_int32_u8_generic, gint32, gint32,
guint8, n_taps, shift) guint8, n_taps, shift)
@ -778,6 +854,27 @@ RESAMPLE_HORIZ_AYUV (resample_horiz_int16_int16_ayuv_taps8_shift0, gint16, gint1
guint8, 8, 0) guint8, 8, 0)
RESAMPLE_HORIZ_AYUV (resample_horiz_int16_int16_ayuv_taps4_shift0, gint16, gint16, RESAMPLE_HORIZ_AYUV (resample_horiz_int16_int16_ayuv_taps4_shift0, gint16, gint16,
guint8, 4, 0) guint8, 4, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int32_int32_nv_taps16_shift0, gint32, gint32,
guint8, 16, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int32_int32_nv_taps12_shift0, gint32, gint32,
guint8, 12, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int32_int32_nv_taps8_shift0, gint32, gint32,
guint8, 8, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int32_int32_nv_taps4_shift0, gint32, gint32,
guint8, 4, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int32_int32_nv_generic, gint32, gint32,
guint8, n_taps, shift)
RESAMPLE_HORIZ_NV (resample_horiz_int16_int16_nv_taps16_shift0, gint16, gint16,
guint8, 16, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int16_int16_nv_taps12_shift0, gint16, gint16,
guint8, 12, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int16_int16_nv_taps8_shift0, gint16, gint16,
guint8, 8, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int16_int16_nv_taps4_shift0, gint16, gint16,
guint8, 4, 0)
RESAMPLE_HORIZ_NV (resample_horiz_int16_int16_nv_generic, gint32, gint32,
guint8, n_taps, shift)
/* *INDENT-ON* */ /* *INDENT-ON* */
#define RESAMPLE_VERT(function, tap_type, src_type, _n_taps, _shift) \ #define RESAMPLE_VERT(function, tap_type, src_type, _n_taps, _shift) \
@ -872,8 +969,8 @@ function (dest_type *dest, \
err_y -= floor (err_y); \ err_y -= floor (err_y); \
} \ } \
} }
/* *INDENT-OFF* */ /* *INDENT-OFF* */
RESAMPLE_VERT_FLOAT (resample_vert_double_generic, guint8, 255, double, double, n_taps, RESAMPLE_VERT_FLOAT (resample_vert_double_generic, guint8, 255, double, double, n_taps,
shift) shift)
RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_double_generic, guint8, 255, double, double, RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_double_generic, guint8, 255, double, double,
@ -893,7 +990,6 @@ RESAMPLE_VERT_FLOAT_DITHER (resample_vert_dither_float_generic, guint8, 255, flo
#define S16_SHIFT2 7 #define S16_SHIFT2 7
#define S16_MIDSHIFT 0 #define S16_MIDSHIFT 0
#define S16_POSTSHIFT (S16_SHIFT1+S16_SHIFT2-S16_MIDSHIFT) #define S16_POSTSHIFT (S16_SHIFT1+S16_SHIFT2-S16_MIDSHIFT)
static void static void
vs_scale_lanczos_Y_int16 (Scale * scale) vs_scale_lanczos_Y_int16 (Scale * scale)
{ {
@ -1238,10 +1334,6 @@ vs_image_scale_lanczos_Y_float (const VSImage * dest, const VSImage * src,
g_free (scale->tmpdata); g_free (scale->tmpdata);
} }
static void static void
vs_scale_lanczos_AYUV_int16 (Scale * scale) vs_scale_lanczos_AYUV_int16 (Scale * scale)
{ {
@ -1337,7 +1429,6 @@ vs_image_scale_lanczos_AYUV_int16 (const VSImage * dest, const VSImage * src,
g_free (scale->tmpdata); g_free (scale->tmpdata);
} }
static void static void
vs_scale_lanczos_AYUV_int32 (Scale * scale) vs_scale_lanczos_AYUV_int32 (Scale * scale)
{ {
@ -1654,3 +1745,368 @@ vs_image_scale_lanczos_AYUV64_double (const VSImage * dest, const VSImage * src,
scale1d_cleanup (&scale->y_scale1d); scale1d_cleanup (&scale->y_scale1d);
g_free (scale->tmpdata); g_free (scale->tmpdata);
} }
void
vs_image_scale_lanczos_NV (const VSImage * dest, const VSImage * src,
uint8_t * tmpbuf, double sharpness, gboolean dither, int submethod,
double a, double sharpen)
{
switch (submethod) {
case 0:
default:
vs_image_scale_lanczos_NV_int16 (dest, src, tmpbuf, sharpness, dither,
a, sharpen);
break;
case 1:
vs_image_scale_lanczos_NV_int32 (dest, src, tmpbuf, sharpness, dither,
a, sharpen);
break;
case 2:
vs_image_scale_lanczos_NV_float (dest, src, tmpbuf, sharpness, dither,
a, sharpen);
break;
case 3:
vs_image_scale_lanczos_NV_double (dest, src, tmpbuf, sharpness, dither,
a, sharpen);
break;
}
}
static void
vs_scale_lanczos_NV_int16 (Scale * scale)
{
int j;
int yi;
int tmp_yi;
tmp_yi = 0;
for (j = 0; j < scale->dest->height; j++) {
guint8 *destline;
gint16 *taps;
destline = scale->dest->pixels + scale->dest->stride * j;
yi = scale->y_scale1d.offsets[j];
while (tmp_yi < yi + scale->y_scale1d.n_taps) {
scale->horiz_resample_func (TMP_LINE_S16_NV (tmp_yi),
scale->x_scale1d.offsets, scale->x_scale1d.taps, SRC_LINE (tmp_yi),
scale->x_scale1d.n_taps, S16_MIDSHIFT, scale->dest->width);
tmp_yi++;
}
taps = (gint16 *) scale->y_scale1d.taps + j * scale->y_scale1d.n_taps;
if (scale->dither) {
resample_vert_dither_int16_generic (destline,
taps, TMP_LINE_S16_NV (scale->y_scale1d.offsets[j]),
sizeof (gint16) * 2 * scale->dest->width,
scale->y_scale1d.n_taps, S16_POSTSHIFT, scale->dest->width * 2);
} else {
resample_vert_int16_generic (destline,
taps, TMP_LINE_S16_NV (scale->y_scale1d.offsets[j]),
sizeof (gint16) * 2 * scale->dest->width,
scale->y_scale1d.n_taps, S16_POSTSHIFT, scale->dest->width * 2);
}
}
}
static void
vs_scale_lanczos_NV_int32 (Scale * scale)
{
int j;
int yi;
int tmp_yi;
tmp_yi = 0;
for (j = 0; j < scale->dest->height; j++) {
guint8 *destline;
gint32 *taps;
destline = scale->dest->pixels + scale->dest->stride * j;
yi = scale->y_scale1d.offsets[j];
while (tmp_yi < yi + scale->y_scale1d.n_taps) {
scale->horiz_resample_func (TMP_LINE_S32_NV (tmp_yi),
scale->x_scale1d.offsets, scale->x_scale1d.taps, SRC_LINE (tmp_yi),
scale->x_scale1d.n_taps, S32_MIDSHIFT, scale->dest->width);
tmp_yi++;
}
taps = (gint32 *) scale->y_scale1d.taps + j * scale->y_scale1d.n_taps;
if (scale->dither) {
resample_vert_dither_int32_generic (destline,
taps, TMP_LINE_S32_NV (scale->y_scale1d.offsets[j]),
sizeof (gint32) * 2 * scale->dest->width, scale->y_scale1d.n_taps,
S32_POSTSHIFT, scale->dest->width * 2);
} else {
resample_vert_int32_generic (destline,
taps, TMP_LINE_S32_NV (scale->y_scale1d.offsets[j]),
sizeof (gint32) * 2 * scale->dest->width, scale->y_scale1d.n_taps,
S32_POSTSHIFT, scale->dest->width * 2);
}
}
}
static void
vs_scale_lanczos_NV_float (Scale * scale)
{
int j;
int yi;
int tmp_yi;
tmp_yi = 0;
for (j = 0; j < scale->dest->height; j++) {
guint8 *destline;
float *taps;
destline = scale->dest->pixels + scale->dest->stride * j;
yi = scale->y_scale1d.offsets[j];
while (tmp_yi < yi + scale->y_scale1d.n_taps) {
scale->horiz_resample_func (TMP_LINE_FLOAT_NV (tmp_yi),
scale->x_scale1d.offsets, scale->x_scale1d.taps, SRC_LINE (tmp_yi),
scale->x_scale1d.n_taps, 0, scale->dest->width);
tmp_yi++;
}
taps = (float *) scale->y_scale1d.taps + j * scale->y_scale1d.n_taps;
if (scale->dither) {
resample_vert_dither_float_generic (destline,
taps, TMP_LINE_FLOAT_NV (scale->y_scale1d.offsets[j]),
sizeof (float) * 2 * scale->dest->width, scale->y_scale1d.n_taps, 0,
scale->dest->width * 2);
} else {
resample_vert_float_generic (destline,
taps, TMP_LINE_FLOAT_NV (scale->y_scale1d.offsets[j]),
sizeof (float) * 2 * scale->dest->width, scale->y_scale1d.n_taps, 0,
scale->dest->width * 2);
}
}
}
static void
vs_scale_lanczos_NV_double (Scale * scale)
{
int j;
int yi;
int tmp_yi;
tmp_yi = 0;
for (j = 0; j < scale->dest->height; j++) {
guint8 *destline;
double *taps;
destline = scale->dest->pixels + scale->dest->stride * j;
yi = scale->y_scale1d.offsets[j];
while (tmp_yi < yi + scale->y_scale1d.n_taps) {
scale->horiz_resample_func (TMP_LINE_DOUBLE_NV (tmp_yi),
scale->x_scale1d.offsets, scale->x_scale1d.taps, SRC_LINE (tmp_yi),
scale->x_scale1d.n_taps, 0, scale->dest->width);
tmp_yi++;
}
taps = (double *) scale->y_scale1d.taps + j * scale->y_scale1d.n_taps;
if (scale->dither) {
resample_vert_dither_double_generic (destline,
taps, TMP_LINE_DOUBLE_NV (scale->y_scale1d.offsets[j]),
sizeof (double) * 2 * scale->dest->width,
scale->y_scale1d.n_taps, 0, scale->dest->width * 2);
} else {
resample_vert_double_generic (destline,
taps, TMP_LINE_DOUBLE_NV (scale->y_scale1d.offsets[j]),
sizeof (double) * 2 * scale->dest->width,
scale->y_scale1d.n_taps, 0, scale->dest->width * 2);
}
}
}
void
vs_image_scale_lanczos_NV_int32 (const VSImage * dest, const VSImage * src,
uint8_t * tmpbuf, double sharpness, gboolean dither, double a,
double sharpen)
{
Scale s = { 0 };
Scale *scale = &s;
int n_taps;
scale->dest = dest;
scale->src = src;
n_taps = scale1d_get_n_taps (src->width, dest->width, a, sharpness);
n_taps = ROUND_UP_4 (n_taps);
scale1d_calculate_taps_int32 (&scale->x_scale1d,
src->width, dest->width, n_taps, a, sharpness, sharpen, S32_SHIFT1);
n_taps = scale1d_get_n_taps (src->height, dest->height, a, sharpness);
scale1d_calculate_taps_int32 (&scale->y_scale1d,
src->height, dest->height, n_taps, a, sharpness, sharpen, S32_SHIFT2);
scale->dither = dither;
switch (scale->x_scale1d.n_taps) {
case 4:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int32_int32_nv_taps4_shift0;
break;
case 8:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int32_int32_nv_taps8_shift0;
break;
case 12:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int32_int32_nv_taps12_shift0;
break;
case 16:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int32_int32_nv_taps16_shift0;
break;
default:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int32_int32_nv_generic;
break;
}
scale->tmpdata =
g_malloc (sizeof (int32_t) * scale->dest->width * scale->src->height * 2);
vs_scale_lanczos_NV_int32 (scale);
scale1d_cleanup (&scale->x_scale1d);
scale1d_cleanup (&scale->y_scale1d);
g_free (scale->tmpdata);
}
void
vs_image_scale_lanczos_NV_int16 (const VSImage * dest, const VSImage * src,
uint8_t * tmpbuf, double sharpness, gboolean dither, double a,
double sharpen)
{
Scale s = { 0 };
Scale *scale = &s;
int n_taps;
scale->dest = dest;
scale->src = src;
n_taps = scale1d_get_n_taps (src->width, dest->width, a, sharpness);
n_taps = ROUND_UP_4 (n_taps);
scale1d_calculate_taps_int16 (&scale->x_scale1d,
src->width, dest->width, n_taps, a, sharpness, sharpen, S16_SHIFT1);
n_taps = scale1d_get_n_taps (src->height, dest->height, a, sharpness);
scale1d_calculate_taps_int16 (&scale->y_scale1d,
src->height, dest->height, n_taps, a, sharpness, sharpen, S16_SHIFT2);
scale->dither = dither;
switch (scale->x_scale1d.n_taps) {
case 4:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int16_int16_nv_taps4_shift0;
break;
case 8:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int16_int16_nv_taps8_shift0;
break;
case 12:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int16_int16_nv_taps12_shift0;
break;
case 16:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int16_int16_nv_taps16_shift0;
break;
default:
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_int16_int16_nv_generic;
break;
}
scale->tmpdata =
g_malloc (sizeof (gint16) * scale->dest->width * scale->src->height * 2);
vs_scale_lanczos_NV_int16 (scale);
scale1d_cleanup (&scale->x_scale1d);
scale1d_cleanup (&scale->y_scale1d);
g_free (scale->tmpdata);
}
void
vs_image_scale_lanczos_NV_float (const VSImage * dest, const VSImage * src,
uint8_t * tmpbuf, double sharpness, gboolean dither, double a,
double sharpen)
{
Scale s = { 0 };
Scale *scale = &s;
int n_taps;
scale->dest = dest;
scale->src = src;
n_taps = scale1d_get_n_taps (src->width, dest->width, a, sharpness);
scale1d_calculate_taps_float (&scale->x_scale1d,
src->width, dest->width, n_taps, a, sharpness, sharpen);
n_taps = scale1d_get_n_taps (src->height, dest->height, a, sharpness);
scale1d_calculate_taps_float (&scale->y_scale1d,
src->height, dest->height, n_taps, a, sharpness, sharpen);
scale->dither = dither;
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_float_nv_generic;
scale->tmpdata =
g_malloc (sizeof (float) * scale->dest->width * scale->src->height * 2);
vs_scale_lanczos_NV_float (scale);
scale1d_cleanup (&scale->x_scale1d);
scale1d_cleanup (&scale->y_scale1d);
g_free (scale->tmpdata);
}
void
vs_image_scale_lanczos_NV_double (const VSImage * dest, const VSImage * src,
uint8_t * tmpbuf, double sharpness, gboolean dither, double a,
double sharpen)
{
Scale s = { 0 };
Scale *scale = &s;
int n_taps;
scale->dest = dest;
scale->src = src;
n_taps = scale1d_get_n_taps (src->width, dest->width, a, sharpness);
scale1d_calculate_taps (&scale->x_scale1d,
src->width, dest->width, n_taps, a, sharpness, sharpen);
n_taps = scale1d_get_n_taps (src->height, dest->height, a, sharpness);
scale1d_calculate_taps (&scale->y_scale1d,
src->height, dest->height, n_taps, a, sharpness, sharpen);
scale->dither = dither;
scale->horiz_resample_func =
(HorizResampleFunc) resample_horiz_double_nv_generic;
scale->tmpdata =
g_malloc (sizeof (double) * scale->dest->width * scale->src->height * 2);
vs_scale_lanczos_NV_double (scale);
scale1d_cleanup (&scale->x_scale1d);
scale1d_cleanup (&scale->y_scale1d);
g_free (scale->tmpdata);
}