summaryrefslogtreecommitdiffstats
path: root/filters
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-10-21 01:29:48 +0200
committerwm4 <wm4@nowhere>2019-10-21 01:38:25 +0200
commit5dba244c226383f9f3b15b07dfa5133ad08b6497 (patch)
tree3b6e46e9ef3350670f32a56140322980e3b37954 /filters
parent8a4e9d5c180157684546db4c1235d8c958172ca9 (diff)
downloadmpv-5dba244c226383f9f3b15b07dfa5133ad08b6497.tar.bz2
mpv-5dba244c226383f9f3b15b07dfa5133ad08b6497.tar.xz
filters: extend vf_format so that it can convert color parameters
Form some reason (and because of my fault), vf_format converts image formats, but nothing else. For example, setting the "colormatrix" sub-parameter would not convert it to the new value, but instead overwrite the metadata (basically "reinterpreting" the image data without changing it). Make the historical mistake worse, and go all the way and extend it such that it can perform a conversion. For compatibility reasons, this needs to be requested explicitly. (Maybe this would deserve a separate filter to begin with, but things are messed up anyway. Feel free to suggest an elegant and simple solution.) This demonstrates how zimg can properly perform some conversions which swscale cannot (see examples added to vf.rst). Stupidly this requires 2 code paths, one for conversion, and one for overriding the parameters. Due to the filter bullshit (what was I thinking), this requires quite some acrobatics that would not be necessary without these abstractions. On the other hand, it'd definitely be more of a mess without it. Oh whatever.
Diffstat (limited to 'filters')
-rw-r--r--filters/f_autoconvert.c45
-rw-r--r--filters/f_autoconvert.h9
-rw-r--r--filters/f_swscale.c13
-rw-r--r--filters/f_swscale.h5
4 files changed, 69 insertions, 3 deletions
diff --git a/filters/f_autoconvert.c b/filters/f_autoconvert.c
index 065092ac64..20c083de54 100644
--- a/filters/f_autoconvert.c
+++ b/filters/f_autoconvert.c
@@ -27,6 +27,8 @@ struct priv {
int *imgfmts;
int *subfmts;
int num_imgfmts;
+ struct mp_image_params imgparams;
+ bool imgparams_set;
// Enable special conversion for the final stage before the VO.
bool vo_convert;
@@ -73,6 +75,7 @@ void mp_autoconvert_clear(struct mp_autoconvert *c)
struct priv *p = c->f->priv;
p->num_imgfmts = 0;
+ p->imgparams_set = false;
p->num_afmts = 0;
p->num_srates = 0;
p->chmaps = (struct mp_chmap_sel){0};
@@ -93,6 +96,23 @@ void mp_autoconvert_add_imgfmt(struct mp_autoconvert *c, int imgfmt, int subfmt)
p->force_update = true;
}
+void mp_autoconvert_set_target_image_params(struct mp_autoconvert *c,
+ struct mp_image_params *par)
+{
+ struct priv *p = c->f->priv;
+
+ if (p->imgparams_set && mp_image_params_equal(&p->imgparams, par) &&
+ p->num_imgfmts == 1 && p->imgfmts[0] == par->imgfmt &&
+ p->subfmts[0] == par->hw_subfmt)
+ return;
+
+ p->imgparams = *par;
+ p->imgparams_set = true;
+
+ p->num_imgfmts = 0;
+ mp_autoconvert_add_imgfmt(c, par->imgfmt, par->hw_subfmt);
+}
+
void mp_autoconvert_add_all_sw_imgfmts(struct mp_autoconvert *c)
{
for (int n = IMGFMT_START; n < IMGFMT_END; n++) {
@@ -185,8 +205,13 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
bool samesubffmt = img->params.hw_subfmt == p->subfmts[n];
if (samefmt && !samesubffmt)
different_subfmt = true;
- if (samefmt && (samesubffmt || !p->subfmts[n]))
+ if (samefmt && (samesubffmt || !p->subfmts[n])) {
+ if (p->imgparams_set) {
+ if (!mp_image_params_equal(&p->imgparams, &img->params))
+ break;
+ }
return true;
+ }
}
struct mp_stream_info *info = mp_filter_find_stream_info(f);
@@ -200,6 +225,8 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
// 2: sw->hw upload
struct mp_filter *filters[3] = {0};
bool need_sws = true;
+ bool force_sws_params = false;
+ struct mp_image_params imgpar = img->params;
int *fmts = p->imgfmts;
int num_fmts = p->num_imgfmts;
@@ -259,9 +286,21 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
if (hwd) {
filters[0] = hwd->f;
src_fmt = res_fmt;
+ // Downloading from hw will obviously change the parameters. We
+ // stupidly don't know the result parameters, but if it's
+ // sufficiently sane, it will only do the following.
+ imgpar.imgfmt = src_fmt;
+ imgpar.hw_subfmt = 0;
+ // Try to compensate for in-sane cases.
+ mp_image_params_guess_csp(&imgpar);
}
}
+ if (p->imgparams_set) {
+ force_sws_params |= !mp_image_params_equal(&imgpar, &p->imgparams);
+ need_sws |= force_sws_params;
+ }
+
if (need_sws) {
// Create a new conversion filter.
struct mp_sws_filter *sws = mp_sws_filter_create(conv);
@@ -277,11 +316,13 @@ static bool build_image_converter(struct mp_autoconvert *c, struct mp_log *log,
goto fail;
}
- if (out == src_fmt) {
+ if (out == src_fmt && !force_sws_params) {
// Can happen if hwupload goes to same format.
talloc_free(sws->f);
} else {
sws->out_format = out;
+ sws->out_params = p->imgparams;
+ sws->use_out_params = force_sws_params;
mp_info(log, "Converting %s -> %s\n", mp_imgfmt_to_name(src_fmt),
mp_imgfmt_to_name(sws->out_format));
filters[1] = sws->f;
diff --git a/filters/f_autoconvert.h b/filters/f_autoconvert.h
index e8c5a44134..ae08fd4e51 100644
--- a/filters/f_autoconvert.h
+++ b/filters/f_autoconvert.h
@@ -3,6 +3,7 @@
#include "filter.h"
struct mp_image;
+struct mp_image_params;
// A filter which automatically creates and uses a conversion filter based on
// the filter settings, or passes through data unchanged if no conversion is
@@ -22,6 +23,14 @@ struct mp_autoconvert {
// (to free this, free the filter itself, mp_autoconvert.f)
struct mp_autoconvert *mp_autoconvert_create(struct mp_filter *parent);
+// Require that output frames have the following params set.
+// This implicitly clears the image format list, and calls
+// mp_autoconvert_add_imgfmt() with the values in *p.
+// Idempotent on subsequent calls (no reinit forced if parameters don't change).
+// Mixing this with other format-altering calls has undefined effects.
+void mp_autoconvert_set_target_image_params(struct mp_autoconvert *c,
+ struct mp_image_params *p);
+
// Add the imgfmt as allowed video image format, and error on non-video frames.
// Each call adds to the list of allowed formats. Before the first call, all
// formats are allowed (even non-video).
diff --git a/filters/f_swscale.c b/filters/f_swscale.c
index 07198b1377..1ff25ab909 100644
--- a/filters/f_swscale.c
+++ b/filters/f_swscale.c
@@ -88,9 +88,18 @@ static void process(struct mp_filter *f)
}
struct mp_image *src = frame.data;
+
int dstfmt = s->out_format ? s->out_format : src->imgfmt;
+ int w = src->w;
+ int h = src->h;
+
+ if (s->use_out_params) {
+ w = s->out_params.w;
+ h = s->out_params.h;
+ dstfmt = s->out_params.imgfmt;
+ }
- struct mp_image *dst = mp_image_pool_get(s->pool, dstfmt, src->w, src->h);
+ struct mp_image *dst = mp_image_pool_get(s->pool, dstfmt, w, h);
if (!dst)
goto error;
@@ -102,6 +111,8 @@ static void process(struct mp_filter *f)
{
dst->params.color.levels = MP_CSP_LEVELS_TV;
}
+ if (s->use_out_params)
+ dst->params = s->out_params;
mp_image_params_guess_csp(&dst->params);
bool ok = mp_sws_scale(s->sws, dst, src) >= 0;
diff --git a/filters/f_swscale.h b/filters/f_swscale.h
index fd5aa11f5e..6e26aef1ac 100644
--- a/filters/f_swscale.h
+++ b/filters/f_swscale.h
@@ -2,10 +2,15 @@
#include <stdbool.h>
+#include "video/mp_image.h"
+
struct mp_sws_filter {
struct mp_filter *f;
// Desired output imgfmt. If 0, uses the input format.
int out_format;
+ // If set, force all image params; ignores out_format.
+ bool use_out_params;
+ struct mp_image_params out_params;
// private state
struct mp_sws_context *sws;
struct mp_image_pool *pool;