summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-07-08 21:55:44 +0200
committerwm4 <wm4@nowhere>2013-07-08 21:55:44 +0200
commit31f685040bd2152d541ed16cf441c6b5e7e430fd (patch)
treeb8351b2847231bbc15d883a622ac972945cce6b4 /core
parent73c76de91edbf8a55eb725196ff54583e3428510 (diff)
parent7a71a2cc483d17bed94408d5aee6fba6893558cb (diff)
downloadmpv-31f685040bd2152d541ed16cf441c6b5e7e430fd.tar.bz2
mpv-31f685040bd2152d541ed16cf441c6b5e7e430fd.tar.xz
Merge branch 'master' into remove_old_demuxers
Conflicts: DOCS/man/en/changes.rst DOCS/man/en/options.rst
Diffstat (limited to 'core')
-rw-r--r--core/command.c10
-rw-r--r--core/input/input.c77
-rw-r--r--core/input/input.h5
-rw-r--r--core/path.c11
-rw-r--r--core/path.h7
-rw-r--r--core/screenshot.c96
-rw-r--r--core/screenshot.h6
7 files changed, 179 insertions, 33 deletions
diff --git a/core/command.c b/core/command.c
index fb21d7bc41..5a68a228bc 100644
--- a/core/command.c
+++ b/core/command.c
@@ -2420,6 +2420,10 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
screenshot_request(mpctx, cmd->args[0].v.i, cmd->args[1].v.i, msg_osd);
break;
+ case MP_CMD_SCREENSHOT_TO_FILE:
+ screenshot_to_file(mpctx, cmd->args[0].v.s, cmd->args[1].v.i, msg_osd);
+ break;
+
case MP_CMD_RUN:
#ifndef __MINGW32__
if (!fork()) {
@@ -2507,6 +2511,12 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
change_video_filters(mpctx, cmd->args[0].v.s, cmd->args[1].v.s);
break;
+ case MP_CMD_COMMAND_LIST: {
+ for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next)
+ run_command(mpctx, sub);
+ break;
+ }
+
default:
mp_msg(MSGT_CPLAYER, MSGL_V,
"Received unknown cmd %s\n", cmd->name);
diff --git a/core/input/input.c b/core/input/input.c
index 4a52b3f9c9..e87d9bb560 100644
--- a/core/input/input.c
+++ b/core/input/input.c
@@ -171,6 +171,12 @@ static const mp_cmd_t mp_cmds[] = {
OARG_CHOICE(0, ({"single", 0},
{"each-frame", 1})),
}},
+ { MP_CMD_SCREENSHOT_TO_FILE, "screenshot_to_file", {
+ ARG_STRING,
+ OARG_CHOICE(2, ({"video", 0},
+ {"window", 1},
+ {"subtitles", 2})),
+ }},
{ MP_CMD_LOADFILE, "loadfile", {
ARG_STRING,
OARG_CHOICE(0, ({"replace", 0}, {"0", 0},
@@ -808,7 +814,7 @@ static bool read_token(bstr str, bstr *out_rest, bstr *out_token)
bstr t = bstr_lstrip(str);
int next = bstrcspn(t, WHITESPACE "#");
// Handle comments
- if (t.start[next] == '#')
+ if (t.len && t.start[next] == '#')
t = bstr_splice(t, 0, next);
if (!t.len)
return false;
@@ -852,13 +858,16 @@ error:
return false;
}
-mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
+// If dest is non-NULL when calling this function, append the command to the
+// list formed by dest->queue_next, otherwise just set *dest = new_cmd;
+static int parse_cmd(struct mp_cmd **dest, bstr str, const char *loc)
{
int pausing = 0;
int on_osd = MP_ON_OSD_AUTO;
bool raw_args = false;
struct mp_cmd *cmd = NULL;
bstr start = str;
+ bstr next = {0};
void *tmp = talloc_new(NULL);
str = bstr_lstrip(str);
@@ -929,8 +938,13 @@ mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
struct mp_cmd_arg *cmdarg = &cmd->args[i];
if (!cmdarg->type.type)
break;
- cmd->nargs++;
str = bstr_lstrip(str);
+ if (eat_token(&str, ";")) {
+ next = str;
+ str.len = 0;
+ break;
+ }
+ cmd->nargs++;
bstr arg = {0};
if (bstr_eatstart0(&str, "\"")) {
if (!read_escaped_string(tmp, &str, &arg)) {
@@ -962,6 +976,11 @@ mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
cmdarg->v.s = talloc_steal(cmd, cmdarg->v.s);
}
+ if (eat_token(&str, ";")) {
+ next = str;
+ str.len = 0;
+ }
+
bstr dummy;
if (read_token(str, &dummy, &dummy)) {
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command %s has trailing unused "
@@ -986,14 +1005,51 @@ mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
bstr orig = (bstr) {start.start, str.start - start.start};
cmd->original = bstrdup(cmd, bstr_strip(orig));
+ while (*dest)
+ dest = &(*dest)->queue_next;
+ *dest = cmd;
+
+ next = bstr_strip(next);
+ if (next.len) {
+ if (parse_cmd(dest, next, loc) < 0) {
+ *dest = NULL;
+ goto error;
+ }
+ }
+
talloc_free(tmp);
- return cmd;
+ return 1;
error:
mp_tmsg(MSGT_INPUT, MSGL_ERR, "Command was defined at %s.\n", loc);
talloc_free(cmd);
talloc_free(tmp);
- return NULL;
+ return -1;
+}
+
+mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
+{
+ struct mp_cmd *cmd = NULL;
+ if (parse_cmd(&cmd, str, loc) < 0) {
+ assert(!cmd);
+ }
+ // Other input.c code uses queue_next for its own purposes, so explicitly
+ // wrap lists in a pseudo-command.
+ if (cmd && cmd->queue_next) {
+ struct mp_cmd *list = talloc_ptrtype(NULL, list);
+ *list = (struct mp_cmd) {
+ .id = MP_CMD_COMMAND_LIST,
+ .name = "list",
+ .original = bstrdup(list, str),
+ };
+ list->args[0].v.p = cmd;
+ while (cmd) {
+ talloc_steal(list, cmd);
+ cmd = cmd->queue_next;
+ }
+ cmd = list;
+ }
+ return cmd;
}
#define MP_CMD_MAX_SIZE 4096
@@ -1726,6 +1782,17 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd)
ret->args[i].v.s = talloc_strdup(ret, cmd->args[i].v.s);
}
+ if (cmd->id == MP_CMD_COMMAND_LIST) {
+ bool first = true;
+ for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next) {
+ sub = mp_cmd_clone(sub);
+ talloc_steal(cmd, sub);
+ if (first)
+ cmd->args[0].v.p = sub;
+ first = false;
+ }
+ }
+
return ret;
}
diff --git a/core/input/input.h b/core/input/input.h
index 2a9b3832c1..da92efd373 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -36,6 +36,7 @@ enum mp_command_type {
MP_CMD_TV_STEP_NORM,
MP_CMD_TV_STEP_CHANNEL_LIST,
MP_CMD_SCREENSHOT,
+ MP_CMD_SCREENSHOT_TO_FILE,
MP_CMD_LOADFILE,
MP_CMD_LOADLIST,
MP_CMD_PLAYLIST_CLEAR,
@@ -87,6 +88,9 @@ enum mp_command_type {
/// Video output commands
MP_CMD_VO_CMDLINE,
+
+ // Internal
+ MP_CMD_COMMAND_LIST, // list of sub-commands in args[0].v.p
};
#define MP_CMD_MAX_ARGS 10
@@ -128,6 +132,7 @@ struct mp_cmd_arg {
float f;
double d;
char *s;
+ void *p;
} v;
};
diff --git a/core/path.c b/core/path.c
index 1cff719041..50350be18c 100644
--- a/core/path.c
+++ b/core/path.c
@@ -164,6 +164,17 @@ struct bstr mp_dirname(const char *path)
return ret;
}
+char *mp_splitext(const char *path, bstr *root)
+{
+ assert(path);
+ const char *split = strrchr(path, '.');
+ if (!split)
+ split = path + strlen(path);
+ if (root)
+ *root = (bstr){.start = (char *)path, .len = path - split};
+ return (char *)split;
+}
+
char *mp_path_join(void *talloc_ctx, struct bstr p1, struct bstr p2)
{
if (p1.len == 0)
diff --git a/core/path.h b/core/path.h
index a3033199df..a38ad503ea 100644
--- a/core/path.h
+++ b/core/path.h
@@ -40,6 +40,13 @@ char *mp_find_user_config_file(const char *filename);
char *mp_basename(const char *path);
+/* Return file extension, including the '.'. If root is not NULL, set it to the
+ * part of the path without extension. So: path == root + returnvalue
+ * Don't consider it a file extension if the only '.' is the first character.
+ * Return "" if no extension.
+ */
+char *mp_splitext(const char *path, bstr *root);
+
/* Return struct bstr referencing directory part of path, or if that
* would be empty, ".".
*/
diff --git a/core/screenshot.c b/core/screenshot.c
index 4f7a0dbcdd..6b07bce5a0 100644
--- a/core/screenshot.c
+++ b/core/screenshot.c
@@ -278,16 +278,12 @@ static void add_subs(struct MPContext *mpctx, struct mp_image *image)
OSD_DRAW_SUB_ONLY, image);
}
-static void screenshot_save(struct MPContext *mpctx, struct mp_image *image,
- bool with_subs)
+static void screenshot_save(struct MPContext *mpctx, struct mp_image *image)
{
screenshot_ctx *ctx = mpctx->screenshot_ctx;
struct image_writer_opts *opts = mpctx->opts.screenshot_image_opts;
- if (with_subs)
- add_subs(mpctx, image);
-
char *filename = gen_fname(ctx, image_writer_file_ext(opts));
if (filename) {
screenshot_msg(ctx, SMSG_OK, "Screenshot: '%s'", filename);
@@ -295,30 +291,15 @@ static void screenshot_save(struct MPContext *mpctx, struct mp_image *image,
screenshot_msg(ctx, SMSG_ERR, "Error writing screenshot!");
talloc_free(filename);
}
-
- talloc_free(image);
}
-void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame,
- bool osd)
+static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode)
{
+ struct mp_image *image = NULL;
if (mpctx->video_out && mpctx->video_out->config_ok) {
- screenshot_ctx *ctx = mpctx->screenshot_ctx;
-
if (mode == MODE_SUBTITLES && mpctx->osd->render_subs_in_filter)
mode = 0;
- if (each_frame) {
- ctx->each_frame = !ctx->each_frame;
- if (!ctx->each_frame)
- return;
- } else {
- ctx->each_frame = false;
- }
-
- ctx->mode = mode;
- ctx->osd = osd;
-
struct voctrl_screenshot_args args =
{ .full_window = (mode == MODE_FULL_WINDOW) };
@@ -328,14 +309,73 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame,
if (!args.out_image)
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &args);
- if (args.out_image) {
- if (args.has_osd)
- mode = 0;
- screenshot_save(mpctx, args.out_image, mode == MODE_SUBTITLES);
- } else {
- screenshot_msg(ctx, SMSG_ERR, "Taking screenshot failed.");
+ image = args.out_image;
+ if (image) {
+ if (mode == MODE_SUBTITLES && !args.has_osd)
+ add_subs(mpctx, image);
}
}
+ return image;
+}
+
+void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode,
+ bool osd)
+{
+ screenshot_ctx *ctx = mpctx->screenshot_ctx;
+ struct image_writer_opts opts = *mpctx->opts.screenshot_image_opts;
+ bool old_osd = ctx->osd;
+ ctx->osd = osd;
+
+ if (mp_path_exists(filename)) {
+ screenshot_msg(ctx, SMSG_ERR, "Screenshot: file '%s' already exists.",
+ filename);
+ goto end;
+ }
+ char *ext = mp_splitext(filename, NULL);
+ if (ext)
+ opts.format = ext + 1; // omit '.'
+ struct mp_image *image = screenshot_get(mpctx, mode);
+ if (!image) {
+ screenshot_msg(ctx, SMSG_ERR, "Taking screenshot failed.");
+ goto end;
+ }
+ screenshot_msg(ctx, SMSG_OK, "Screenshot: '%s'", filename);
+ if (!write_image(image, &opts, filename))
+ screenshot_msg(ctx, SMSG_ERR, "Error writing screenshot!");
+ talloc_free(image);
+
+end:
+ ctx->osd = old_osd;
+}
+
+void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame,
+ bool osd)
+{
+ screenshot_ctx *ctx = mpctx->screenshot_ctx;
+
+ if (mode == MODE_SUBTITLES && mpctx->osd->render_subs_in_filter)
+ mode = 0;
+
+ if (each_frame) {
+ ctx->each_frame = !ctx->each_frame;
+ if (!ctx->each_frame)
+ return;
+ } else {
+ ctx->each_frame = false;
+ }
+
+ ctx->mode = mode;
+ ctx->osd = osd;
+
+ struct mp_image *image = screenshot_get(mpctx, mode);
+
+ if (image) {
+ screenshot_save(mpctx, image);
+ } else {
+ screenshot_msg(ctx, SMSG_ERR, "Taking screenshot failed.");
+ }
+
+ talloc_free(image);
}
void screenshot_flip(struct MPContext *mpctx)
diff --git a/core/screenshot.h b/core/screenshot.h
index 916a875505..1b12ac9b73 100644
--- a/core/screenshot.h
+++ b/core/screenshot.h
@@ -34,6 +34,12 @@ void screenshot_init(struct MPContext *mpctx);
void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame,
bool osd);
+// filename: where to store the screenshot; doesn't try to find an alternate
+// name if the file already exists
+// mode, osd: same as in screenshot_request()
+void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode,
+ bool osd);
+
// Called by the playback core code when a new frame is displayed.
void screenshot_flip(struct MPContext *mpctx);