1
mirror of https://github.com/mpv-player/mpv synced 2024-11-11 00:15:33 +01:00

vo_opengl: add oversample support for tscale

This is interesting mainly because it's essentially equivalent to the
old smoothmotion algorithm. As such, it is now the default for tscale.
This commit is contained in:
Niklas Haas 2015-03-15 07:11:51 +01:00
parent ac1e31957d
commit 31a5f08f13
2 changed files with 54 additions and 25 deletions

View File

@ -327,6 +327,14 @@ Available video output drivers are:
``scale-param1`` and ``scale-param2``. This filter is very good at
downscaling (see ``scale-down``).
``oversample``
A version of nearest neighbour that (naively) oversamples pixels,
so that pixels overlapping edges get linearly interpolated instead
of rounded. This essentially removes the small imperfections and
judder artifacts caused by nearest-neighbour interpolation, in
exchange for adding some blur. This filter is good at temporal
interpolation, and also known as "smoothmotion" (see ``tscale``).
There are some more filters, but most are not as useful. For a complete
list, pass ``help`` as value, e.g.::
@ -474,7 +482,7 @@ Available video output drivers are:
only used if ``interpolation`` is enabled. The only valid choices
for ``tscale`` are separable convolution filters (use ``tscale=help``
to get a list). The other options (``tscale-param1`` etc.) are
analogous to their ``scale`` counterparts. The default is ``mitchell``.
analogous to their ``scale`` counterparts. The default is ``oversample``.
Note that the maximum supported filter radius is currently 3, and that
using filters with larger radius may introduce isues when pausing or

View File

@ -62,6 +62,10 @@ static const char *const fixed_scale_filters[] = {
"oversample",
NULL
};
static const char *const fixed_tscale_filters[] = {
"oversample",
NULL
};
// must be sorted, and terminated with 0
int filter_sizes[] =
@ -321,7 +325,7 @@ const struct gl_video_opts gl_video_opts_def = {
.fbo_format = GL_RGBA,
.sigmoid_center = 0.75,
.sigmoid_slope = 6.5,
.scalers = { "bilinear", "bilinear", "mitchell" },
.scalers = { "bilinear", "bilinear", "oversample" },
.dscaler = "bilinear",
.scaler_params = {{NAN, NAN}, {NAN, NAN}, {NAN, NAN}},
.scaler_radius = {3, 3, 3},
@ -339,7 +343,7 @@ const struct gl_video_opts gl_video_opts_hq_def = {
.sigmoid_center = 0.75,
.sigmoid_slope = 6.5,
.sigmoid_upscaling = 1,
.scalers = { "spline36", "bilinear", "mitchell" },
.scalers = { "spline36", "bilinear", "oversample" },
.dscaler = "mitchell",
.scaler_params = {{NAN, NAN}, {NAN, NAN}, {NAN, NAN}},
.scaler_radius = {3, 3, 3},
@ -427,7 +431,6 @@ const struct m_sub_options gl_video_conf = {
OPT_REMOVED("cscale-down", "chroma is never downscaled"),
OPT_REMOVED("scale-sep", "this is set automatically whenever sane"),
OPT_REMOVED("indirect", "this is set automatically whenever sane"),
OPT_REMOVED("smoothmotion-threshold", "to be readded as a proper scaler"),
OPT_REPLACED("lscale", "scale"),
OPT_REPLACED("lscale-down", "scale-down"),
@ -441,6 +444,7 @@ const struct m_sub_options gl_video_conf = {
OPT_REPLACED("cantiring", "cscale-antiring"),
OPT_REPLACED("srgb", "target-prim=srgb:target-trc=srgb"),
OPT_REPLACED("smoothmotion", "interpolation"),
OPT_REPLACED("smoothmotion-threshold", "tscale-param1"),
{0}
},
@ -1734,10 +1738,15 @@ static void gl_video_interpolate_frame(struct gl_video *p, int fbo,
// surface_end.
struct scaler *tscale = &p->scalers[2];
reinit_scaler(p, 2, p->opts.scalers[2], 1, tscale_sizes);
assert(tscale->kernel && !tscale->kernel->polar);
int size = ceil(tscale->kernel->size);
assert(size <= TEXUNIT_VIDEO_NUM);
bool oversample = strcmp(tscale->name, "oversample") == 0;
int size;
if (oversample) {
size = 2;
} else {
assert(tscale->kernel && !tscale->kernel->polar);
size = ceil(tscale->kernel->size);
assert(size <= TEXUNIT_VIDEO_NUM);
}
int radius = size/2;
int surface_now = p->surface_now;
@ -1781,22 +1790,31 @@ static void gl_video_interpolate_frame(struct gl_video *p, int fbo,
} else {
int64_t pts_now = p->surfaces[surface_now].pts,
pts_nxt = p->surfaces[surface_nxt].pts;
double fscale = pts_nxt - pts_now;
double fcoord = (t->next_vsync - pts_now) / fscale;
gl_sc_uniform_f(p->sc, "fcoord", fcoord);
MP_STATS(p, "frame-mix");
MP_DBG(p, "inter frame ppts: %lld, pts: %lld, vsync: %lld, mix: %f\n",
(long long)pts_now, (long long)pts_nxt,
(long long)t->next_vsync, fcoord);
double fscale = pts_nxt - pts_now, mix;
if (oversample) {
double vsync_interval = t->next_vsync - t->prev_vsync,
threshold = isnan(tscale->params[0]) ? 0 : tscale->params[0];
mix = (pts_nxt - t->next_vsync) / vsync_interval;
mix = mix <= 0 + threshold ? 0 : mix;
mix = mix >= 1 - threshold ? 1 : mix;
gl_sc_uniform_f(p->sc, "inter_coeff", mix);
GLSL(vec4 color = mix(texture(texture1, texcoord1),
texture(texture0, texcoord0),
inter_coeff);)
} else {
mix = (t->next_vsync - pts_now) / fscale;
gl_sc_uniform_f(p->sc, "fcoord", mix);
pass_sample_separated_gen(p, tscale, 0, 0);
}
for (int i = 0; i < size; i++) {
pass_load_fbotex(p, &p->surfaces[fbosurface_wrap(surface_bse+i)].fbotex,
i, vp_w, vp_h);
}
pass_sample_separated_gen(p, tscale, 0, 0);
MP_STATS(p, "frame-mix");
MP_DBG(p, "inter frame ppts: %lld, pts: %lld, vsync: %lld, mix: %f\n",
(long long)pts_now, (long long)pts_nxt,
(long long)t->next_vsync, mix);
p->is_interpolated = true;
}
pass_draw_to_screen(p, fbo);
@ -2368,7 +2386,7 @@ struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct osd_state *osd
.scalers = {
{ .index = 0, .name = "bilinear" },
{ .index = 1, .name = "bilinear" },
{ .index = 2, .name = "mitchell" },
{ .index = 2, .name = "oversample" },
},
.sc = gl_sc_create(gl, log),
};
@ -2387,8 +2405,10 @@ static const char *handle_scaler_opt(const char *name, bool tscale)
if (kernel && (!tscale || !kernel->polar))
return kernel->name;
for (const char *const *filter = fixed_scale_filters; *filter; filter++) {
if (strcmp(*filter, name) == 0 && !tscale)
for (const char *const *filter = tscale ? fixed_tscale_filters
: fixed_scale_filters;
*filter; filter++) {
if (strcmp(*filter, name) == 0)
return *filter;
}
}
@ -2452,9 +2472,10 @@ static int validate_scaler_opt(struct mp_log *log, const m_option_t *opt,
}
if (r < 1) {
mp_info(log, "Available scalers:\n");
if (!tscale) {
for (const char *const *filter = fixed_scale_filters; *filter; filter++)
mp_info(log, " %s\n", *filter);
for (const char *const *filter = tscale ? fixed_tscale_filters
: fixed_scale_filters;
*filter; filter++) {
mp_info(log, " %s\n", *filter);
}
for (int n = 0; mp_filter_kernels[n].name; n++) {
if (!tscale || !mp_filter_kernels[n].polar)