summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/input.rst31
-rw-r--r--core/command.c40
-rw-r--r--core/input/input.c2
-rw-r--r--core/input/input.h3
-rw-r--r--core/mp_core.h1
-rw-r--r--core/mplayer.c46
-rw-r--r--video/decode/dec_video.c1
7 files changed, 112 insertions, 12 deletions
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst
index bd62e65cd6..4acba49169 100644
--- a/DOCS/man/en/input.rst
+++ b/DOCS/man/en/input.rst
@@ -236,6 +236,37 @@ af_clr
Remove all audio filters. (Conversion filters will be re-added
automatically if needed.)
+vf set|add|toggle|del "filter1=params,filter2,..."
+ Change video filter chain.
+
+ The first argument decides what happens:
+
+ set
+ Overwrite the previous filter chain with the new one.
+
+ add
+ Append the new filter chain to the previous one.
+
+ toggle
+ Check if the given filter (with the exact parameters) is already
+ in the video chain. If yes, remove the filter. If no, add the filter.
+ (If several filters are passed to the command, this is done for
+ each filter.)
+
+ del
+ Remove the given filters from the video chain. Unlike in the other
+ cases, the second parameter is a comma separated list of filter names
+ or integer indexes. ``0`` would denote the first filter. Negative
+ indexes start from the last filter, and ``-1`` denotes the last
+ filter.
+
+ *EXAMPLE for input.conf*:
+
+ - ``a vf set flip`` turn video upside-down on the ``a`` key
+ - ``b vf set ""`` remove all video filters on ``b``
+ - ``c vf toggle lavfi=gradfun`` toggle debanding on ``c``
+
+
Undocumented commands: tv_start_scan, tv_step_channel, tv_step_norm,
tv_step_chanlist, tv_set_channel, tv_last_channel, tv_set_freq, tv_step_freq,
tv_set_norm, dvb_set_channel, radio_step_channel, radio_set_channel,
diff --git a/core/command.c b/core/command.c
index ebc8d93485..9e16804e8a 100644
--- a/core/command.c
+++ b/core/command.c
@@ -1775,6 +1775,42 @@ static void show_playlist_on_osd(MPContext *mpctx)
talloc_free(res);
}
+static void change_video_filters(MPContext *mpctx, const char *cmd,
+ const char *arg)
+{
+ struct MPOpts *opts = &mpctx->opts;
+ struct m_config *conf = mpctx->mconfig;
+ struct m_obj_settings *old_vf_settings = NULL;
+ bool success = false;
+ bool need_refresh = false;
+ double refresh_pts = mpctx->last_vo_pts;
+
+ // The option parser is used to modify the filter list itself.
+ char optname[20];
+ snprintf(optname, sizeof(optname), "vf-%s", cmd);
+ const struct m_option *type = m_config_get_option(conf, bstr0(optname));
+
+ // Backup old settings, in case it fails
+ m_option_copy(type, &old_vf_settings, &opts->vf_settings);
+
+ if (m_config_set_option0(conf, optname, arg) >= 0) {
+ need_refresh = true;
+ success = reinit_video_filters(mpctx) >= 0;
+ }
+
+ if (!success) {
+ m_option_copy(type, &opts->vf_settings, &old_vf_settings);
+ if (need_refresh)
+ reinit_video_filters(mpctx);
+ }
+ m_option_free(type, &old_vf_settings);
+
+ // Try to refresh the video by doing a precise seek to the currently
+ // displayed frame.
+ if (need_refresh && opts->pause)
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, refresh_pts, 1);
+}
+
void run_command(MPContext *mpctx, mp_cmd_t *cmd)
{
struct MPOpts *opts = &mpctx->opts;
@@ -2289,6 +2325,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
af_uninit(mpctx->mixer.afilter);
af_init(mpctx->mixer.afilter);
}
+ /* fallthrough */
case MP_CMD_AF_ADD:
case MP_CMD_AF_DEL: {
if (!sh_audio)
@@ -2331,6 +2368,9 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
af_reinit(sh_audio->afilter);
}
break;
+ case MP_CMD_VF:
+ change_video_filters(mpctx, cmd->args[0].v.s, cmd->args[1].v.s);
+ break;
case MP_CMD_SHOW_CHAPTERS:
show_chapters_on_osd(mpctx);
break;
diff --git a/core/input/input.c b/core/input/input.c
index 7ba6b64cdc..116e963b93 100644
--- a/core/input/input.c
+++ b/core/input/input.c
@@ -198,6 +198,8 @@ static const mp_cmd_t mp_cmds[] = {
{ MP_CMD_AF_CLR, "af_clr", },
{ MP_CMD_AF_CMDLINE, "af_cmdline", { ARG_STRING, ARG_STRING } },
+ { MP_CMD_VF, "vf", { ARG_STRING, ARG_STRING } },
+
{ MP_CMD_SHOW_CHAPTERS, "show_chapters", },
{ MP_CMD_SHOW_TRACKS, "show_tracks", },
{ MP_CMD_SHOW_PLAYLIST, "show_playlist", },
diff --git a/core/input/input.h b/core/input/input.h
index 367abedfca..12823dd004 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -78,6 +78,9 @@ enum mp_command_type {
MP_CMD_AF_CLR,
MP_CMD_AF_CMDLINE,
+ /// Video filter commands
+ MP_CMD_VF,
+
MP_CMD_SHOW_CHAPTERS,
MP_CMD_SHOW_TRACKS,
MP_CMD_SHOW_PLAYLIST,
diff --git a/core/mp_core.h b/core/mp_core.h
index 941396c48a..ce576273b4 100644
--- a/core/mp_core.h
+++ b/core/mp_core.h
@@ -298,6 +298,7 @@ double playing_audio_pts(struct MPContext *mpctx);
struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
float fps, int noerr);
int reinit_video_chain(struct MPContext *mpctx);
+int reinit_video_filters(struct MPContext *mpctx);
void pause_player(struct MPContext *mpctx);
void unpause_player(struct MPContext *mpctx);
void add_step_frame(struct MPContext *mpctx, int dir);
diff --git a/core/mplayer.c b/core/mplayer.c
index ac597beac1..a0b18cab62 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -2466,6 +2466,39 @@ static void update_fps(struct MPContext *mpctx)
#endif
}
+static void recreate_video_filters(struct MPContext *mpctx)
+{
+ struct MPOpts *opts = &mpctx->opts;
+ struct sh_video *sh_video = mpctx->sh_video;
+ assert(sh_video);
+
+ vf_uninit_filter_chain(sh_video->vfilter);
+
+ char *vf_arg[] = {
+ "_oldargs_", (char *)mpctx->video_out, NULL
+ };
+ sh_video->vfilter = vf_open_filter(opts, NULL, "vo", vf_arg);
+
+ sh_video->vfilter = append_filters(sh_video->vfilter, opts->vf_settings);
+
+ struct vf_instance *vf = sh_video->vfilter;
+ mpctx->osd->render_subs_in_filter
+ = vf->control(vf, VFCTRL_INIT_OSD, NULL) == VO_TRUE;
+}
+
+int reinit_video_filters(struct MPContext *mpctx)
+{
+ struct sh_video *sh_video = mpctx->sh_video;
+
+ if (!sh_video)
+ return -2;
+
+ recreate_video_filters(mpctx);
+ video_reinit_vo(sh_video);
+
+ return sh_video->vf_initialized > 0 ? 0 : -1;
+}
+
int reinit_video_chain(struct MPContext *mpctx)
{
struct MPOpts *opts = &mpctx->opts;
@@ -2518,18 +2551,7 @@ int reinit_video_chain(struct MPContext *mpctx)
STREAM_CTRL_GET_ASPECT_RATIO, &ar) != STREAM_UNSUPPORTED)
mpctx->sh_video->stream_aspect = ar;
- {
- char *vf_arg[] = {
- "_oldargs_", (char *)mpctx->video_out, NULL
- };
- sh_video->vfilter = vf_open_filter(opts, NULL, "vo", vf_arg);
- }
-
- sh_video->vfilter = append_filters(sh_video->vfilter, opts->vf_settings);
-
- struct vf_instance *vf = sh_video->vfilter;
- mpctx->osd->render_subs_in_filter
- = vf->control(vf, VFCTRL_INIT_OSD, NULL) == VO_TRUE;
+ recreate_video_filters(mpctx);
init_best_video_codec(sh_video, opts->video_decoders);
diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c
index 1dd83db8bd..5e55e78220 100644
--- a/video/decode/dec_video.c
+++ b/video/decode/dec_video.c
@@ -184,6 +184,7 @@ void uninit_video(sh_video_t *sh_video)
mp_tmsg(MSGT_DECVIDEO, MSGL_V, "Uninit video.\n");
sh_video->vd_driver->uninit(sh_video);
vf_uninit_filter_chain(sh_video->vfilter);
+ sh_video->vfilter = NULL;
talloc_free(sh_video->gsh->decoder_desc);
sh_video->gsh->decoder_desc = NULL;
sh_video->initialized = 0;