mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-01 13:49:58 +00:00
video: add generic resampler
Add an object that can generate a set of resample filter coefficients.
This commit is contained in:
parent
549bdd4ece
commit
c9c9e8158d
3 changed files with 468 additions and 0 deletions
|
@ -39,6 +39,7 @@ libgstvideo_@GST_API_VERSION@_la_SOURCES = \
|
|||
gstvideodecoder.c \
|
||||
gstvideoencoder.c \
|
||||
gstvideoutils.c \
|
||||
resampler.c \
|
||||
video-blend.c \
|
||||
video-overlay-composition.c
|
||||
|
||||
|
@ -67,6 +68,7 @@ libgstvideo_@GST_API_VERSION@include_HEADERS = \
|
|||
gstvideodecoder.h \
|
||||
gstvideoencoder.h \
|
||||
gstvideoutils.h \
|
||||
resampler.h \
|
||||
video-blend.h \
|
||||
video-overlay-composition.h
|
||||
|
||||
|
|
361
gst-libs/gst/video/resampler.c
Normal file
361
gst-libs/gst/video/resampler.c
Normal file
|
@ -0,0 +1,361 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2014> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "resampler.h"
|
||||
|
||||
typedef struct _ResamplerParams ResamplerParams;
|
||||
|
||||
struct _ResamplerParams
|
||||
{
|
||||
GstResamplerMethod method;
|
||||
GstResamplerFlags flags;
|
||||
|
||||
gdouble shift;
|
||||
|
||||
gdouble (*get_tap) (ResamplerParams * params, gint l, gint xi, gdouble x);
|
||||
|
||||
/* used by lanczos */
|
||||
gdouble ex, fx, dx;
|
||||
/* extra params */
|
||||
gdouble envelope;
|
||||
gdouble sharpness;
|
||||
gdouble sharpen;
|
||||
|
||||
GstResampler *resampler;
|
||||
};
|
||||
|
||||
static double
|
||||
sinc (double x)
|
||||
{
|
||||
if (x == 0)
|
||||
return 1;
|
||||
|
||||
return sin (G_PI * x) / (G_PI * x);
|
||||
}
|
||||
|
||||
static double
|
||||
envelope (double x)
|
||||
{
|
||||
if (x <= -1 || x >= 1)
|
||||
return 0;
|
||||
return sinc (x);
|
||||
}
|
||||
|
||||
static gdouble
|
||||
get_nearest_tap (ResamplerParams * params, gint l, gint xi, gdouble x)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
static gdouble
|
||||
get_linear_tap (ResamplerParams * params, gint l, gint xi, gdouble x)
|
||||
{
|
||||
gdouble n_taps;
|
||||
gdouble res, a;
|
||||
gint xl = xi + l;
|
||||
|
||||
n_taps = (params->resampler->max_taps + 1) / 2;
|
||||
|
||||
a = fabs (x - xl);
|
||||
|
||||
if (a < n_taps)
|
||||
res = (n_taps - a) / (gdouble) n_taps;
|
||||
else
|
||||
res = 0.0;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gdouble
|
||||
bicubic (gdouble s)
|
||||
{
|
||||
s = fabs (s);
|
||||
|
||||
if (s <= 1.0)
|
||||
return 3.0 * (s * s * s) / 2.0 - 5.0 * (s * s) / 2.0 + 1.0;
|
||||
else if (s <= 2.0)
|
||||
return -1.0 * (s * s * s) / 2.0 + 5.0 * (s * s) / 2.0 - 4.0 * s + 2.0;
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static gdouble
|
||||
get_bicubic_tap (ResamplerParams * params, gint l, gint xi, gdouble x)
|
||||
{
|
||||
gdouble a, res;
|
||||
|
||||
a = x - (xi + 1);
|
||||
|
||||
if (l == 0)
|
||||
res = bicubic (1.0 + a);
|
||||
else if (l == 1)
|
||||
res = bicubic (a);
|
||||
else if (l == 2)
|
||||
res = bicubic (1.0 - a);
|
||||
else
|
||||
res = bicubic (2.0 - a);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static gdouble
|
||||
get_sinc_tap (ResamplerParams * params, gint l, gint xi, gdouble x)
|
||||
{
|
||||
gint xl = xi + l;
|
||||
return sinc (x - xl);
|
||||
}
|
||||
|
||||
static gdouble
|
||||
get_lanczos_tap (ResamplerParams * params, gint l, gint xi, gdouble x)
|
||||
{
|
||||
gint xl = xi + l;
|
||||
gdouble env = envelope ((x - xl) * params->ex);
|
||||
return (sinc ((x - xl) * params->fx) - params->sharpen) * env;
|
||||
}
|
||||
|
||||
static void
|
||||
resampler_calculate_taps (ResamplerParams * params)
|
||||
{
|
||||
GstResampler *resampler = params->resampler;
|
||||
gint j;
|
||||
guint *offset, *n_taps, *phase;
|
||||
gint tap_offs;
|
||||
gint max_taps;
|
||||
gint in_size, out_size;
|
||||
gdouble shift;
|
||||
gdouble corr;
|
||||
|
||||
in_size = resampler->in_size;
|
||||
out_size = resampler->out_size;
|
||||
|
||||
max_taps = resampler->max_taps;
|
||||
tap_offs = (max_taps - 1) / 2;
|
||||
corr = (max_taps == 1 ? 0.5 : 0.0);
|
||||
|
||||
shift = params->shift;
|
||||
|
||||
resampler->taps = g_malloc (sizeof (gdouble) * max_taps * out_size);
|
||||
n_taps = resampler->n_taps = g_malloc (sizeof (guint) * out_size);
|
||||
offset = resampler->offset = g_malloc (sizeof (guint) * out_size);
|
||||
phase = resampler->phase = g_malloc (sizeof (guint) * out_size);
|
||||
|
||||
for (j = 0; j < out_size; j++) {
|
||||
gdouble x;
|
||||
gint xi;
|
||||
gint l;
|
||||
gdouble weight;
|
||||
gdouble *taps;
|
||||
|
||||
/* x is the source pixel to use, can be fractional */
|
||||
x = shift + (in_size * j) / (gdouble) out_size;
|
||||
x = CLAMP (x, 0, in_size - 1);
|
||||
/* this is the first source pixel to use */
|
||||
xi = floor (x + corr) - tap_offs;
|
||||
|
||||
offset[j] = xi;
|
||||
phase[j] = j;
|
||||
n_taps[j] = max_taps;
|
||||
weight = 0;
|
||||
taps = resampler->taps + j * max_taps;
|
||||
|
||||
for (l = 0; l < max_taps; l++) {
|
||||
taps[l] = params->get_tap (params, l, xi, x);
|
||||
weight += taps[l];
|
||||
}
|
||||
|
||||
for (l = 0; l < max_taps; l++)
|
||||
taps[l] /= weight;
|
||||
|
||||
if (xi < 0) {
|
||||
gint sh = -xi;
|
||||
|
||||
for (l = 0; l < sh; l++) {
|
||||
taps[sh] += taps[l];
|
||||
}
|
||||
for (l = 0; l < max_taps - sh; l++) {
|
||||
taps[l] = taps[sh + l];
|
||||
}
|
||||
for (; l < max_taps; l++) {
|
||||
taps[l] = 0;
|
||||
}
|
||||
offset[j] += sh;
|
||||
}
|
||||
if (xi > in_size - max_taps) {
|
||||
gint sh = xi - (in_size - max_taps);
|
||||
|
||||
for (l = 0; l < sh; l++) {
|
||||
taps[max_taps - sh - 1] += taps[max_taps - sh + l];
|
||||
}
|
||||
for (l = 0; l < max_taps - sh; l++) {
|
||||
taps[max_taps - 1 - l] = taps[max_taps - 1 - sh - l];
|
||||
}
|
||||
for (l = 0; l < sh; l++) {
|
||||
taps[l] = 0;
|
||||
}
|
||||
offset[j] -= sh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_resampler_new:
|
||||
* @resampler: a #GstResampler
|
||||
* @method: a #GstResamplerMethod
|
||||
* @flags: #GstResamplerFlags
|
||||
* @n_phases: number of phases to use
|
||||
* @n_taps: number of taps to use
|
||||
* @in_size: number of source elements
|
||||
* @out_size: number of destination elements
|
||||
* @options: extra options
|
||||
*
|
||||
* Make a new resampler. @in_size source elements will
|
||||
* be resampled to @out_size destination elements.
|
||||
*
|
||||
* @n_taps specifies the amount of elements to use from the source for one output
|
||||
* element. If n_taps is 0, this function chooses a good value automatically based
|
||||
* on the @method and @in_size/@out_size.
|
||||
*
|
||||
* Returns: %TRUE on success
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
gboolean
|
||||
gst_resampler_init (GstResampler * resampler,
|
||||
GstResamplerMethod method, GstResamplerFlags flags,
|
||||
guint n_phases, guint n_taps, gdouble shift, guint in_size, guint out_size,
|
||||
GstStructure * options)
|
||||
{
|
||||
ResamplerParams params;
|
||||
|
||||
g_return_val_if_fail (in_size != 0, FALSE);
|
||||
g_return_val_if_fail (out_size != 0, FALSE);
|
||||
g_return_val_if_fail (n_phases == out_size, FALSE);
|
||||
|
||||
resampler->in_size = in_size;
|
||||
resampler->out_size = out_size;
|
||||
resampler->max_taps = n_taps;
|
||||
resampler->n_phases = n_phases;
|
||||
|
||||
params.method = method;
|
||||
params.flags = flags;
|
||||
params.shift = shift;
|
||||
params.resampler = resampler;
|
||||
|
||||
GST_DEBUG ("%d %u %u->%u", method, n_taps, in_size, out_size);
|
||||
|
||||
switch (method) {
|
||||
case GST_RESAMPLER_METHOD_NEAREST:
|
||||
params.get_tap = get_nearest_tap;
|
||||
if (n_taps == 0)
|
||||
n_taps = 1;
|
||||
break;
|
||||
case GST_RESAMPLER_METHOD_LINEAR:
|
||||
params.get_tap = get_linear_tap;
|
||||
if (n_taps == 0)
|
||||
n_taps = 2;
|
||||
break;
|
||||
case GST_RESAMPLER_METHOD_BICUBIC:
|
||||
n_taps = 4;
|
||||
params.get_tap = get_bicubic_tap;
|
||||
break;
|
||||
case GST_RESAMPLER_METHOD_SINC:
|
||||
params.get_tap = get_sinc_tap;
|
||||
if (n_taps == 0)
|
||||
n_taps = 4;
|
||||
break;
|
||||
case GST_RESAMPLER_METHOD_LANCZOS:
|
||||
{
|
||||
gdouble resample_inc = in_size / (gdouble) out_size;
|
||||
|
||||
params.envelope = 2.0;
|
||||
params.sharpness = 1.0;
|
||||
params.sharpen = 0.0;
|
||||
|
||||
if (resample_inc > 1.0) {
|
||||
params.fx = (1.0 / resample_inc) * params.sharpness;
|
||||
} else {
|
||||
params.fx = (1.0) * params.sharpness;
|
||||
}
|
||||
params.ex = params.fx / params.envelope;
|
||||
params.dx = ceil (params.envelope / params.fx);
|
||||
|
||||
if (n_taps == 0)
|
||||
n_taps = 2 * params.dx;
|
||||
params.get_tap = get_lanczos_tap;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
resampler_calculate_taps (¶ms);
|
||||
|
||||
#if 0
|
||||
{
|
||||
gint i, max_taps;
|
||||
|
||||
max_taps = resampler->max_taps;
|
||||
|
||||
for (i = 0; i < out_size; i++) {
|
||||
gint j, o, n_taps;
|
||||
gdouble sum;
|
||||
|
||||
o = resampler->offsets[i];
|
||||
n_taps = resampler->n_taps[i];
|
||||
|
||||
printf ("%u: \t%d ", i, o);
|
||||
sum = 0;
|
||||
for (j = 0; j < n_taps; j++) {
|
||||
gdouble tap;
|
||||
tap = resampler->taps[i * max_taps + j];
|
||||
printf ("\t%f ", tap);
|
||||
sum += tap;
|
||||
}
|
||||
printf ("\t: sum %f\n", sum);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_resampler_clear:
|
||||
* @resampler: a #GstResampler
|
||||
*
|
||||
* Clear a previously initialized #GstResampler @resampler.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
void
|
||||
gst_resampler_clear (GstResampler * resampler)
|
||||
{
|
||||
g_return_if_fail (resampler != NULL);
|
||||
|
||||
g_free (resampler->phase);
|
||||
g_free (resampler->offset);
|
||||
g_free (resampler->n_taps);
|
||||
g_free (resampler->taps);
|
||||
}
|
105
gst-libs/gst/video/resampler.h
Normal file
105
gst-libs/gst/video/resampler.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2014> Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_RESAMPLER_H__
|
||||
#define __GST_RESAMPLER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstResampler GstResampler;
|
||||
|
||||
/**
|
||||
* GstResamplerMethod:
|
||||
* @GST_RESAMPLER_METHOD_NEAREST: Duplicates the samples when
|
||||
* upsampling and drops when downsampling
|
||||
* @GST_RESAMPLER_METHOD_LINEAR: Uses linear interpolation to reconstruct
|
||||
* missing samples and averaging to downsample
|
||||
* @GST_RESAMPLER_METHOD_BICUBIC: Uses bicubic interpolation
|
||||
* @GST_RESAMPLER_METHOD_SINC: Uses sinc interpolation
|
||||
* @GST_RESAMPLER_METHOD_LANCZOS: Uses lanczos interpolation
|
||||
*
|
||||
* Different subsampling and upsampling methods
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
typedef enum {
|
||||
GST_RESAMPLER_METHOD_NEAREST,
|
||||
GST_RESAMPLER_METHOD_LINEAR,
|
||||
GST_RESAMPLER_METHOD_BICUBIC,
|
||||
GST_RESAMPLER_METHOD_SINC,
|
||||
GST_RESAMPLER_METHOD_LANCZOS,
|
||||
} GstResamplerMethod;
|
||||
|
||||
/**
|
||||
* GstResamplerFlags:
|
||||
* @GST_RESAMPLER_FLAG_NONE: no flags
|
||||
*
|
||||
* Different resampler flags.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
typedef enum {
|
||||
GST_RESAMPLER_FLAG_NONE = (0),
|
||||
} GstResamplerFlags;
|
||||
|
||||
/**
|
||||
* GstResampler:
|
||||
* @in_size: the input size
|
||||
* @out_size: the output size
|
||||
* @max_taps: the maximum number of taps
|
||||
* @n_phases: the number of phases
|
||||
* @offset: array with the source offset for each output element
|
||||
* @phase: array with the phase to use for each output element
|
||||
* @n_taps: array with new number of taps for each phase
|
||||
* @taps: the taps for all phases
|
||||
*
|
||||
* A structure holding resampler information.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
struct _GstResampler
|
||||
{
|
||||
gint in_size;
|
||||
gint out_size;
|
||||
guint max_taps;
|
||||
guint n_phases;
|
||||
guint *offset;
|
||||
guint *phase;
|
||||
guint *n_taps;
|
||||
gdouble *taps;
|
||||
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
|
||||
gboolean gst_resampler_init (GstResampler *resampler,
|
||||
GstResamplerMethod method,
|
||||
GstResamplerFlags flags,
|
||||
guint n_phases, guint n_taps,
|
||||
gdouble shift,
|
||||
guint in_size, guint out_size,
|
||||
GstStructure *options);
|
||||
|
||||
void gst_resampler_clear (GstResampler *resampler);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RESAMPLER_H__ */
|
Loading…
Reference in a new issue