summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2016-07-05 21:10:26 +0200
committerwm4 <wm4@nowhere>2016-07-05 21:10:26 +0200
commitd72bcc8041f1a5cc5ea92a9579aa2b07fd8b3b59 (patch)
tree3839d81a2319f6a6cf88b8d35df08fea9d5214d6
parent329a7147d003f70a017ad6560a1b671b66ae2b62 (diff)
downloadmpv-d72bcc8041f1a5cc5ea92a9579aa2b07fd8b3b59.tar.bz2
mpv-d72bcc8041f1a5cc5ea92a9579aa2b07fd8b3b59.tar.xz
player: rewrite deinterlace filter auto-insertion
Instead of using the "vf" command code (which changes filters at runtime on user input), use the general filter-insertion code. The latter was added later, and is more suitable for automatically inserted filters. The old code failed in particular when using watch-later saving, which stored the filter list in the resume config file. If a user changed the hardware decoding mode via command line, the stored filter chain was out of date and could cause failure due to not working with hardware or software decoding mode. Storing the deinterlace filter in the filter list was unavoidable, because it was part of the user state. (The new code only edits the actually instantiated filters.)
-rw-r--r--player/command.c82
-rw-r--r--player/command.h3
-rw-r--r--player/core.h2
-rw-r--r--player/video.c104
4 files changed, 84 insertions, 107 deletions
diff --git a/player/command.c b/player/command.c
index 85f453e0ef..425f040ff2 100644
--- a/player/command.c
+++ b/player/command.c
@@ -2258,88 +2258,6 @@ static int mp_property_detected_hwdec(void *ctx, struct m_property *prop,
return M_PROPERTY_NOT_IMPLEMENTED;
}
-#define VF_DEINTERLACE_LABEL "deinterlace"
-
-static bool probe_deint_filter(struct MPContext *mpctx, const char *filt)
-{
- char filter[80];
- // add a label so that removing the filter is easier
- snprintf(filter, sizeof(filter), "@%s:%s", VF_DEINTERLACE_LABEL, filt);
- return edit_filters(mpctx, mp_null_log, STREAM_VIDEO, "pre", filter) >= 0;
-}
-
-static bool check_output_format(struct MPContext *mpctx, int imgfmt)
-{
- struct vo_chain *vo_c = mpctx->vo_chain;
- if (!vo_c)
- return false;
- return vo_c->vf->allowed_output_formats[imgfmt - IMGFMT_START];
-}
-
-static int probe_deint_filters(struct MPContext *mpctx)
-{
- if (check_output_format(mpctx, IMGFMT_VDPAU)) {
- char filter[80] = "vdpaupp:deint=yes";
- int pref = 0;
- vo_control(mpctx->video_out, VOCTRL_GET_PREF_DEINT, &pref);
- pref = pref < 0 ? -pref : pref;
- if (pref > 0 && pref <= 4) {
- const char *types[] =
- {"", "first-field", "bob", "temporal", "temporal-spatial"};
- mp_snprintf_cat(filter, sizeof(filter), ":deint-mode=%s",
- types[pref]);
- }
-
- probe_deint_filter(mpctx, filter);
- return 0;
- }
- if (check_output_format(mpctx, IMGFMT_VAAPI) &&
- probe_deint_filter(mpctx, "vavpp"))
- return 0;
- if ((check_output_format(mpctx, IMGFMT_D3D11VA) ||
- check_output_format(mpctx, IMGFMT_D3D11NV12)) &&
- probe_deint_filter(mpctx, "d3d11vpp"))
- return 0;
- if (probe_deint_filter(mpctx, "yadif"))
- return 0;
- return -1;
-}
-
-static int get_deinterlacing(struct MPContext *mpctx)
-{
- struct vo_chain *vo_c = mpctx->vo_chain;
- int enabled = 0;
- if (video_vf_vo_control(vo_c, VFCTRL_GET_DEINTERLACE, &enabled) != CONTROL_OK)
- enabled = -1;
- if (enabled < 0) {
- // vf_lavfi doesn't support VFCTRL_GET_DEINTERLACE
- if (vf_find_by_label(vo_c->vf, VF_DEINTERLACE_LABEL))
- enabled = 1;
- }
- return enabled;
-}
-
-void remove_deint_filter(struct MPContext *mpctx)
-{
- edit_filters(mpctx, mp_null_log, STREAM_VIDEO, "del", "@" VF_DEINTERLACE_LABEL);
-}
-
-void set_deinterlacing(struct MPContext *mpctx, bool enable)
-{
- struct vo_chain *vo_c = mpctx->vo_chain;
- if (vf_find_by_label(vo_c->vf, VF_DEINTERLACE_LABEL)) {
- if (!enable)
- remove_deint_filter(mpctx);
- } else {
- if ((get_deinterlacing(mpctx) > 0) != enable) {
- int arg = enable;
- if (video_vf_vo_control(vo_c, VFCTRL_SET_DEINTERLACE, &arg) != CONTROL_OK)
- probe_deint_filters(mpctx);
- }
- }
- mpctx->opts->deinterlace = get_deinterlacing(mpctx) > 0;
-}
-
static int mp_property_deinterlace(void *ctx, struct m_property *prop,
int action, void *arg)
{
diff --git a/player/command.h b/player/command.h
index 7c3994c39e..a233319ad7 100644
--- a/player/command.h
+++ b/player/command.h
@@ -59,7 +59,4 @@ void mp_hook_run(struct MPContext *mpctx, char *client, char *type);
void handle_ab_loop(struct MPContext *mpctx);
-void remove_deint_filter(struct MPContext *mpctx);
-void set_deinterlacing(struct MPContext *mpctx, bool enable);
-
#endif /* MPLAYER_COMMAND_H */
diff --git a/player/core.h b/player/core.h
index 61360b726e..8afcfbe64d 100644
--- a/player/core.h
+++ b/player/core.h
@@ -555,5 +555,7 @@ void uninit_video_out(struct MPContext *mpctx);
void uninit_video_chain(struct MPContext *mpctx);
double calc_average_frame_duration(struct MPContext *mpctx);
int init_video_decoder(struct MPContext *mpctx, struct track *track);
+int get_deinterlacing(struct MPContext *mpctx);
+void set_deinterlacing(struct MPContext *mpctx, bool enable);
#endif /* MPLAYER_MP_CORE_H */
diff --git a/player/video.c b/player/video.c
index 1d2dc29fc6..d0d0b60ed5 100644
--- a/player/video.c
+++ b/player/video.c
@@ -49,6 +49,8 @@
#include "command.h"
#include "screenshot.h"
+#define VF_DEINTERLACE_LABEL "deinterlace"
+
enum {
// update_video() - code also uses: <0 error, 0 eof, >0 progress
VD_ERROR = -1,
@@ -153,8 +155,37 @@ static int try_filter(struct vo_chain *vo_c, char *name, char *label, char **arg
return 0;
}
+static bool check_output_format(struct vo_chain *vo_c, int imgfmt)
+{
+ return vo_c->vf->output_params.imgfmt == imgfmt;
+}
+
+static int probe_deint_filters(struct vo_chain *vo_c)
+{
+ if (check_output_format(vo_c, IMGFMT_VDPAU)) {
+ char *args[5] = {"deint", "yes"};
+ int pref = 0;
+ vo_control(vo_c->vo, VOCTRL_GET_PREF_DEINT, &pref);
+ pref = pref < 0 ? -pref : pref;
+ if (pref > 0 && pref <= 4) {
+ const char *types[] =
+ {"", "first-field", "bob", "temporal", "temporal-spatial"};
+ args[2] = "deint-mode";
+ args[3] = (char *)types[pref];
+ }
+
+ return try_filter(vo_c, "vdpaupp", VF_DEINTERLACE_LABEL, args);
+ }
+ if (check_output_format(vo_c, IMGFMT_VAAPI))
+ return try_filter(vo_c, "vavpp", VF_DEINTERLACE_LABEL, NULL);
+ if (check_output_format(vo_c, IMGFMT_D3D11VA) ||
+ check_output_format(vo_c, IMGFMT_D3D11NV12))
+ return try_filter(vo_c, "d3d11vpp", VF_DEINTERLACE_LABEL, NULL);
+ return try_filter(vo_c, "yadif", VF_DEINTERLACE_LABEL, NULL);
+}
+
// Reconfigure the filter chain according to the new input format.
-static void filter_reconfig(struct vo_chain *vo_c)
+static void filter_reconfig(struct MPContext *mpctx, struct vo_chain *vo_c)
{
struct mp_image_params params = vo_c->input_format;
if (!params.imgfmt)
@@ -165,7 +196,7 @@ static void filter_reconfig(struct vo_chain *vo_c)
if (vf_reconfig(vo_c->vf, &params) < 0)
return;
- char *filters[] = {"autorotate", "autostereo3d", NULL};
+ char *filters[] = {"autorotate", "autostereo3d", "deinterlace", NULL};
for (int n = 0; filters[n]; n++) {
struct vf_instance *vf = vf_find_by_label(vo_c->vf, filters[n]);
if (vf) {
@@ -194,6 +225,53 @@ static void filter_reconfig(struct vo_chain *vo_c)
MP_ERR(vo_c, "Can't insert 3D conversion filter.\n");
}
}
+
+ if (mpctx->opts->deinterlace == 1)
+ probe_deint_filters(vo_c);
+}
+
+static void recreate_auto_filters(struct MPContext *mpctx)
+{
+ filter_reconfig(mpctx, mpctx->vo_chain);
+
+ mp_force_video_refresh(mpctx);
+
+ mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL);
+}
+
+int get_deinterlacing(struct MPContext *mpctx)
+{
+ struct vo_chain *vo_c = mpctx->vo_chain;
+ int enabled = 0;
+ if (video_vf_vo_control(vo_c, VFCTRL_GET_DEINTERLACE, &enabled) != CONTROL_OK)
+ enabled = -1;
+ if (enabled < 0) {
+ // vf_lavfi doesn't support VFCTRL_GET_DEINTERLACE
+ if (vf_find_by_label(vo_c->vf, VF_DEINTERLACE_LABEL))
+ enabled = 1;
+ }
+ return enabled;
+}
+
+void set_deinterlacing(struct MPContext *mpctx, bool enable)
+{
+ struct vo_chain *vo_c = mpctx->vo_chain;
+ if (vf_find_by_label(vo_c->vf, VF_DEINTERLACE_LABEL)) {
+ if (!enable) {
+ mpctx->opts->deinterlace = 0;
+ recreate_auto_filters(mpctx);
+ }
+ } else {
+ if ((get_deinterlacing(mpctx) > 0) != enable) {
+ int arg = enable;
+ if (video_vf_vo_control(vo_c, VFCTRL_SET_DEINTERLACE, &arg) != CONTROL_OK)
+ {
+ mpctx->opts->deinterlace = 1;
+ recreate_auto_filters(mpctx);
+ }
+ }
+ }
+ mpctx->opts->deinterlace = get_deinterlacing(mpctx) > 0;
}
static void recreate_video_filters(struct MPContext *mpctx)
@@ -230,7 +308,7 @@ int reinit_video_filters(struct MPContext *mpctx)
recreate_video_filters(mpctx);
if (need_reconfig)
- filter_reconfig(vo_c);
+ filter_reconfig(mpctx, vo_c);
mp_force_video_refresh(mpctx);
@@ -314,7 +392,6 @@ void uninit_video_chain(struct MPContext *mpctx)
mpctx->video_status = STATUS_EOF;
- remove_deint_filter(mpctx);
mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL);
}
}
@@ -522,22 +599,6 @@ static int decode_image(struct MPContext *mpctx)
}
}
-// Called after video reinit. This can be generally used to try to insert more
-// filters using the filter chain edit functionality in command.c.
-static void init_filter_params(struct MPContext *mpctx)
-{
- struct MPOpts *opts = mpctx->opts;
-
- // Note that the filter chain is already initialized. This code might
- // recreate the chain a second time, which is not very elegant, but allows
- // us to test whether enabling deinterlacing works with the current video
- // format and other filters.
- if (opts->deinterlace >= 0) {
- remove_deint_filter(mpctx);
- set_deinterlacing(mpctx, opts->deinterlace != 0);
- }
-}
-
// Feed newly decoded frames to the filter, take care of format changes.
// If eof=true, drain the filter chain, and return VD_EOF if empty.
static int video_filter(struct MPContext *mpctx, bool eof)
@@ -564,7 +625,7 @@ static int video_filter(struct MPContext *mpctx, bool eof)
return VD_PROGRESS;
// The filter chain is drained; execute the filter format change.
- filter_reconfig(mpctx->vo_chain);
+ filter_reconfig(mpctx, mpctx->vo_chain);
mp_notify(mpctx, MPV_EVENT_VIDEO_RECONFIG, NULL);
@@ -586,7 +647,6 @@ static int video_filter(struct MPContext *mpctx, bool eof)
MP_FATAL(mpctx, "Cannot initialize video filters.\n");
return VD_ERROR;
}
- init_filter_params(mpctx);
return VD_RECONFIG;
}