From cdb25d5a21e2502fef51c2ae7ae387bf990ab73d Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 27 Sep 2014 18:13:14 +0200 Subject: [PATCH] video: change automatic rotation and 3D filter insertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We inserted these filters with fixed parameters, which was ok. But this also didn't change image parameters for the filters down the filter chain and the VO. For example, if rotation by 90° was requested by the file, we would insert a filter and rotate the video, but the VO would still receive image parameters that direct rotation by 90°. This wasn't a problem, but it could become one. Fix this by letting the filters automatically pick up the image params. The image params are reset on application. (We could probably also always try to apply and reset image params in a filter, instead of having special "auto" parameters. This would probably work, and video.c would insert a "rotate=0" filter. But I'm afraid this would be confusing and the current solution is cosmetically slightly nicer.) Unfortunately, the vf_stereo3d.c change turned out a big mess, but once the "internal" filter is fully replaced with libavfilter, most of this can be radically simplified. --- player/video.c | 9 ++--- video/filter/vf_rotate.c | 39 +++++++++++++----- video/filter/vf_stereo3d.c | 83 +++++++++++++++++++++++++++++++++++++- 3 files changed, 114 insertions(+), 17 deletions(-) diff --git a/player/video.c b/player/video.c index 61c7914920..3d308ae955 100644 --- a/player/video.c +++ b/player/video.c @@ -147,9 +147,7 @@ static void filter_reconfig(struct MPContext *mpctx, if (params.rotate && (params.rotate % 90 == 0)) { if (!(mpctx->video_out->driver->caps & VO_CAP_ROTATE90)) { // Try to insert a rotation filter. - char deg[10]; - snprintf(deg, sizeof(deg), "%d", params.rotate); - char *args[] = {"angle", deg, NULL, NULL}; + char *args[] = {"angle", "auto", NULL}; if (try_filter(mpctx, params, "rotate", "autorotate", args) >= 0) { params.rotate = 0; } else { @@ -161,10 +159,9 @@ static void filter_reconfig(struct MPContext *mpctx, if (params.stereo_in != params.stereo_out && params.stereo_in > 0 && params.stereo_out >= 0) { - char *from = MP_STEREO3D_NAME(params.stereo_in); char *to = MP_STEREO3D_NAME(params.stereo_out); - if (from && to) { - char *args[] = {"in", from, "out", to, NULL, NULL}; + if (to) { + char *args[] = {"in", "auto", "out", to, NULL, NULL}; if (try_filter(mpctx, params, "stereo3d", "stereo3d", args) < 0) MP_ERR(mpctx, "Can't insert 3D conversion filter.\n"); } diff --git a/video/filter/vf_rotate.c b/video/filter/vf_rotate.c index 6328e75722..579c3ea24a 100644 --- a/video/filter/vf_rotate.c +++ b/video/filter/vf_rotate.c @@ -32,19 +32,39 @@ struct vf_priv_s { struct vf_lw_opts *lw_opts; }; +static const char *const rot[] = { + "null", + "transpose=clock", + "vflip,hflip", + "transpose=cclock", + "null", // actually set in lavfi_recreate() +}; + +static int lavfi_reconfig(struct vf_instance *vf, + struct mp_image_params *in, + struct mp_image_params *out) +{ + struct vf_priv_s *p = vf_lw_old_priv(vf); + if (p->angle == 4) { // "auto" + int r = in->rotate; + if (r < 0 || (r % 90) != 0) { + MP_ERR(vf, "Can't apply rotation of %d degrees.\n", r); + return -1; + } + vf_lw_update_graph(vf, NULL, "%s", rot[(r / 90) % 360]); + out->rotate = 0; + } + return 0; +} + static int vf_open(vf_instance_t *vf) { struct vf_priv_s *p = vf->priv; - static const char *const rot[] = { - "null", - "transpose=clock", - "vflip,hflip", - "transpose=cclock", - }; - - if (vf_lw_set_graph(vf, p->lw_opts, NULL, "%s", rot[p->angle]) >= 0) + if (vf_lw_set_graph(vf, p->lw_opts, NULL, "%s", rot[p->angle]) >= 0) { + vf_lw_set_reconfig_cb(vf, lavfi_reconfig); return 1; + } MP_FATAL(vf, "Requires libavfilter.\n"); return 1; @@ -61,7 +81,8 @@ const vf_info_t vf_info_rotate = { ({"0", 0}, {"90", 1}, {"180", 2}, - {"270", 3})), + {"270", 3}, + {"auto", 4})), OPT_SUBSTRUCT("", lw_opts, vf_lw_conf, 0), {0} }, diff --git a/video/filter/vf_stereo3d.c b/video/filter/vf_stereo3d.c index fcf583eef4..77d041af79 100644 --- a/video/filter/vf_stereo3d.c +++ b/video/filter/vf_stereo3d.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -64,6 +65,7 @@ typedef enum stereo_code { ABOVE_BELOW_2_RL, //above-below with half height resolution INTERLEAVE_ROWS_LR, //row-interleave (left eye has top row) INTERLEAVE_ROWS_RL, //row-interleave (right eye has top row) + STEREO_AUTO, //use video metadata info (for input) STEREO_CODE_COUNT //no value set - TODO: needs autodetection } stereo_code; @@ -132,6 +134,7 @@ static const int ana_coeff[][3][6] = { struct vf_priv_s { component in; component out; + bool auto_in; int ana_matrix[3][6]; unsigned int width; unsigned int height; @@ -142,6 +145,8 @@ struct vf_priv_s { {ANAGLYPH_RC_DUBOIS} }; +static bool handle_auto_in(struct vf_instance *vf); + //==functions==// static inline uint8_t ana_convert(int coeff[6], uint8_t left[3], uint8_t right[3]) { @@ -171,6 +176,9 @@ static int config(struct vf_instance *vf, int width, int height, int d_width, vf->priv->in.row_left = 0; vf->priv->in.row_right = 0; + if (vf->priv->auto_in && !handle_auto_in(vf)) + return 0; + //check input format switch (vf->priv->in.fmt) { case SIDE_BY_SIDE_2_LR: @@ -447,6 +455,8 @@ const struct m_opt_choice_alternatives stereo_code_names[] = { {"interleave_rows_right_first", INTERLEAVE_ROWS_RL}, // convenience alias for MP_STEREO3D_MONO {"mono", MONO_L}, + // for filter auto-insertion + {"auto", STEREO_AUTO}, { NULL, 0} }; @@ -461,18 +471,87 @@ static const char *rev_map_name(int val) return NULL; } +// Extremely stupid; can be dropped when the internal filter is dropped, +// and OPT_VID_STEREO_MODE() can be used instead. +static int opt_to_stereo3dmode(int val) +{ + // Find x for rev_map_name(val) == MP_STEREO3D_NAME(x) + const char *name = rev_map_name(val); + for (int n = 0; n < MP_STEREO3D_COUNT; n++) { + const char *o = MP_STEREO3D_NAME(val); + if (name && o && strcmp(o, name) == 0) + return n; + } + return MP_STEREO3D_INVALID; +} +static int stereo3dmode_to_opt(int val) +{ + // Find x for rev_map_name(x) == MP_STEREO3D_NAME(val) + const char *name = MP_STEREO3D_NAME(val); + for (int n = 0; stereo_code_names[n].name; n++) { + if (name && strcmp(stereo_code_names[n].name, name) == 0) + return stereo_code_names[n].value; + } + return -1; +} + +static bool handle_auto_in(struct vf_instance *vf) +{ + if (vf->priv->auto_in) { + int inv = stereo3dmode_to_opt(vf->fmt_in.stereo_in); + if (inv < 0) { + MP_ERR(vf, "Unknown/unsupported 3D mode.\n"); + return false; + } + vf->priv->in.fmt = inv; + vf->fmt_out.stereo_in = vf->fmt_out.stereo_out = + opt_to_stereo3dmode(vf->priv->out.fmt); + } + return true; +} + +static int lavfi_reconfig(struct vf_instance *vf, + struct mp_image_params *in, + struct mp_image_params *out) +{ + struct vf_priv_s *p = vf_lw_old_priv(vf); + if (p->auto_in) { + const char *inf = MP_STEREO3D_NAME(in->stereo_in); + if (!inf) { + MP_ERR(vf, "Unknown/unsupported 3D mode.\n"); + return -1; + } + vf_lw_update_graph(vf, "stereo3d", "%s:%s", + inf, rev_map_name(p->out.fmt)); + out->stereo_in = out->stereo_out = opt_to_stereo3dmode(p->out.fmt); + } + return 0; +} + static int vf_open(vf_instance_t *vf) { vf->config = config; vf->filter = filter; vf->query_format = query_format; + if (vf->priv->out.fmt == STEREO_AUTO) { + MP_FATAL(vf, "No autodetection for stereo output.\n"); + return 0; + } + if (vf->priv->in.fmt == STEREO_AUTO) + vf->priv->auto_in = 1; + + if (vf->priv->in.fmt == STEREO_AUTO && + vf_lw_set_graph(vf, vf->priv->lw_opts, NULL, "null") >= 0) + { + vf_lw_set_reconfig_cb(vf, lavfi_reconfig); + return 1; + } + if (vf_lw_set_graph(vf, vf->priv->lw_opts, "stereo3d", "%s:%s", rev_map_name(vf->priv->in.fmt), rev_map_name(vf->priv->out.fmt)) >= 0) - { return 1; - } return 1; }