command: add screenshot_to_file command

This commit is contained in:
wm4 2013-07-08 20:34:26 +02:00
parent 0bb41524f0
commit c460258f5a
8 changed files with 116 additions and 28 deletions

View File

@ -140,6 +140,19 @@ List of Input Commands
Take a screenshot each frame. Issue this command again to stop taking
screenshots.
``screenshot_to_file "<filename>" [subtitles|video|window]``
Take a screenshot and save it to a given file. The format of the file will
be guessed by the extension (and ``--screenshot-format`` is ignored - the
behavior when the extension is missing or unknown is arbitrary).
The second argument is like the first argument to ``screenshot``.
This command tries to never overwrite files. If the file already exists,
it fails.
Like all input command parameters, the filename is subject to property
expansion as described in `Property Expansion`_.
``playlist_next [weak|force]``
Go to the next entry on the playlist.

View File

@ -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()) {

View File

@ -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},

View File

@ -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,

View File

@ -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)

View File

@ -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, ".".
*/

View File

@ -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)

View File

@ -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);