summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2015-03-15 07:11:51 +0100
committerNiklas Haas <git@nand.wakku.to>2015-03-15 18:01:39 +0100
commit31a5f08f135535e5c284d3994d2fad17ce8e2e53 (patch)
tree2534d56b72c809866bc0b56c5e5e987e788ff077
parentac1e31957d00d06071757fd271c09a045cd6f39a (diff)
downloadmpv-31a5f08f135535e5c284d3994d2fad17ce8e2e53.tar.bz2
mpv-31a5f08f135535e5c284d3994d2fad17ce8e2e53.tar.xz
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.
-rw-r--r--DOCS/man/vo.rst10
-rw-r--r--video/out/gl_video.c69
2 files changed, 54 insertions, 25 deletions
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst
index b59f97b6a9..f15ae9a3fb 100644
--- a/DOCS/man/vo.rst
+++ b/DOCS/man/vo.rst
@@ -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
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index 1b75b680c3..17dd121709 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -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)