aboutsummaryrefslogtreecommitdiffhomepage
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)
+ mp_set_playlist_entry(mpctx, new ? new : mpctx->playlist->first);
- if (!append || (append == 2 && !mpctx->playlist->current)) {
- if (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);
- break;
+ } else {
+ MP_ERR(mpctx, "Unable to load playlist %s.\n", filename);
+ cmd->success = false;
}
+}
- case MP_CMD_LOADLIST: {
- 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);
-
- if (!append && mpctx->playlist->first)
- mp_set_playlist_entry(mpctx, new ? new : mpctx->playlist->first);
+static void cmd_playlist_clear(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
- mp_wakeup_core(mpctx);
- } else {
- MP_ERR(mpctx, "Unable to load playlist %s.\n", filename);
- return -1;
+ // Supposed to clear the playlist, except the currently played item.
+ if (mpctx->playlist->current_was_replaced)
+ mpctx->playlist->current = NULL;
+ while (mpctx->playlist->first) {
+ struct playlist_entry *e = mpctx->playlist->first;
+ if (e == mpctx->playlist->current) {
+ e = e->next;
+ if (!e)
+ break;
}
- break;
+ playlist_remove(mpctx->playlist, e);
}
+ mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
+ mp_wakeup_core(mpctx);
+}
- case MP_CMD_PLAYLIST_CLEAR: {
- // Supposed to clear the playlist, except the currently played item.
- if (mpctx->playlist->current_was_replaced)
- mpctx->playlist->current = NULL;
- while (mpctx->playlist->first) {
- struct playlist_entry *e = mpctx->playlist->first;
- if (e == mpctx->playlist->current) {
- e = e->next;
- if (!e)
- break;
- }
- playlist_remove(mpctx->playlist, e);
- }
- mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
- mp_wakeup_core(mpctx);
- break;
- }
+static void cmd_playlist_remove(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_PLAYLIST_REMOVE: {
- struct playlist_entry *e = playlist_entry_from_index(mpctx->playlist,
- cmd->args[0].v.i);
- if (cmd->args[0].v.i < 0)
- e = mpctx->playlist->current;
- if (!e)
- return -1;
- // Can't play a removed entry
- if (mpctx->playlist->current == e && !mpctx->stop_play)
- mpctx->stop_play = PT_NEXT_ENTRY;
- playlist_remove(mpctx->playlist, e);
- mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
- mp_wakeup_core(mpctx);
- break;
+ struct playlist_entry *e = playlist_entry_from_index(mpctx->playlist,
+ cmd->args[0].v.i);
+ if (cmd->args[0].v.i < 0)
+ e = mpctx->playlist->current;
+ if (!e) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_PLAYLIST_MOVE: {
- struct playlist_entry *e1 = playlist_entry_from_index(mpctx->playlist,
- cmd->args[0].v.i);
- struct playlist_entry *e2 = playlist_entry_from_index(mpctx->playlist,
- cmd->args[1].v.i);
- if (!e1)
- return -1;
- playlist_move(mpctx->playlist, e1, e2);
- mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
- break;
+ // Can't play a removed entry
+ if (mpctx->playlist->current == e && !mpctx->stop_play)
+ mpctx->stop_play = PT_NEXT_ENTRY;
+ playlist_remove(mpctx->playlist, e);
+ mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
+ mp_wakeup_core(mpctx);
+}
+
+static void cmd_playlist_move(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ struct playlist_entry *e1 = playlist_entry_from_index(mpctx->playlist,
+ cmd->args[0].v.i);
+ struct playlist_entry *e2 = playlist_entry_from_index(mpctx->playlist,
+ cmd->args[1].v.i);
+ if (!e1) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_PLAYLIST_SHUFFLE: {
- playlist_shuffle(mpctx->playlist);
- mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
- break;
+ playlist_move(mpctx->playlist, e1, e2);
+ mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
+}
+
+static void cmd_playlist_shuffle(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ playlist_shuffle(mpctx->playlist);
+ mp_notify(mpctx, MP_EVENT_CHANGE_PLAYLIST, NULL);
+}
+
+static void cmd_stop(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ playlist_clear(mpctx->playlist);
+ if (mpctx->stop_play != PT_QUIT)
+ mpctx->stop_play = PT_STOP;
+ mp_wakeup_core(mpctx);
+}
+
+static void cmd_show_progress(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ mpctx->add_osd_seek_info |=
+ (cmd->msg_osd ? OSD_SEEK_INFO_TEXT : 0) |
+ (cmd->bar_osd ? OSD_SEEK_INFO_BAR : 0);
+ mpctx->osd_force_update = true;
+ mp_wakeup_core(mpctx);
+}
+
+static void cmd_tv_last_channel(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ if (!mpctx->demuxer) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_STOP:
- playlist_clear(mpctx->playlist);
- if (mpctx->stop_play != PT_QUIT)
- mpctx->stop_play = PT_STOP;
- mp_wakeup_core(mpctx);
- break;
+ demux_stream_control(mpctx->demuxer, STREAM_CTRL_TV_LAST_CHAN, NULL);
+}
- case MP_CMD_SHOW_PROGRESS:
- mpctx->add_osd_seek_info |=
- (msg_osd ? OSD_SEEK_INFO_TEXT : 0) |
- (bar_osd ? OSD_SEEK_INFO_BAR : 0);
- mpctx->osd_force_update = true;
- mp_wakeup_core(mpctx);
- break;
+static void cmd_track_add(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int type = *(int *)cmd->priv;
- case MP_CMD_TV_LAST_CHANNEL: {
- if (!mpctx->demuxer)
- return -1;
- demux_stream_control(mpctx->demuxer, STREAM_CTRL_TV_LAST_CHAN, NULL);
- break;
+ if (!mpctx->playing) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_SUB_ADD:
- case MP_CMD_AUDIO_ADD: {
- if (!mpctx->playing)
- return -1;
- int type = cmd->id == MP_CMD_SUB_ADD ? STREAM_SUB : STREAM_AUDIO;
- if (cmd->args[1].v.i == 2) {
- struct track *t = find_track_with_url(mpctx, type, cmd->args[0].v.s);
- if (t) {
- if (mpctx->playback_initialized) {
- mp_switch_track(mpctx, t->type, t, FLAG_MARK_SELECTION);
- print_track_list(mpctx, "Track switched:");
- } else {
- opts->stream_id[0][t->type] = t->user_tid;
- }
- return 0;
+ if (cmd->args[1].v.i == 2) {
+ struct track *t = find_track_with_url(mpctx, type, cmd->args[0].v.s);
+ if (t) {
+ if (mpctx->playback_initialized) {
+ mp_switch_track(mpctx, t->type, t, FLAG_MARK_SELECTION);
+ print_track_list(mpctx, "Track switched:");
+ } else {
+ mpctx->opts->stream_id[0][t->type] = t->user_tid;
}
+ return;
}
- int first = mp_add_external_file(mpctx, cmd->args[0].v.s, type);
- if (first < 0)
- return -1;
-
- for (int n = first; n < mpctx->num_tracks; n++) {
- struct track *t = mpctx->tracks[n];
- if (cmd->args[1].v.i == 1) {
- t->no_default = true;
- } else if (n == first) {
- if (mpctx->playback_initialized) {
- mp_switch_track(mpctx, t->type, t, FLAG_MARK_SELECTION);
- } else {
- opts->stream_id[0][t->type] = t->user_tid;
- }
+ }
+ int first = mp_add_external_file(mpctx, cmd->args[0].v.s, type);
+ if (first < 0) {
+ cmd->success = false;
+ return;
+ }
+
+ for (int n = first; n < mpctx->num_tracks; n++) {
+ struct track *t = mpctx->tracks[n];
+ if (cmd->args[1].v.i == 1) {
+ t->no_default = true;
+ } else if (n == first) {
+ if (mpctx->playback_initialized) {
+ mp_switch_track(mpctx, t->type, t, FLAG_MARK_SELECTION);
+ } else {
+ mpctx->opts->stream_id[0][t->type] = t->user_tid;
}
- char *title = cmd->args[2].v.s;
- if (title && title[0])
- t->title = talloc_strdup(t, title);
- char *lang = cmd->args[3].v.s;
- if (lang && lang[0])
- t->lang = talloc_strdup(t, lang);
}
-
- if (mpctx->playback_initialized)
- print_track_list(mpctx, "Track added:");
- break;
+ char *title = cmd->args[2].v.s;
+ if (title && title[0])
+ t->title = talloc_strdup(t, title);
+ char *lang = cmd->args[3].v.s;
+ if (lang && lang[0])
+ t->lang = talloc_strdup(t, lang);
}
- case MP_CMD_SUB_REMOVE:
- case MP_CMD_AUDIO_REMOVE: {
- int type = cmd->id == MP_CMD_SUB_REMOVE ? STREAM_SUB : STREAM_AUDIO;
- struct track *t = mp_track_by_tid(mpctx, type, cmd->args[0].v.i);
- if (!t)
- return -1;
- mp_remove_track(mpctx, t);
- if (mpctx->playback_initialized)
- print_track_list(mpctx, "Track removed:");
- break;
+ if (mpctx->playback_initialized)
+ print_track_list(mpctx, "Track added:");
+}
+
+static void cmd_track_remove(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int type = *(int *)cmd->priv;
+
+ struct track *t = mp_track_by_tid(mpctx, type, cmd->args[0].v.i);
+ if (!t) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_SUB_RELOAD:
- case MP_CMD_AUDIO_RELOAD: {
- if (!mpctx->playback_initialized) {
- MP_ERR(mpctx, "Cannot reload while not initialized.\n");
- return -1;
- }
- int type = cmd->id == MP_CMD_SUB_RELOAD ? STREAM_SUB : STREAM_AUDIO;
- struct track *t = mp_track_by_tid(mpctx, type, cmd->args[0].v.i);
- int nt_num = -1;
- if (t && t->is_external && t->external_filename) {
- char *filename = talloc_strdup(NULL, t->external_filename);
- mp_remove_track(mpctx, t);
- nt_num = mp_add_external_file(mpctx, filename, type);
- talloc_free(filename);
- }
- if (nt_num >= 0) {
- struct track *nt = mpctx->tracks[nt_num];
- mp_switch_track(mpctx, nt->type, nt, 0);
- print_track_list(mpctx, "Reloaded:");
- return 0;
- }
- return -1;
+ mp_remove_track(mpctx, t);
+ if (mpctx->playback_initialized)
+ print_track_list(mpctx, "Track removed:");
+}
+
+static void cmd_track_reload(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int type = *(int *)cmd->priv;
+
+ if (!mpctx->playback_initialized) {
+ MP_ERR(mpctx, "Cannot reload while not initialized.\n");
+ cmd->success = false;
+ return;
}
- case MP_CMD_RESCAN_EXTERNAL_FILES: {
- if (!mpctx->playing)
- return -1;
- autoload_external_files(mpctx);
- if (cmd->args[0].v.i && mpctx->playback_initialized) {
- // somewhat fuzzy and not ideal
- struct track *a = select_default_track(mpctx, 0, STREAM_AUDIO);
- if (a && a->is_external)
- mp_switch_track(mpctx, STREAM_AUDIO, a, 0);
- struct track *s = select_default_track(mpctx, 0, STREAM_SUB);
- if (s && s->is_external)
- mp_switch_track(mpctx, STREAM_SUB, s, 0);
-
- print_track_list(mpctx, "Track list:\n");
- }
- break;
+ struct track *t = mp_track_by_tid(mpctx, type, cmd->args[0].v.i);
+ int nt_num = -1;
+
+ if (t && t->is_external && t->external_filename) {
+ char *filename = talloc_strdup(NULL, t->external_filename);
+ mp_remove_track(mpctx, t);
+ nt_num = mp_add_external_file(mpctx, filename, type);
+ talloc_free(filename);
}
- case MP_CMD_SCREENSHOT: {
- int mode = cmd->args[0].v.i & 3;
- int freq = (cmd->args[0].v.i | cmd->args[1].v.i) >> 3;
- screenshot_request(mpctx, mode, freq, msg_osd, async);
- break;
+ if (nt_num < 0) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_SCREENSHOT_TO_FILE:
- screenshot_to_file(mpctx, cmd->args[0].v.s, cmd->args[1].v.i, msg_osd,
- async);
- break;
+ struct track *nt = mpctx->tracks[nt_num];
+ mp_switch_track(mpctx, nt->type, nt, 0);
+ print_track_list(mpctx, "Reloaded:");
+}
- case MP_CMD_SCREENSHOT_RAW: {
- if (!res)
- return -1;
- struct mp_image *img = screenshot_get_rgb(mpctx, cmd->args[0].v.i);
- if (!img)
- return -1;
- node_init(res, MPV_FORMAT_NODE_MAP, NULL);
- node_map_add_int64(res, "w", img->w);
- node_map_add_int64(res, "h", img->h);
- node_map_add_int64(res, "stride", img->stride[0]);
- node_map_add_string(res, "format", "bgr0");
- struct mpv_byte_array *ba =
- node_map_add(res, "data", MPV_FORMAT_BYTE_ARRAY)->u.ba;
- *ba = (struct mpv_byte_array){
- .data = img->planes[0],
- .size = img->stride[0] * img->h,
- };
- talloc_steal(ba, img);
- break;
+static void cmd_rescan_external_files(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ if (!mpctx->playing) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_RUN: {
- char **args = talloc_zero_array(NULL, char *, cmd->nargs + 1);
- for (int n = 0; n < cmd->nargs; n++)
- args[n] = cmd->args[n].v.s;
- mp_subprocess_detached(mpctx->log, args);
- talloc_free(args);
- break;
+ autoload_external_files(mpctx);
+ if (cmd->args[0].v.i && mpctx->playback_initialized) {
+ // somewhat fuzzy and not ideal
+ struct track *a = select_default_track(mpctx, 0, STREAM_AUDIO);
+ if (a && a->is_external)
+ mp_switch_track(mpctx, STREAM_AUDIO, a, 0);
+ struct track *s = select_default_track(mpctx, 0, STREAM_SUB);
+ if (s && s->is_external)
+ mp_switch_track(mpctx, STREAM_SUB, s, 0);
+
+ print_track_list(mpctx, "Track list:\n");
}
+}
- case MP_CMD_ENABLE_INPUT_SECTION:
- mp_input_enable_section(mpctx->input, cmd->args[0].v.s, cmd->args[1].v.i);
- break;
+static void cmd_screenshot(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ bool async = cmd->cmd->flags & MP_ASYNC_CMD;
+ int mode = cmd->args[0].v.i & 3;
+ int freq = (cmd->args[0].v.i | cmd->args[1].v.i) >> 3;
+ screenshot_request(mpctx, mode, freq, cmd->msg_osd, async);
+}
- case MP_CMD_DISABLE_INPUT_SECTION:
- mp_input_disable_section(mpctx->input, cmd->args[0].v.s);
- break;
+static void cmd_screenshot_to_file(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ bool async = cmd->cmd->flags & MP_ASYNC_CMD;
+ screenshot_to_file(mpctx, cmd->args[0].v.s, cmd->args[1].v.i, cmd->msg_osd,
+ async);
+}
- case MP_CMD_DEFINE_INPUT_SECTION:
- mp_input_define_section(mpctx->input, cmd->args[0].v.s, "<api>",
- cmd->args[1].v.s, !!cmd->args[2].v.i,
- cmd->sender);
- break;
+static void cmd_screenshot_raw(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ struct mpv_node *res = cmd->result;
- case MP_CMD_AB_LOOP: {
- double now = get_current_time(mpctx);
- if (opts->ab_loop[0] == MP_NOPTS_VALUE) {
- mp_property_do("ab-loop-a", M_PROPERTY_SET, &now, mpctx);
- show_property_osd(mpctx, "ab-loop-a", on_osd);
- } else if (opts->ab_loop[1] == MP_NOPTS_VALUE) {
- mp_property_do("ab-loop-b", M_PROPERTY_SET, &now, mpctx);
- show_property_osd(mpctx, "ab-loop-b", on_osd);
- } else {
- now = MP_NOPTS_VALUE;
- mp_property_do("ab-loop-a", M_PROPERTY_SET, &now, mpctx);
- mp_property_do("ab-loop-b", M_PROPERTY_SET, &now, mpctx);
- set_osd_msg(mpctx, osdl, osd_duration, "Clear A-B loop");
- }
- break;
+ struct mp_image *img = screenshot_get_rgb(mpctx, cmd->args[0].v.i);
+ if (!img) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_DROP_BUFFERS: {
- reset_audio_state(mpctx);
- reset_video_state(mpctx);
+ node_init(res, MPV_FORMAT_NODE_MAP, NULL);
+ node_map_add_int64(res, "w", img->w);
+ node_map_add_int64(res, "h", img->h);
+ node_map_add_int64(res, "stride", img->stride[0]);
+ node_map_add_string(res, "format", "bgr0");
+ struct mpv_byte_array *ba =
+ node_map_add(res, "data", MPV_FORMAT_BYTE_ARRAY)->u.ba;
+ *ba = (struct mpv_byte_array){
+ .data = img->planes[0],
+ .size = img->stride[0] * img->h,
+ };
+ talloc_steal(ba, img);
+}
- if (mpctx->demuxer)
- demux_flush(mpctx->demuxer);
+static void cmd_run(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ char **args = talloc_zero_array(NULL, char *, cmd->num_args + 1);
+ for (int n = 0; n < cmd->num_args; n++)
+ args[n] = cmd->args[n].v.s;
+ mp_subprocess_detached(mpctx->log, args);
+ talloc_free(args);
+}
- break;
+static void cmd_enable_input_section(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ mp_input_enable_section(mpctx->input, cmd->args[0].v.s, cmd->args[1].v.i);
+}
+
+static void cmd_disable_input_section(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ mp_input_disable_section(mpctx->input, cmd->args[0].v.s);
+}
+
+static void cmd_define_input_section(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ mp_input_define_section(mpctx->input, cmd->args[0].v.s, "<api>",
+ cmd->args[1].v.s, !!cmd->args[2].v.i,
+ cmd->cmd->sender);
+}
+
+static void cmd_ab_loop(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int osd_duration = mpctx->opts->osd_duration;
+ int osdl = cmd->msg_osd ? 1 : OSD_LEVEL_INVISIBLE;
+
+ double now = get_current_time(mpctx);
+ if (mpctx->opts->ab_loop[0] == MP_NOPTS_VALUE) {
+ mp_property_do("ab-loop-a", M_PROPERTY_SET, &now, mpctx);
+ show_property_osd(mpctx, "ab-loop-a", cmd->on_osd);
+ } else if (mpctx->opts->ab_loop[1] == MP_NOPTS_VALUE) {
+ mp_property_do("ab-loop-b", M_PROPERTY_SET, &now, mpctx);
+ show_property_osd(mpctx, "ab-loop-b", cmd->on_osd);
+ } else {
+ now = MP_NOPTS_VALUE;
+ mp_property_do("ab-loop-a", M_PROPERTY_SET, &now, mpctx);
+ mp_property_do("ab-loop-b", M_PROPERTY_SET, &now, mpctx);
+ set_osd_msg(mpctx, osdl, osd_duration, "Clear A-B loop");
}
+}
- case MP_CMD_AO_RELOAD:
- reload_audio_output(mpctx);
- break;
+static void cmd_drop_buffers(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_AF:
- return edit_filters_osd(mpctx, STREAM_AUDIO, cmd->args[0].v.s,
- cmd->args[1].v.s, msg_osd);
+ reset_audio_state(mpctx);
+ reset_video_state(mpctx);
- case MP_CMD_VF:
- return edit_filters_osd(mpctx, STREAM_VIDEO, cmd->args[0].v.s,
- cmd->args[1].v.s, msg_osd);
+ if (mpctx->demuxer)
+ demux_flush(mpctx->demuxer);
+}
- case MP_CMD_AF_COMMAND:
- case MP_CMD_VF_COMMAND: {
- struct mp_output_chain *chain = NULL;
- if (cmd->id == MP_CMD_VF_COMMAND) {
- chain = mpctx->vo_chain ? mpctx->vo_chain->filter : NULL;
- } else {
- chain = mpctx->ao_chain ? mpctx->ao_chain->filter : NULL;
- }
- if (!chain)
- return -1;
- struct mp_filter_command filter_cmd = {
- .type = MP_FILTER_COMMAND_TEXT,
- .cmd = cmd->args[1].v.s,
- .arg = cmd->args[2].v.s,
- };
- return mp_output_chain_command(chain, cmd->args[0].v.s, &filter_cmd)
- ? 0 : -1;
- }
-
- case MP_CMD_SCRIPT_BINDING: {
- mpv_event_client_message event = {0};
- char *name = cmd->args[0].v.s;
- if (!name || !name[0])
- return -1;
- char *sep = strchr(name, '/');
- char *target = NULL;
- char space[MAX_CLIENT_NAME];
- if (sep) {
- snprintf(space, sizeof(space), "%.*s", (int)(sep - name), name);
- target = space;
- name = sep + 1;
- }
- char state[3] = {'p', cmd->is_mouse_button ? 'm' : '-'};
- if (cmd->is_up_down)
- state[0] = cmd->repeated ? 'r' : (cmd->is_up ? 'u' : 'd');
- event.num_args = 4;
- event.args = (const char*[4]){"key-binding", name, state,
- cmd->key_name ? cmd->key_name : ""};
- if (mp_client_send_event_dup(mpctx, target,
- MPV_EVENT_CLIENT_MESSAGE, &event) < 0)
- {
- MP_VERBOSE(mpctx, "Can't find script '%s' when handling input.\n",
- target ? target : "-");
- return -1;
- }
- break;
+static void cmd_ao_reload(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ reload_audio_output(mpctx);
+}
+
+static void cmd_filter(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int type = *(int *)cmd->priv;
+ cmd->success = edit_filters_osd(mpctx, type, cmd->args[0].v.s,
+ cmd->args[1].v.s, cmd->msg_osd) >= 0;
+}
+
+static void cmd_filter_command(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int type = *(int *)cmd->priv;
+
+ struct mp_output_chain *chain = NULL;
+ if (type == STREAM_VIDEO)
+ chain = mpctx->vo_chain ? mpctx->vo_chain->filter : NULL;
+ if (type == STREAM_AUDIO)
+ chain = mpctx->ao_chain ? mpctx->ao_chain->filter : NULL;
+ if (!chain) {
+ cmd->success = false;
+ return;
}
+ struct mp_filter_command filter_cmd = {
+ .type = MP_FILTER_COMMAND_TEXT,
+ .cmd = cmd->args[1].v.s,
+ .arg = cmd->args[2].v.s,
+ };
+ cmd->success = mp_output_chain_command(chain, cmd->args[0].v.s, &filter_cmd);
+}
- case MP_CMD_SCRIPT_MESSAGE_TO: {
- mpv_event_client_message *event = talloc_ptrtype(NULL, event);
- *event = (mpv_event_client_message){0};
- for (int n = 1; n < cmd->nargs; n++) {
- MP_TARRAY_APPEND(event, event->args, event->num_args,
- talloc_strdup(event, cmd->args[n].v.s));
- }
- if (mp_client_send_event(mpctx, cmd->args[0].v.s, 0,
- MPV_EVENT_CLIENT_MESSAGE, event) < 0)
- {
- MP_VERBOSE(mpctx, "Can't find script '%s' for %s.\n",
- cmd->args[0].v.s, cmd->name);
- return -1;
- }
- break;
+static void cmd_script_binding(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct mp_cmd *incmd = cmd->cmd;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ mpv_event_client_message event = {0};
+ char *name = cmd->args[0].v.s;
+ if (!name || !name[0]) {
+ cmd->success = false;
+ return;
}
- case MP_CMD_SCRIPT_MESSAGE: {
- const char **args = talloc_array(NULL, const char *, cmd->nargs);
- mpv_event_client_message event = {.args = args};
- for (int n = 0; n < cmd->nargs; n++)
- event.args[event.num_args++] = cmd->args[n].v.s;
- mp_client_broadcast_event(mpctx, MPV_EVENT_CLIENT_MESSAGE, &event);
- talloc_free(args);
- break;
+
+ char *sep = strchr(name, '/');
+ char *target = NULL;
+ char space[MAX_CLIENT_NAME];
+ if (sep) {
+ snprintf(space, sizeof(space), "%.*s", (int)(sep - name), name);
+ target = space;
+ name = sep + 1;
+ }
+ char state[3] = {'p', incmd->is_mouse_button ? 'm' : '-'};
+ if (incmd->is_up_down)
+ state[0] = incmd->repeated ? 'r' : (incmd->is_up ? 'u' : 'd');
+ event.num_args = 4;
+ event.args = (const char*[4]){"key-binding", name, state,
+ incmd->key_name ? incmd->key_name : ""};
+ if (mp_client_send_event_dup(mpctx, target,
+ MPV_EVENT_CLIENT_MESSAGE, &event) < 0)
+ {
+ MP_VERBOSE(mpctx, "Can't find script '%s' when handling input.\n",
+ target ? target : "-");
+ cmd->success = false;
}
+}
- case MP_CMD_OVERLAY_ADD:
- overlay_add(mpctx,
- cmd->args[0].v.i, cmd->args[1].v.i, cmd->args[2].v.i,
- cmd->args[3].v.s, cmd->args[4].v.i, cmd->args[5].v.s,
- cmd->args[6].v.i, cmd->args[7].v.i, cmd->args[8].v.i);
- break;
+static void cmd_script_message_to(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_OVERLAY_REMOVE:
- overlay_remove(mpctx, cmd->args[0].v.i);
- break;
+ mpv_event_client_message *event = talloc_ptrtype(NULL, event);
+ *event = (mpv_event_client_message){0};
+ for (int n = 1; n < cmd->num_args; n++) {
+ MP_TARRAY_APPEND(event, event->args, event->num_args,
+ talloc_strdup(event, cmd->args[n].v.s));
+ }
+ if (mp_client_send_event(mpctx, cmd->args[0].v.s, 0,
+ MPV_EVENT_CLIENT_MESSAGE, event) < 0)
+ {
+ MP_VERBOSE(mpctx, "Can't find script '%s' to send message to.\n",
+ cmd->args[0].v.s);
+ cmd->success = false;
+ }
+}
- case MP_CMD_COMMAND_LIST: {
- for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next)
- run_command(mpctx, sub, NULL);
- break;
+static void cmd_script_message(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ const char **args = talloc_array(NULL, const char *, cmd->num_args);
+ mpv_event_client_message event = {.args = args};
+ for (int n = 0; n < cmd->num_args; n++)
+ event.args[event.num_args++] = cmd->args[n].v.s;
+ mp_client_broadcast_event(mpctx, MPV_EVENT_CLIENT_MESSAGE, &event);
+ talloc_free(args);
+}
+
+static void cmd_ignore(void *p)
+{
+}
+
+static void cmd_write_watch_later_config(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ mp_write_watch_later_conf(mpctx);
+}
+
+static void cmd_hook_add(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+
+ if (!cmd->cmd->sender) {
+ MP_ERR(mpctx, "Can be used from client API only.\n");
+ cmd->success = false;
+ return;
}
+ mp_hook_add(mpctx, cmd->cmd->sender, cmd->args[0].v.s, cmd->args[1].v.i,
+ cmd->args[2].v.i, true);
+}
- case MP_CMD_IGNORE:
- break;
+static void cmd_hook_ack(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_WRITE_WATCH_LATER_CONFIG: {
- mp_write_watch_later_conf(mpctx);
- break;
+ if (!cmd->cmd->sender) {
+ MP_ERR(mpctx, "Can be used from client API only.\n");
+ cmd->success = false;
+ return;
}
+ mp_hook_continue(mpctx, cmd->cmd->sender, cmd->args[0].v.i);
+}
- case MP_CMD_HOOK_ADD:
- if (!cmd->sender) {
- MP_ERR(mpctx, "Can be used from client API only.\n");
- return -1;
- }
- mp_hook_add(mpctx, cmd->sender, cmd->args[0].v.s, cmd->args[1].v.i,
- cmd->args[2].v.i, true);
- break;
- case MP_CMD_HOOK_ACK:
- if (!cmd->sender) {
- MP_ERR(mpctx, "Can be used from client API only.\n");
- return -1;
- }
- mp_hook_continue(mpctx, cmd->sender, cmd->args[0].v.i);
- break;
+static void cmd_mouse(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_MOUSE: {
- const int x = cmd->args[0].v.i, y = cmd->args[1].v.i;
- int button = cmd->args[2].v.i;
- if (button == -1) {// no button
- mp_input_set_mouse_pos_artificial(mpctx->input, x, y);
- break;
- }
- if (button < 0 || button >= 20) {// invalid button
- MP_ERR(mpctx, "%d is not a valid mouse button number.\n", button);
- return -1;
- }
- const bool dbc = cmd->args[3].v.i;
- if (dbc && button > (MP_MBTN_RIGHT - MP_MBTN_BASE)) {
- MP_ERR(mpctx, "%d is not a valid mouse button for double-clicks.\n",
- button);
- return -1;
- }
- button += dbc ? MP_MBTN_DBL_BASE : MP_MBTN_BASE;
+ const int x = cmd->args[0].v.i, y = cmd->args[1].v.i;
+ int button = cmd->args[2].v.i;
+ if (button == -1) {// no button
mp_input_set_mouse_pos_artificial(mpctx->input, x, y);
- mp_input_put_key_artificial(mpctx->input, button);
- break;
+ return;
}
+ if (button < 0 || button >= 20) {// invalid button
+ MP_ERR(mpctx, "%d is not a valid mouse button number.\n", button);
+ cmd->success = false;
+ return;
+ }
+ const bool dbc = cmd->args[3].v.i;
+ if (dbc && button > (MP_MBTN_RIGHT - MP_MBTN_BASE)) {
+ MP_ERR(mpctx, "%d is not a valid mouse button for double-clicks.\n",
+ button);
+ cmd->success = false;
+ return;
+ }
+ button += dbc ? MP_MBTN_DBL_BASE : MP_MBTN_BASE;
+ mp_input_set_mouse_pos_artificial(mpctx->input, x, y);
+ mp_input_put_key_artificial(mpctx->input, button);
+}
+
+static void cmd_key(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
+ int action = *(int *)cmd->priv;
- case MP_CMD_KEYPRESS:
- case MP_CMD_KEYDOWN: {
- const char *key_name = cmd->args[0].v.s;
+ const char *key_name = cmd->args[0].v.s;
+ if (key_name[0] == '\0' && action == MP_KEY_STATE_UP) {
+ mp_input_put_key_artificial(mpctx->input, MP_INPUT_RELEASE_ALL);
+ } else {
int code = mp_input_get_key_from_name(key_name);
if (code < 0) {
MP_ERR(mpctx, "%s is not a valid input name.\n", key_name);
- return -1;
+ cmd->success = false;
+ return;
}
- if (cmd->id == MP_CMD_KEYDOWN)
- code |= MP_KEY_STATE_DOWN;
-
- mp_input_put_key_artificial(mpctx->input, code);
- break;
+ mp_input_put_key_artificial(mpctx->input, code | action);
}
+}
- case MP_CMD_KEYUP: {
- const char *key_name = cmd->args[0].v.s;
- if (key_name[0] == '\0') {
- mp_input_put_key_artificial(mpctx->input, MP_INPUT_RELEASE_ALL);
- } else {
- int code = mp_input_get_key_from_name(key_name);
- if (code < 0) {
- MP_ERR(mpctx, "%s is not a valid input name.\n", key_name);
- return -1;
- }
- mp_input_put_key_artificial(mpctx->input, code | MP_KEY_STATE_UP);
- }
- break;
- }
+static void cmd_apply_profile(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- case MP_CMD_APPLY_PROFILE: {
- char *profile = cmd->args[0].v.s;
- if (m_config_set_profile(mpctx->mconfig, profile, M_SETOPT_RUNTIME) < 0)
- return -1;
- break;
- }
+ char *profile = cmd->args[0].v.s;
+ if (m_config_set_profile(mpctx->mconfig, profile, M_SETOPT_RUNTIME) < 0)
+ cmd->success = false;
+}
- case MP_CMD_LOAD_SCRIPT: {
- char *script = cmd->args[0].v.s;
- if (mp_load_user_script(mpctx, script) < 0)
- return -1;
- break;
- }
+static void cmd_load_script(void *p)
+{
+ struct mp_cmd_ctx *cmd = p;
+ struct MPContext *mpctx = cmd->mpctx;
- default:
- MP_VERBOSE(mpctx, "Received unknown cmd %s\n", cmd->name);
- return -1;
- }
- return 0;
+ char *script = cmd->args[0].v.s;
+ if (mp_load_user_script(mpctx, script) < 0)
+ cmd->success = false;
}
-
// This does not specify the real destination of the command parameter values,
// it just provides a dummy for the OPT_ macros.
#define OPT_BASE_STRUCT struct mp_cmd_arg
@@ -5645,9 +5846,9 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
#define OARG_CYCLEDIR(def) OPT_CYCLEDIR(ARG(d), 0, OPTDEF_DOUBLE(def))
const struct mp_cmd_def mp_cmds[] = {
- { MP_CMD_IGNORE, "ignore", .is_ignore = true },
+ { "ignore", cmd_ignore, .is_ignore = true },
- { MP_CMD_SEEK, "seek", {
+ { "seek", cmd_seek, {
ARG_TIME,
OARG_FLAGS(4|0, ({"relative", 4|0}, {"-", 4|0},
{"absolute-percent", 4|1},
@@ -5663,46 +5864,54 @@ const struct mp_cmd_def mp_cmds[] = {
.allow_auto_repeat = true,
.scalable = true,
},
- { MP_CMD_REVERT_SEEK, "revert-seek", {
+ { "revert-seek", cmd_revert_seek, {
OARG_FLAGS(0, ({"mark", 1})),
}},
- { MP_CMD_QUIT, "quit", { OARG_INT(0) },
- .is_abort = true },
- { MP_CMD_QUIT_WATCH_LATER, "quit-watch-later", { OARG_INT(0) },
- .is_abort = true },
- { MP_CMD_STOP, "stop", .is_abort = true },
- { MP_CMD_FRAME_STEP, "frame-step", .allow_auto_repeat = true,
+ { "quit", cmd_quit, { OARG_INT(0) },
+ .priv = &(const bool){0}, .is_abort = true },
+ { "quit-watch-later", cmd_quit, { OARG_INT(0) },
+ .priv = &(const bool){1}, .is_abort = true },
+ { "stop", cmd_stop, .is_abort = true },
+ { "frame-step", cmd_frame_step, .allow_auto_repeat = true,
.on_updown = true },
- { MP_CMD_FRAME_BACK_STEP, "frame-back-step", .allow_auto_repeat = true },
- { MP_CMD_PLAYLIST_NEXT, "playlist-next", {
+ { "frame-back-step", cmd_frame_back_step, .allow_auto_repeat = true },
+ { "playlist-next", cmd_playlist_next_prev, {
OARG_CHOICE(0, ({"weak", 0},
{"force", 1})),
},
- .is_soft_abort = true,
+ .is_soft_abort = true, .priv = &(const int){1},
},
- { MP_CMD_PLAYLIST_PREV, "playlist-prev", {
+ { "playlist-prev", cmd_playlist_next_prev, {
OARG_CHOICE(0, ({"weak", 0},
{"force", 1})),
},
- .is_soft_abort = true,
+ .is_soft_abort = true, .priv = &(const int){-1},
},
- { MP_CMD_PLAYLIST_SHUFFLE, "playlist-shuffle", },
- { MP_CMD_SUB_STEP, "sub-step", { ARG_INT }, .allow_auto_repeat = true },
- { MP_CMD_SUB_SEEK, "sub-seek", { ARG_INT }, .allow_auto_repeat = true },
- { MP_CMD_PRINT_TEXT, "print-text", { ARG_STRING }, .allow_auto_repeat = true },
- { MP_CMD_SHOW_TEXT, "show-text", { ARG_STRING, OARG_INT(-1), OARG_INT(0) },
+ { "playlist-shuffle", cmd_playlist_shuffle, },
+ { "sub-step", cmd_sub_step_seek, { ARG_INT }, .allow_auto_repeat = true,
+ .priv = &(const bool){true} },
+ { "sub-seek", cmd_sub_step_seek, { ARG_INT }, .allow_auto_repeat = true,
+ .priv = &(const bool){false} },
+ { "print-text", cmd_print_text, { ARG_STRING }, .allow_auto_repeat = true },
+ { "show-text", cmd_show_text, { ARG_STRING, OARG_INT(-1), OARG_INT(0) },
.allow_auto_repeat = true},
- { MP_CMD_EXPAND_TEXT, "expand-text", { ARG_STRING } },
- { MP_CMD_SHOW_PROGRESS, "show-progress", .allow_auto_repeat = true},
- { MP_CMD_SUB_ADD, "sub-add", { ARG_STRING,
- OARG_CHOICE(0, ({"select", 0}, {"auto", 1}, {"cached", 2})),
- OARG_STRING(""), OARG_STRING("") } },
- { MP_CMD_SUB_REMOVE, "sub-remove", { OARG_INT(-1) } },
- { MP_CMD_SUB_RELOAD, "sub-reload", { OARG_INT(-1) } },
+ { "expand-text", cmd_expand_text, { ARG_STRING } },
+ { "show-progress", cmd_show_progress, .allow_auto_repeat = true},
+ { "sub-add", cmd_track_add, {
+ ARG_STRING,
+ OARG_CHOICE(0, ({"select", 0}, {"auto", 1}, {"cached", 2})),
+ OARG_STRING(""), OARG_STRING(""),
+ },
+ .priv = &(const int){STREAM_SUB},
+ },
+ { "sub-remove", cmd_track_remove, { OARG_INT(-1) },
+ .priv = &(const int){STREAM_SUB}, },
+ { "sub-reload", cmd_track_reload, { OARG_INT(-1) },
+ .priv = &(const int){STREAM_SUB}, },
- { MP_CMD_TV_LAST_CHANNEL, "tv-last-channel", },
+ { "tv-last-channel", cmd_tv_last_channel, },
- { MP_CMD_SCREENSHOT, "screenshot", {
+ { "screenshot", cmd_screenshot, {
OARG_FLAGS(4|2, ({"video", 4|0}, {"-", 4|0},
{"window", 4|1},
{"subtitles", 4|2},
@@ -5711,122 +5920,133 @@ const struct mp_cmd_def mp_cmds[] = {
OARG_CHOICE(0, ({"unused", 0}, {"single", 0},
{"each-frame", 8})),
}},
- { MP_CMD_SCREENSHOT_TO_FILE, "screenshot-to-file", {
+ { "screenshot-to-file", cmd_screenshot_to_file, {
ARG_STRING,
OARG_CHOICE(2, ({"video", 0},
{"window", 1},
{"subtitles", 2})),
}},
- { MP_CMD_SCREENSHOT_RAW, "screenshot-raw", {
+ { "screenshot-raw", cmd_screenshot_raw, {
OARG_CHOICE(2, ({"video", 0},
{"window", 1},
{"subtitles", 2})),
}},
- { MP_CMD_LOADFILE, "loadfile", {
+ { "loadfile", cmd_loadfile, {
ARG_STRING,
OARG_CHOICE(0, ({"replace", 0},
{"append", 1},
{"append-play", 2})),
OPT_KEYVALUELIST(ARG(str_list), MP_CMD_OPT_ARG),
}},
- { MP_CMD_LOADLIST, "loadlist", {
+ { "loadlist", cmd_loadlist, {
ARG_STRING,
OARG_CHOICE(0, ({"replace", 0},
{"append", 1})),
}},
- { MP_CMD_PLAYLIST_CLEAR, "playlist-clear", },
- { MP_CMD_PLAYLIST_REMOVE, "playlist-remove", {
+ { "playlist-clear", cmd_playlist_clear },
+ { "playlist-remove", cmd_playlist_remove, {
ARG_CHOICE_OR_INT(0, INT_MAX, ({"current", -1})),
}},
- { MP_CMD_PLAYLIST_MOVE, "playlist-move", { ARG_INT, ARG_INT } },
- { MP_CMD_RUN, "run", { ARG_STRING, ARG_STRING }, .vararg = true },
+ { "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } },
+ { "run", cmd_run, { ARG_STRING, ARG_STRING }, .vararg = true },
- { MP_CMD_SET, "set", { ARG_STRING, ARG_STRING } },
- { MP_CMD_CHANGE_LIST, "change-list", { ARG_STRING, ARG_STRING, ARG_STRING } },
- { MP_CMD_ADD, "add", { ARG_STRING, OARG_DOUBLE(1) },
+ { "set", cmd_set, { ARG_STRING, ARG_STRING } },
+ { "change-list", cmd_change_list, { ARG_STRING, ARG_STRING, ARG_STRING } },
+ { "add", cmd_add_cycle, { ARG_STRING, OARG_DOUBLE(1) },
.allow_auto_repeat = true,
.scalable = true,
},
- { MP_CMD_CYCLE, "cycle", {
- ARG_STRING,
- OARG_CYCLEDIR(1),
+ { "cycle", cmd_add_cycle, {
+ ARG_STRING,
+ OARG_CYCLEDIR(1),
},
.allow_auto_repeat = true,
.scalable = true,
+ .priv = "",
},
- { MP_CMD_MULTIPLY, "multiply", { ARG_STRING, ARG_DOUBLE },
+ { "multiply", cmd_multiply, { ARG_STRING, ARG_DOUBLE },
.allow_auto_repeat = true},
- { MP_CMD_CYCLE_VALUES, "cycle-values", { ARG_STRING, ARG_STRING, ARG_STRING },
+ { "cycle-values", cmd_cycle_values, { ARG_STRING, ARG_STRING, ARG_STRING },
.vararg = true},
- { MP_CMD_ENABLE_INPUT_SECTION, "enable-section", {
+ { "enable-section", cmd_enable_input_section, {
ARG_STRING,
OARG_FLAGS(0, ({"default", 0},
{"exclusive", MP_INPUT_EXCLUSIVE},
{"allow-hide-cursor", MP_INPUT_ALLOW_HIDE_CURSOR},
{"allow-vo-dragging", MP_INPUT_ALLOW_VO_DRAGGING})),
}},
- { MP_CMD_DISABLE_INPUT_SECTION, "disable-section", { ARG_STRING } },
- { MP_CMD_DEFINE_INPUT_SECTION, "define-section", {
+ { "disable-section", cmd_disable_input_section, { ARG_STRING } },
+ { "define-section", cmd_define_input_section, {
ARG_STRING,
ARG_STRING,
OARG_CHOICE(1, ({"default", 1},
{"force", 0})),
}},
- { MP_CMD_AB_LOOP, "ab-loop", },
+ { "ab-loop", cmd_ab_loop },
- { MP_CMD_DROP_BUFFERS, "drop-buffers", },
+ { "drop-buffers", cmd_drop_buffers, },
- { MP_CMD_AF, "af", { ARG_STRING, ARG_STRING } },
- { MP_CMD_AF_COMMAND, "af-command", { ARG_STRING, ARG_STRING, ARG_STRING } },
- { MP_CMD_AO_RELOAD, "ao-reload", },
+ { "af", cmd_filter, { ARG_STRING, ARG_STRING },
+ .priv = &(const int){STREAM_AUDIO}, },
+ { "af-command", cmd_filter_command, { ARG_STRING, ARG_STRING, ARG_STRING },
+ .priv = &(const int){STREAM_AUDIO}, },
+ { "ao-reload", cmd_ao_reload },
- { MP_CMD_VF, "vf", { ARG_STRING, ARG_STRING } },
- { MP_CMD_VF_COMMAND, "vf-command", { ARG_STRING, ARG_STRING, ARG_STRING } },
+ { "vf", cmd_filter, { ARG_STRING, ARG_STRING },
+ .priv = &(const int){STREAM_VIDEO}, },
+ { "vf-command", cmd_filter_command, { ARG_STRING, ARG_STRING, ARG_STRING },
+ .priv = &(const int){STREAM_VIDEO}, },
- { MP_CMD_SCRIPT_BINDING, "script-binding", { ARG_STRING },
+ { "script-binding", cmd_script_binding, { ARG_STRING },
.allow_auto_repeat = true, .on_updown = true},
- { MP_CMD_SCRIPT_MESSAGE, "script-message", { ARG_STRING }, .vararg = true },
- { MP_CMD_SCRIPT_MESSAGE_TO, "script-message-to", { ARG_STRING, ARG_STRING },
+ { "script-message", cmd_script_message, { ARG_STRING }, .vararg = true },
+ { "script-message-to", cmd_script_message_to, { ARG_STRING, ARG_STRING },
.vararg = true },
- { MP_CMD_OVERLAY_ADD, "overlay-add",
+ { "overlay-add", cmd_overlay_add,
{ ARG_INT, ARG_INT, ARG_INT, ARG_STRING, ARG_INT, ARG_STRING, ARG_INT,
ARG_INT, ARG_INT }},
- { MP_CMD_OVERLAY_REMOVE, "overlay-remove", { ARG_INT } },
+ { "overlay-remove", cmd_overlay_remove, { ARG_INT } },
- { MP_CMD_WRITE_WATCH_LATER_CONFIG, "write-watch-later-config", },
+ { "write-watch-later-config", cmd_write_watch_later_config },
- { MP_CMD_HOOK_ADD, "hook-add", { ARG_STRING, ARG_INT, ARG_INT } },
- { MP_CMD_HOOK_ACK, "hook-ack", { ARG_INT } },
+ { "hook-add", cmd_hook_add, { ARG_STRING, ARG_INT, ARG_INT } },
+ { "hook-ack", cmd_hook_ack, { ARG_INT } },
- { MP_CMD_MOUSE, "mouse", {
+ { "mouse", cmd_mouse, {
ARG_INT, ARG_INT, // coordinate (x, y)
OARG_INT(-1), // button number
OARG_CHOICE(0, ({"single", 0},
{"double", 1})),
}},
- { MP_CMD_KEYPRESS, "keypress", { ARG_STRING } },
- { MP_CMD_KEYDOWN, "keydown", { ARG_STRING } },
- { MP_CMD_KEYUP, "keyup", { OARG_STRING("") } },
-
- { MP_CMD_AUDIO_ADD, "audio-add", { ARG_STRING,
- OARG_CHOICE(0, ({"select", 0}, {"auto", 1}, {"cached", 2})),
- OARG_STRING(""), OARG_STRING("") } },
- { MP_CMD_AUDIO_REMOVE, "audio-remove", { OARG_INT(-1) } },
- { MP_CMD_AUDIO_RELOAD, "audio-reload", { OARG_INT(-1) } },
+ { "keypress", cmd_key, { ARG_STRING }, .priv = &(const int){0}},
+ { "keydown", cmd_key, { ARG_STRING }, .priv = &(const int){MP_KEY_STATE_DOWN}},
+ { "keyup", cmd_key, { OARG_STRING("") }, .priv = &(const int){MP_KEY_STATE_UP}},
+
+ { "audio-add", cmd_track_add, {
+ ARG_STRING,
+ OARG_CHOICE(0, ({"select", 0}, {"auto", 1}, {"cached", 2})),
+ OARG_STRING(""), OARG_STRING(""),
+ },
+ .priv = &(const int){STREAM_AUDIO},
+ },
+ { "audio-remove", cmd_track_remove, { OARG_INT(-1) },
+ .priv = &(const int){STREAM_AUDIO}, },
+ { "audio-reload", cmd_track_reload, { OARG_INT(-1) },
+ .priv = &(const int){STREAM_AUDIO}, },
- { MP_CMD_RESCAN_EXTERNAL_FILES, "rescan-external-files", {
+ { "rescan-external-files", cmd_rescan_external_files, {
OARG_CHOICE(1, ({"keep-selection", 0},
{"reselect", 1})),
}},
- { MP_CMD_APPLY_PROFILE, "apply-profile", {ARG_STRING } },
+ { "apply-profile", cmd_apply_profile, {ARG_STRING } },
- { MP_CMD_LOAD_SCRIPT, "load-script", {ARG_STRING} },
+ { "load-script", cmd_load_script, {ARG_STRING} },
{0}
};
diff --git a/player/command.h b/player/command.h
index a8638d6666..b6ccffe80f 100644
--- a/player/command.h
+++ b/player/command.h
@@ -29,6 +29,25 @@ struct m_config_option;
void command_init(struct MPContext *mpctx);
void command_uninit(struct MPContext *mpctx);
+// Runtime context for a single command.
+struct mp_cmd_ctx {
+ struct MPContext *mpctx;
+ struct mp_cmd *cmd; // original command
+ // Fields from cmd (for convenience)
+ struct mp_cmd_arg *args;
+ int num_args;
+ const void *priv; // cmd->def->priv
+ // OSD control
+ int on_osd; // MP_ON_OSD_FLAGS;
+ bool msg_osd; // OSD message requested
+ bool bar_osd; // OSD bar requested
+ bool seek_msg_osd; // same as above, but for seek commands
+ bool seek_bar_osd;
+ // Return values
+ bool success; // true by default
+ struct mpv_node *result;
+};
+
int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *res);
char *mp_property_expand_string(struct MPContext *mpctx, const char *str);
char *mp_property_expand_escaped_string(struct MPContext *mpctx, const char *str);