summaryrefslogtreecommitdiffstats
path: root/player/video.c
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 /player/video.c
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.)
Diffstat (limited to 'player/video.c')
-rw-r--r--player/video.c104
1 files changed, 82 insertions, 22 deletions
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;
}