summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--input/cmd_list.h92
-rw-r--r--input/cmd_parse.c3
-rw-r--r--player/command.c1770
-rw-r--r--player/command.h19
4 files changed, 1018 insertions, 866 deletions
diff --git a/input/cmd_list.h b/input/cmd_list.h
index c6d7c66100..5f44602907 100644
--- a/input/cmd_list.h
+++ b/input/cmd_list.h
@@ -25,10 +25,13 @@
#define MP_CMD_OPT_ARG 0x1000
+struct mp_cmd_ctx;
+
struct mp_cmd_def {
- int id; // one of MP_CMD_...
const char *name; // user-visible name (as used in input.conf)
+ void (*handler)(void *ctx);
const struct m_option args[MP_CMD_DEF_MAX_ARGS];
+ const void *priv; // for free use by handler()
bool allow_auto_repeat; // react to repeated key events
bool on_updown; // always emit it on both up and down key events
bool vararg; // last argument can be given 0 to multiple times
@@ -40,93 +43,6 @@ struct mp_cmd_def {
extern const struct mp_cmd_def mp_cmds[];
-// All command IDs
-enum mp_command_type {
- MP_CMD_IGNORE,
- MP_CMD_SEEK,
- MP_CMD_REVERT_SEEK,
- MP_CMD_QUIT,
- MP_CMD_QUIT_WATCH_LATER,
- MP_CMD_PLAYLIST_NEXT,
- MP_CMD_PLAYLIST_PREV,
- MP_CMD_SCREENSHOT,
- MP_CMD_SCREENSHOT_TO_FILE,
- MP_CMD_SCREENSHOT_RAW,
- MP_CMD_LOADFILE,
- MP_CMD_LOADLIST,
- MP_CMD_PLAYLIST_CLEAR,
- MP_CMD_PLAYLIST_REMOVE,
- MP_CMD_PLAYLIST_MOVE,
- MP_CMD_PLAYLIST_SHUFFLE,
- MP_CMD_SUB_STEP,
- MP_CMD_SUB_SEEK,
- MP_CMD_TV_LAST_CHANNEL,
- MP_CMD_FRAME_STEP,
- MP_CMD_FRAME_BACK_STEP,
- MP_CMD_RUN,
- MP_CMD_SUB_ADD,
- MP_CMD_SUB_REMOVE,
- MP_CMD_SUB_RELOAD,
- MP_CMD_SET,
- MP_CMD_CHANGE_LIST,
- MP_CMD_PRINT_TEXT,
- MP_CMD_SHOW_TEXT,
- MP_CMD_EXPAND_TEXT,
- MP_CMD_SHOW_PROGRESS,
- MP_CMD_ADD,
- MP_CMD_CYCLE,
- MP_CMD_MULTIPLY,
- MP_CMD_CYCLE_VALUES,
- MP_CMD_STOP,
- MP_CMD_AUDIO_ADD,
- MP_CMD_AUDIO_REMOVE,
- MP_CMD_AUDIO_RELOAD,
-
- MP_CMD_ENABLE_INPUT_SECTION,
- MP_CMD_DISABLE_INPUT_SECTION,
- MP_CMD_DEFINE_INPUT_SECTION,
-
- MP_CMD_AB_LOOP,
-
- MP_CMD_DROP_BUFFERS,
-
- MP_CMD_MOUSE,
- MP_CMD_KEYPRESS,
- MP_CMD_KEYDOWN,
- MP_CMD_KEYUP,
-
- /// Audio Filter commands
- MP_CMD_AF,
- MP_CMD_AF_COMMAND,
- MP_CMD_AO_RELOAD,
-
- /// Video filter commands
- MP_CMD_VF,
- MP_CMD_VF_COMMAND,
-
- /// Internal for Lua scripts
- MP_CMD_SCRIPT_BINDING,
- MP_CMD_SCRIPT_MESSAGE,
- MP_CMD_SCRIPT_MESSAGE_TO,
-
- MP_CMD_OVERLAY_ADD,
- MP_CMD_OVERLAY_REMOVE,
-
- MP_CMD_WRITE_WATCH_LATER_CONFIG,
-
- MP_CMD_HOOK_ADD,
- MP_CMD_HOOK_ACK,
-
- MP_CMD_RESCAN_EXTERNAL_FILES,
-
- MP_CMD_APPLY_PROFILE,
-
- MP_CMD_LOAD_SCRIPT,
-
- // Internal
- MP_CMD_COMMAND_LIST, // list of sub-commands in args[0].v.p
-};
-
// Executing this command will maybe abort playback (play something else, or quit).
struct mp_cmd;
bool mp_input_is_maybe_abort_cmd(struct mp_cmd *cmd);
diff --git a/input/cmd_parse.c b/input/cmd_parse.c
index ae518fdf98..f401e5b9c7 100644
--- a/input/cmd_parse.c
+++ b/input/cmd_parse.c
@@ -29,7 +29,6 @@
#include "libmpv/client.h"
const struct mp_cmd_def mp_cmd_list = {
- .id = MP_CMD_COMMAND_LIST,
.name = "list",
};
@@ -87,7 +86,6 @@ static bool find_cmd(struct mp_log *log, struct mp_cmd *cmd, bstr name)
if (strcmp(nname, mp_cmds[n].name) == 0) {
cmd->def = &mp_cmds[n];
cmd->name = (char *)cmd->def->name;
- cmd->id = cmd->def->id;
return true;
}
}
@@ -341,7 +339,6 @@ mp_cmd_t *mp_input_parse_cmd_(struct mp_log *log, bstr str, const char *loc)
struct mp_cmd *list = talloc_ptrtype(NULL, list);
talloc_set_destructor(list, destroy_cmd);
*list = (struct mp_cmd) {
- .id = mp_cmd_list.id,
.name = (char *)mp_cmd_list.name,
.def = &mp_cmd_list,
.original = bstrdup(list, original),
diff --git a/player/command.c b/player/command.c
index c820a1ceb5..d5cedb235a 100644
--- a/player/command.c
+++ b/player/command.c
@@ -4582,11 +4582,16 @@ static void replace_overlay(struct MPContext *mpctx, int id, struct overlay *new
recreate_overlays(mpctx);
}
-static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
- char *file, int offset, char *fmt, int w, int h,
- int stride)
+static void cmd_overlay_add(void *pcmd)
{
- int r = -1;
+ struct mp_cmd_ctx *cmd = pcmd;
+ struct MPContext *mpctx = cmd->mpctx;
+ int id = cmd->args[0].v.i, x = cmd->args[1].v.i, y = cmd->args[2].v.i;
+ char *file = cmd->args[3].v.s;
+ int offset = cmd->args[4].v.i;
+ char *fmt = cmd->args[5].v.s;
+ int w = cmd->args[6].v.i, h = cmd->args[7].v.i, stride = cmd->args[8].v.i;
+
if (strcmp(fmt, "bgra") != 0) {
MP_ERR(mpctx, "overlay-add: unsupported OSD format '%s'\n", fmt);
goto error;
@@ -4644,15 +4649,18 @@ static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
munmap(p, map_size);
replace_overlay(mpctx, id, &overlay);
- r = 0;
+ return;
error:
- return r;
+ cmd->success = false;
}
-static void overlay_remove(struct MPContext *mpctx, int id)
+static void cmd_overlay_remove(void *p)
{
- struct command_ctx *cmd = mpctx->command_ctx;
- if (id >= 0 && id < cmd->num_overlays)
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ struct command_ctx *cmdctx = mpctx->command_ctx;
+ int id = cmd->args[0].v.i;
+ if (id >= 0 && id < cmdctx->num_overlays)
replace_overlay(mpctx, id, &(struct overlay){0});
}
@@ -4662,7 +4670,7 @@ static void overlay_uninit(struct MPContext *mpctx)
if (!mpctx->osd)
return;
for (int id = 0; id < cmd->num_overlays; id++)
- overlay_remove(mpctx, id);
+ replace_overlay(mpctx, id, &(struct overlay){0});
osd_set_external2(mpctx->osd, NULL);
for (int n = 0; n < 2; n++)
mp_image_unrefp(&cmd->overlay_osd[n].packed);
@@ -4708,36 +4716,32 @@ static bool check_property_scalable(char *property, struct MPContext *mpctx)
prop.type == &m_option_type_aspect;
}
-static int show_property_status(struct MPContext *mpctx, struct mp_cmd *cmd,
- const char *name, int r)
+static void show_property_status(struct mp_cmd_ctx *cmd, const char *name, int r)
{
+ struct MPContext *mpctx = cmd->mpctx;
struct MPOpts *opts = mpctx->opts;
int osd_duration = opts->osd_duration;
- int on_osd = cmd->flags & MP_ON_OSD_FLAGS;
- bool auto_osd = on_osd == MP_ON_OSD_AUTO;
- bool msg_osd = auto_osd || (on_osd & MP_ON_OSD_MSG);
- int osdl = msg_osd ? 1 : OSD_LEVEL_INVISIBLE;
+ int osdl = cmd->msg_osd ? 1 : OSD_LEVEL_INVISIBLE;
if (r == M_PROPERTY_OK || r == M_PROPERTY_UNAVAILABLE) {
- show_property_osd(mpctx, name, on_osd);
+ show_property_osd(mpctx, name, cmd->on_osd);
if (r == M_PROPERTY_UNAVAILABLE)
- return -1;
+ cmd->success = false;
} else if (r == M_PROPERTY_UNKNOWN) {
set_osd_msg(mpctx, osdl, osd_duration, "Unknown property: '%s'", name);
- return -1;
+ cmd->success = false;
} else if (r <= 0) {
set_osd_msg(mpctx, osdl, osd_duration, "Failed to set property '%s'",
name);
- return -1;
+ cmd->success = false;
}
- return 0;
}
-static int change_property_cmd(struct MPContext *mpctx, struct mp_cmd *cmd,
- const char *name, int action, void *arg)
+static void change_property_cmd(struct mp_cmd_ctx *cmd,
+ const char *name, int action, void *arg)
{
- int r = mp_property_do(name, action, arg, mpctx);
- return show_property_status(mpctx, cmd, name, r);
+ int r = mp_property_do(name, action, arg, cmd->mpctx);
+ show_property_status(cmd, name, r);
}
static bool compare_values(struct m_option *type, void *a, void *b)
@@ -4752,8 +4756,10 @@ static bool compare_values(struct m_option *type, void *a, void *b)
return res;
}
-static int cycle_values_cmd(struct MPContext *mpctx, struct mp_cmd *cmd)
+static void cmd_cycle_values(void *p)
{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
int first = 0, dir = 1;
if (strcmp(cmd->args[first].v.s, "!reverse") == 0) {
@@ -4764,26 +4770,31 @@ static int cycle_values_cmd(struct MPContext *mpctx, struct mp_cmd *cmd)
const char *name = cmd->args[first].v.s;
first += 1;
- if (first >= cmd->nargs) {
+ if (first >= cmd->num_args) {
MP_ERR(mpctx, "cycle-values command does not have any value arguments.\n");
- return -1;
+ cmd->success = false;
+ return;
}
struct m_option prop = {0};
int r = mp_property_do(name, M_PROPERTY_GET_TYPE, &prop, mpctx);
- if (r <= 0)
- return show_property_status(mpctx, cmd, name, r);
+ if (r <= 0) {
+ show_property_status(cmd, name, r);
+ return;
+ }
union m_option_value curval = {0};
r = mp_property_do(name, M_PROPERTY_GET, &curval, mpctx);
- if (r <= 0)
- return show_property_status(mpctx, cmd, name, r);
+ if (r <= 0) {
+ show_property_status(cmd, name, r);
+ return;
+ }
// Find the current value. Note that we even though compare_values() uses
// strings internally, we need to convert the cycle-values arguments to
// native anyway to "normalize" the value for comparison.
int current = -1;
- for (int n = first; n < cmd->nargs; n++) {
+ for (int n = first; n < cmd->num_args; n++) {
union m_option_value val = {0};
if (m_option_parse(mpctx->log, &prop, bstr0(name),
bstr0(cmd->args[n].v.s), &val) <= 0)
@@ -4803,32 +4814,37 @@ static int cycle_values_cmd(struct MPContext *mpctx, struct mp_cmd *cmd)
if (current >= 0) {
current += dir;
if (current < first)
- current = cmd->nargs - 1;
- if (current >= cmd->nargs)
+ current = cmd->num_args - 1;
+ if (current >= cmd->num_args)
current = first;
} else {
MP_VERBOSE(mpctx, "Current value not found. Picking default.\n");
- current = dir > 0 ? first : cmd->nargs - 1;
+ current = dir > 0 ? first : cmd->num_args - 1;
}
- return change_property_cmd(mpctx, cmd, name, M_PROPERTY_SET_STRING,
- cmd->args[current].v.s);
+ change_property_cmd(cmd, name, M_PROPERTY_SET_STRING, cmd->args[current].v.s);
}
int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *res)
{
- struct command_ctx *cmdctx = mpctx->command_ctx;
- struct MPOpts *opts = mpctx->opts;
- int osd_duration = opts->osd_duration;
- int on_osd = cmd->flags & MP_ON_OSD_FLAGS;
- bool auto_osd = on_osd == MP_ON_OSD_AUTO;
- bool msg_osd = auto_osd || (on_osd & MP_ON_OSD_MSG);
- bool bar_osd = auto_osd || (on_osd & MP_ON_OSD_BAR);
- bool seek_msg_osd = auto_osd ? opts->osd_on_seek & 2 : msg_osd;
- bool seek_bar_osd = auto_osd ? opts->osd_on_seek & 1 : bar_osd;
+ struct mpv_node dummy_node = {0};
+ struct mp_cmd_ctx *ctx = &(struct mp_cmd_ctx){
+ .mpctx = mpctx,
+ .cmd = cmd,
+ .args = cmd->args,
+ .num_args = cmd->nargs,
+ .priv = cmd->def->priv,
+ .success = true,
+ .result = res ? res : &dummy_node,
+ };
- int osdl = msg_osd ? 1 : OSD_LEVEL_INVISIBLE;
- bool async = cmd->flags & MP_ASYNC_CMD;
+ struct MPOpts *opts = mpctx->opts;
+ ctx->on_osd = cmd->flags & MP_ON_OSD_FLAGS;
+ bool auto_osd = ctx->on_osd == MP_ON_OSD_AUTO;
+ ctx->msg_osd = auto_osd || (ctx->on_osd & MP_ON_OSD_MSG);
+ ctx->bar_osd = auto_osd || (ctx->on_osd & MP_ON_OSD_BAR);
+ ctx->seek_msg_osd = auto_osd ? opts->osd_on_seek & 2 : ctx->msg_osd;
+ ctx->seek_bar_osd = auto_osd ? opts->osd_on_seek & 1 : ctx->bar_osd;
mp_cmd_dump(mpctx->log, cmd->def->is_ignore ? MSGL_TRACE : MSGL_DEBUG,
"Run command:", cmd);
@@ -4845,774 +4861,959 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
}
}
- switch (cmd->id) {
- case MP_CMD_SEEK: {
- double v = cmd->args[0].v.d * cmd->scale;
- int abs = cmd->args[1].v.i & 3;
- enum seek_precision precision = MPSEEK_DEFAULT;
- switch (((cmd->args[2].v.i | cmd->args[1].v.i) >> 3) & 3) {
- case 1: precision = MPSEEK_KEYFRAME; break;
- case 2: precision = MPSEEK_EXACT; break;
- }
- if (!mpctx->playback_initialized)
- return -1;
- mark_seek(mpctx);
- switch (abs) {
- case 0: { // Relative seek
- queue_seek(mpctx, MPSEEK_RELATIVE, v, precision, MPSEEK_FLAG_DELAY);
- set_osd_function(mpctx, (v > 0) ? OSD_FFW : OSD_REW);
- break;
- }
- case 1: { // Absolute seek by percentage
- double ratio = v / 100.0;
- double cur_pos = get_current_pos_ratio(mpctx, false);
- queue_seek(mpctx, MPSEEK_FACTOR, ratio, precision, MPSEEK_FLAG_DELAY);
- set_osd_function(mpctx, cur_pos < ratio ? OSD_FFW : OSD_REW);
- break;
- }
- case 2: { // Absolute seek to a timestamp in seconds
- if (v < 0) {
- // Seek from end
- double len = get_time_length(mpctx);
- if (len < 0)
- return -1;
- v = MPMAX(0, len + v);
+ if (cmd->def == &mp_cmd_list) {
+ for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next)
+ run_command(mpctx, sub, NULL);
+ } else {
+ assert(cmd->def->handler);
+ cmd->def->handler(ctx);
+ }
+
+ if (!ctx->success)
+ mpv_free_node_contents(ctx->result);
+
+ mpv_free_node_contents(&dummy_node);
+
+ return ctx->success ? 0 : -1;
+}
+
+static void cmd_seek(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ double v = cmd->args[0].v.d * cmd->cmd->scale;
+ int abs = cmd->args[1].v.i & 3;
+ enum seek_precision precision = MPSEEK_DEFAULT;
+ switch (((cmd->args[2].v.i | cmd->args[1].v.i) >> 3) & 3) {
+ case 1: precision = MPSEEK_KEYFRAME; break;
+ case 2: precision = MPSEEK_EXACT; break;
+ }
+ if (!mpctx->playback_initialized) {
+ cmd->success = false;
+ return;
+ }
+
+ mark_seek(mpctx);
+ switch (abs) {
+ case 0: { // Relative seek
+ queue_seek(mpctx, MPSEEK_RELATIVE, v, precision, MPSEEK_FLAG_DELAY);
+ set_osd_function(mpctx, (v > 0) ? OSD_FFW : OSD_REW);
+ break;
+ }
+ case 1: { // Absolute seek by percentage
+ double ratio = v / 100.0;
+ double cur_pos = get_current_pos_ratio(mpctx, false);
+ queue_seek(mpctx, MPSEEK_FACTOR, ratio, precision, MPSEEK_FLAG_DELAY);
+ set_osd_function(mpctx, cur_pos < ratio ? OSD_FFW : OSD_REW);
+ break;
+ }
+ case 2: { // Absolute seek to a timestamp in seconds
+ if (v < 0) {
+ // Seek from end
+ double len = get_time_length(mpctx);
+ if (len < 0) {
+ cmd->success = false;
+ return;
}
- queue_seek(mpctx, MPSEEK_ABSOLUTE, v, precision, MPSEEK_FLAG_DELAY);
- set_osd_function(mpctx,
- v > get_current_time(mpctx) ? OSD_FFW : OSD_REW);
- break;
+ v = MPMAX(0, len + v);
}
- case 3: { // Relative seek by percentage
- queue_seek(mpctx, MPSEEK_FACTOR,
- get_current_pos_ratio(mpctx, false) + v / 100.0,
- precision, MPSEEK_FLAG_DELAY);
- set_osd_function(mpctx, v > 0 ? OSD_FFW : OSD_REW);
- break;
- }}
- if (seek_bar_osd)
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, v, precision, MPSEEK_FLAG_DELAY);
+ set_osd_function(mpctx,
+ v > get_current_time(mpctx) ? OSD_FFW : OSD_REW);
+ break;
+ }
+ case 3: { // Relative seek by percentage
+ queue_seek(mpctx, MPSEEK_FACTOR,
+ get_current_pos_ratio(mpctx, false) + v / 100.0,
+ precision, MPSEEK_FLAG_DELAY);
+ set_osd_function(mpctx, v > 0 ? OSD_FFW : OSD_REW);
+ break;
+ }}
+ if (cmd->seek_bar_osd)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;
+ if (cmd->seek_msg_osd)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_TEXT;
+}
+
+static void cmd_revert_seek(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ struct command_ctx *cmdctx = mpctx->command_ctx;
+
+ if (!mpctx->playback_initialized) {
+ cmd->success = false;
+ return;
+ }
+
+ double oldpts = cmdctx->last_seek_pts;
+ if (cmdctx->marked_pts != MP_NOPTS_VALUE)
+ oldpts = cmdctx->marked_pts;
+ if (cmd->args[0].v.i == 1) {
+ cmdctx->marked_pts = get_current_time(mpctx);
+ } else if (oldpts != MP_NOPTS_VALUE) {
+ cmdctx->last_seek_pts = get_current_time(mpctx);
+ cmdctx->marked_pts = MP_NOPTS_VALUE;
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, oldpts, MPSEEK_EXACT,
+ MPSEEK_FLAG_DELAY);
+ set_osd_function(mpctx, OSD_REW);
+ if (cmd->seek_bar_osd)
mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;
- if (seek_msg_osd)
+ if (cmd->seek_msg_osd)
mpctx->add_osd_seek_info |= OSD_SEEK_INFO_TEXT;
- break;
+ } else {
+ cmd->success = false;
}
+}
- case MP_CMD_REVERT_SEEK: {
- if (!mpctx->playback_initialized)
- return -1;
- double oldpts = cmdctx->last_seek_pts;
- if (cmdctx->marked_pts != MP_NOPTS_VALUE)
- oldpts = cmdctx->marked_pts;
- if (cmd->args[0].v.i == 1) {
- cmdctx->marked_pts = get_current_time(mpctx);
- } else if (oldpts != MP_NOPTS_VALUE) {
- cmdctx->last_seek_pts = get_current_time(mpctx);
- cmdctx->marked_pts = MP_NOPTS_VALUE;
- queue_seek(mpctx, MPSEEK_ABSOLUTE, oldpts, MPSEEK_EXACT,
- MPSEEK_FLAG_DELAY);
- set_osd_function(mpctx, OSD_REW);
- if (seek_bar_osd)
- mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;
- if (seek_msg_osd)
- mpctx->add_osd_seek_info |= OSD_SEEK_INFO_TEXT;
- } else {
- return -1;
- }
- break;
+static void cmd_set(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+
+ change_property_cmd(cmd, cmd->args[0].v.s,
+ M_PROPERTY_SET_STRING, cmd->args[1].v.s);
+}
+
+static void cmd_change_list(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ char *name = cmd->args[0].v.s;
+ char *op = cmd->args[1].v.s;
+ char *value = cmd->args[2].v.s;
+ int osd_duration = mpctx->opts->osd_duration;
+ int osdl = cmd->msg_osd ? 1 : OSD_LEVEL_INVISIBLE;
+
+ struct m_config_option *co = m_config_get_co(mpctx->mconfig, bstr0(name));
+ if (!co) {
+ set_osd_msg(mpctx, osdl, osd_duration, "Unknown option: '%s'", name);
+ cmd->success = false;
+ return;
}
- case MP_CMD_SET: {
- return change_property_cmd(mpctx, cmd, cmd->args[0].v.s,
- M_PROPERTY_SET_STRING, cmd->args[1].v.s);
+ const struct m_option_type *type = co->opt->type;
+ bool found = false;
+ for (int i = 0; type->actions && type->actions[i].name; i++) {
+ const struct m_option_action *action = &type->actions[i];
+ if (strcmp(action->name, op) == 0)
+ found = true;
+ }
+ if (!found) {
+ set_osd_msg(mpctx, osdl, osd_duration, "Unknown action: '%s'", op);
+ cmd->success = false;
+ return;
}
- case MP_CMD_CHANGE_LIST: {
- char *name = cmd->args[0].v.s;
- char *op = cmd->args[1].v.s;
- char *value = cmd->args[2].v.s;
- struct m_config_option *co = m_config_get_co(mpctx->mconfig, bstr0(name));
- if (!co) {
- set_osd_msg(mpctx, osdl, osd_duration, "Unknown option: '%s'", name);
- return -1;
- }
- const struct m_option_type *type = co->opt->type;
- bool found = false;
- for (int i = 0; type->actions && type->actions[i].name; i++) {
- const struct m_option_action *action = &type->actions[i];
- if (strcmp(action->name, op) == 0)
- found = true;
- }
- if (!found) {
- set_osd_msg(mpctx, osdl, osd_duration, "Unknown action: '%s'", op);
- return -1;
- }
- char *optname = mp_tprintf(80, "%s-%s", name, op); // the dirty truth
- int r = m_config_set_option_cli(mpctx->mconfig, bstr0(optname),
- bstr0(value), M_SETOPT_RUNTIME);
- if (r < 0) {
- set_osd_msg(mpctx, osdl, osd_duration,
- "Failed setting option: '%s'", name);
- return -1;
- }
- show_property_osd(mpctx, name, on_osd);
- break;
+ char *optname = mp_tprintf(80, "%s-%s", name, op); // the dirty truth
+ int r = m_config_set_option_cli(mpctx->mconfig, bstr0(optname),
+ bstr0(value), M_SETOPT_RUNTIME);
+ if (r < 0) {
+ set_osd_msg(mpctx, osdl, osd_duration,
+ "Failed setting option: '%s'", name);
+ cmd->success = false;
+ return;
}
- case MP_CMD_ADD:
- case MP_CMD_CYCLE:
- {
- char *property = cmd->args[0].v.s;
- if (cmd->repeated && !check_property_autorepeat(property, mpctx)) {
- MP_VERBOSE(mpctx, "Dropping command '%.*s' from auto-repeated key.\n",
- BSTR_P(cmd->original));
- break;
- }
- double scale = 1;
- int scale_units = cmd->scale_units;
- if (check_property_scalable(property, mpctx)) {
- scale = cmd->scale;
- scale_units = 1;
- }
- for (int i = 0; i < scale_units; i++) {
- struct m_property_switch_arg s = {
- .inc = cmd->args[1].v.d * scale,
- .wrap = cmd->id == MP_CMD_CYCLE,
- };
- int r =
- change_property_cmd(mpctx, cmd, property, M_PROPERTY_SWITCH, &s);
- if (r < 0)
- return r;
- }
- break;
+ show_property_osd(mpctx, name, cmd->on_osd);
+}
+
+static void cmd_add_cycle(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ bool is_cycle = !!cmd->priv;
+
+ char *property = cmd->args[0].v.s;
+ if (cmd->cmd->repeated && !check_property_autorepeat(property, mpctx)) {
+ MP_VERBOSE(mpctx, "Dropping command '%.*s' from auto-repeated key.\n",
+ BSTR_P(cmd->cmd->original));
+ return;
}
- case MP_CMD_MULTIPLY: {
- return change_property_cmd(mpctx, cmd, cmd->args[0].v.s,
- M_PROPERTY_MULTIPLY, &cmd->args[1].v.d);
+ double scale = 1;
+ int scale_units = cmd->cmd->scale_units;
+ if (check_property_scalable(property, mpctx)) {
+ scale = cmd->cmd->scale;
+ scale_units = 1;
}
- case MP_CMD_CYCLE_VALUES:
- return cycle_values_cmd(mpctx, cmd);
+ for (int i = 0; i < scale_units; i++) {
+ struct m_property_switch_arg s = {
+ .inc = cmd->args[1].v.d * scale,
+ .wrap = is_cycle,
+ };
+ change_property_cmd(cmd, property, M_PROPERTY_SWITCH, &s);
+ if (!cmd->success)
+ return;
+ }
+}
+
+static void cmd_multiply(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+
+ change_property_cmd(cmd, cmd->args[0].v.s,
+ M_PROPERTY_MULTIPLY, &cmd->args[1].v.d);
+}
+
+static void cmd_frame_step(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_FRAME_STEP:
- if (!mpctx->playback_initialized)
- return -1;
- if (cmd->is_up_down) {
- if (cmd->is_up) {
- if (mpctx->step_frames < 1)
- set_pause_state(mpctx, true);
+ if (!mpctx->playback_initialized) {
+ cmd->success = false;
+ return;
+ }
+
+ if (cmd->cmd->is_up_down) {
+ if (cmd->cmd->is_up) {
+ if (mpctx->step_frames < 1)
+ set_pause_state(mpctx, true);
+ } else {
+ if (cmd->cmd->repeated) {
+ set_pause_state(mpctx, false);
} else {
- if (cmd->repeated) {
- set_pause_state(mpctx, false);
- } else {
- add_step_frame(mpctx, 1);
- }
+ add_step_frame(mpctx, 1);
}
- } else {
- add_step_frame(mpctx, 1);
}
- break;
+ } else {
+ add_step_frame(mpctx, 1);
+ }
+}
- case MP_CMD_FRAME_BACK_STEP:
- if (!mpctx->playback_initialized)
- return -1;
- add_step_frame(mpctx, -1);
- break;
+static void cmd_frame_back_step(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_QUIT:
- case MP_CMD_QUIT_WATCH_LATER:
- if (cmd->id == MP_CMD_QUIT_WATCH_LATER || opts->position_save_on_quit)
- mp_write_watch_later_conf(mpctx);
- mpctx->stop_play = PT_QUIT;
- mpctx->quit_custom_rc = cmd->args[0].v.i;
- mpctx->has_quit_custom_rc = true;
- mp_wakeup_core(mpctx);
- break;
+ if (!mpctx->playback_initialized) {
+ cmd->success = false;
+ return;
+ }
- case MP_CMD_PLAYLIST_NEXT:
- case MP_CMD_PLAYLIST_PREV:
- {
- int dir = cmd->id == MP_CMD_PLAYLIST_PREV ? -1 : +1;
- int force = cmd->args[0].v.i;
+ add_step_frame(mpctx, -1);
+}
- struct playlist_entry *e = mp_next_file(mpctx, dir, force, true);
- if (!e && !force)
- return -1;
- mp_set_playlist_entry(mpctx, e);
- if (on_osd & MP_ON_OSD_MSG)
- mpctx->add_osd_seek_info |= OSD_SEEK_INFO_CURRENT_FILE;
- break;
+static void cmd_quit(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ bool write_watch_later = *(bool *)cmd->priv;
+ if (write_watch_later || mpctx->opts->position_save_on_quit)
+ mp_write_watch_later_conf(mpctx);
+ mpctx->stop_play = PT_QUIT;
+ mpctx->quit_custom_rc = cmd->args[0].v.i;
+ mpctx->has_quit_custom_rc = true;
+ mp_wakeup_core(mpctx);
+}
+
+static void cmd_playlist_next_prev(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int dir = *(int *)cmd->priv;
+ int force = cmd->args[0].v.i;
+
+ struct playlist_entry *e = mp_next_file(mpctx, dir, force, true);
+ if (!e && !force) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_SUB_STEP:
- case MP_CMD_SUB_SEEK: {
- if (!mpctx->playback_initialized)
- return -1;
- struct track *track = mpctx->current_track[0][STREAM_SUB];
- struct dec_sub *sub = track ? track->d_sub : NULL;
- double refpts = get_current_time(mpctx);
- if (sub && refpts != MP_NOPTS_VALUE) {
- double a[2];
- a[0] = refpts;
- a[1] = cmd->args[0].v.i;
- if (sub_control(sub, SD_CTRL_SUB_STEP, a) > 0) {
- if (cmd->id == MP_CMD_SUB_STEP) {
- opts->subs_rend->sub_delay -= a[0] - refpts;
- m_config_notify_change_opt_ptr(mpctx->mconfig,
- &opts->subs_rend->sub_delay);
- show_property_osd(mpctx, "sub-delay", on_osd);
- } else {
- // We can easily get stuck by failing to seek to the video
- // frame which actually shows the sub first (because video
- // frame PTS and sub PTS rarely match exactly). Add some
- // rounding for the mess of it.
- a[0] += 0.01 * (a[1] >= 0 ? 1 : -1);
- mark_seek(mpctx);
- queue_seek(mpctx, MPSEEK_ABSOLUTE, a[0], MPSEEK_EXACT,
- MPSEEK_FLAG_DELAY);
- set_osd_function(mpctx, (a[0] > refpts) ? OSD_FFW : OSD_REW);
- if (seek_bar_osd)
- mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;
- if (seek_msg_osd)
- mpctx->add_osd_seek_info |= OSD_SEEK_INFO_TEXT;
- }
+ mp_set_playlist_entry(mpctx, e);
+ if (cmd->on_osd & MP_ON_OSD_MSG)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_CURRENT_FILE;
+}
+
+static void cmd_sub_step_seek(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ bool step = *(bool *)cmd->priv;
+
+ if (!mpctx->playback_initialized) {
+ cmd->success = false;
+ return;
+ }
+
+ struct track *track = mpctx->current_track[0][STREAM_SUB];
+ struct dec_sub *sub = track ? track->d_sub : NULL;
+ double refpts = get_current_time(mpctx);
+ if (sub && refpts != MP_NOPTS_VALUE) {
+ double a[2];
+ a[0] = refpts;
+ a[1] = cmd->args[0].v.i;
+ if (sub_control(sub, SD_CTRL_SUB_STEP, a) > 0) {
+ if (step) {
+ mpctx->opts->subs_rend->sub_delay -= a[0] - refpts;
+ m_config_notify_change_opt_ptr(mpctx->mconfig,
+ &mpctx->opts->subs_rend->sub_delay);
+ show_property_osd(mpctx, "sub-delay", cmd->on_osd);
+ } else {
+ // We can easily get stuck by failing to seek to the video
+ // frame which actually shows the sub first (because video
+ // frame PTS and sub PTS rarely match exactly). Add some
+ // rounding for the mess of it.
+ a[0] += 0.01 * (a[1] >= 0 ? 1 : -1);
+ mark_seek(mpctx);
+ queue_seek(mpctx, MPSEEK_ABSOLUTE, a[0], MPSEEK_EXACT,
+ MPSEEK_FLAG_DELAY);
+ set_osd_function(mpctx, (a[0] > refpts) ? OSD_FFW : OSD_REW);
+ if (cmd->seek_bar_osd)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;
+ if (cmd->seek_msg_osd)
+ mpctx->add_osd_seek_info |= OSD_SEEK_INFO_TEXT;
}
}
- break;
}
+}
- case MP_CMD_PRINT_TEXT: {
- MP_INFO(mpctx, "%s\n", cmd->args[0].v.s);
- break;
- }
+static void cmd_print_text(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_SHOW_TEXT: {
- // if no argument supplied use default osd_duration, else <arg> ms.
- set_osd_msg(mpctx, cmd->args[2].v.i,
- (cmd->args[1].v.i < 0 ? osd_duration : cmd->args[1].v.i),
- "%s", cmd->args[0].v.s);
- break;
+ MP_INFO(mpctx, "%s\n", cmd->args[0].v.s);
+}
+
+static void cmd_show_text(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int osd_duration = mpctx->opts->osd_duration;
+
+ // if no argument supplied use default osd_duration, else <arg> ms.
+ set_osd_msg(mpctx, cmd->args[2].v.i,
+ (cmd->args[1].v.i < 0 ? osd_duration : cmd->args[1].v.i),
+ "%s", cmd->args[0].v.s);
+}
+
+static void cmd_expand_text(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ *cmd->result = (mpv_node){
+ .format = MPV_FORMAT_STRING,
+ .u.string = mp_property_expand_string(mpctx, cmd->args[0].v.s)
+ };
+}
+
+static void cmd_loadfile(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ char *filename = cmd->args[0].v.s;
+ int append = cmd->args[1].v.i;
+
+ if (!append)
+ playlist_clear(mpctx->playlist);
+
+ struct playlist_entry *entry = playlist_entry_new(filename);
+ if (cmd->args[2].v.str_list) {
+ char **pairs = cmd->args[2].v.str_list;
+ for (int i = 0; pairs[i] && pairs[i + 1]; i += 2)
+ playlist_entry_add_param(entry, bstr0(pairs[i]), bstr0(pairs[i + 1]));
}
+ playlist_add(mpctx->playlist, entry);
- case MP_CMD_EXPAND_TEXT: {
- if (!res)
- return -1;
- *res = (mpv_node){
- .format = MPV_FORMAT_STRING,
- .u.string = mp_property_expand_string(mpctx, cmd->args[0].v.s)
- };
- break;
+ if (!append || (append == 2 && !mpctx->playlist->current)) {
+ if (mpctx->opts->position_save_on_quit) // requested in issue #1148
+ mp_write_watch_later_conf(mpctx);
+ mp_set_playlist_entry(mpctx, entry);
}
+ mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
+ mp_wakeup_core(mpctx);
+}
- case MP_CMD_LOADFILE: {
- char *filename = cmd->args[0].v.s;
- int append = cmd->args[1].v.i;
+static void cmd_loadlist(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ char *filename = cmd->args[0].v.s;
+ bool append = cmd->args[1].v.i;
+ struct playlist *pl = playlist_parse_file(filename, mpctx->global);
+ if (pl) {
+ prepare_playlist(mpctx, pl);
+ struct playlist_entry *new = pl->current;
if (!append)
playlist_clear(mpctx->playlist);
+ playlist_append_entries(mpctx->playlist, pl);
+ talloc_free(pl);
- struct playlist_entry *entry = playlist_entry_new(filename);
- if (cmd->args[2].v.str_list) {
- char **pairs = cmd->args[2].v.str_list;
- for (int i = 0; pairs[i] && pairs[i + 1]; i += 2) {
- playlist_entry_add_param(entry, bstr0(pairs[i]),
- bstr0(pairs[i + 1]));
- }
- }
- playlist_add(mpctx->playlist, entry);
+ if (!append && mpctx->playlist->first)