diff options
Diffstat (limited to 'player/screenshot.c')
-rw-r--r-- | player/screenshot.c | 185 |
1 files changed, 100 insertions, 85 deletions
diff --git a/player/screenshot.c b/player/screenshot.c index d0e5777a65..e24ca051f1 100644 --- a/player/screenshot.c +++ b/player/screenshot.c @@ -27,9 +27,11 @@ #include "screenshot.h" #include "core.h" #include "command.h" +#include "input/cmd.h" #include "misc/bstr.h" #include "misc/dispatch.h" -#include "misc/thread_pool.h" +#include "misc/node.h" +#include "misc/thread_tools.h" #include "common/msg.h" #include "options/path.h" #include "video/mp_image.h" @@ -46,13 +48,12 @@ typedef struct screenshot_ctx { struct MPContext *mpctx; - int mode; - bool each_frame; bool osd; - int frameno; + // Command to repeat in each-frame mode. + struct mp_cmd *each_frame; - struct mp_thread_pool *thread_pool; + int frameno; } screenshot_ctx; void screenshot_init(struct MPContext *mpctx) @@ -92,73 +93,27 @@ static char *stripext(void *talloc_ctx, const char *s) return talloc_asprintf(talloc_ctx, "%.*s", (int)(end - s), s); } -struct screenshot_item { - bool on_thread; - struct MPContext *mpctx; - const char *filename; - struct mp_image *img; - struct image_writer_opts opts; -}; - -#define LOCK(item) if (item->on_thread) mp_dispatch_lock(item->mpctx->dispatch); -#define UNLOCK(item) if (item->on_thread) mp_dispatch_unlock(item->mpctx->dispatch); - -static void write_screenshot_thread(void *arg) +static bool write_screenshot(struct MPContext *mpctx, struct mp_image *img, + const char *filename, struct image_writer_opts *opts) { - struct screenshot_item *item = arg; - screenshot_ctx *ctx = item->mpctx->screenshot_ctx; + screenshot_ctx *ctx = mpctx->screenshot_ctx; + struct image_writer_opts *gopts = mpctx->opts->screenshot_image_opts; + struct image_writer_opts opts_copy = opts ? *opts : *gopts; - LOCK(item) - screenshot_msg(ctx, MSGL_INFO, "Screenshot: '%s'", item->filename); - UNLOCK(item) + screenshot_msg(ctx, MSGL_V, "Starting screenshot: '%s'", filename); - if (!item->img || !write_image(item->img, &item->opts, item->filename, - item->mpctx->log)) - { - LOCK(item) - screenshot_msg(ctx, MSGL_ERR, "Error writing screenshot!"); - UNLOCK(item) - } + mp_core_unlock(mpctx); - if (item->on_thread) { - mp_dispatch_lock(item->mpctx->dispatch); - screenshot_msg(ctx, MSGL_V, "Screenshot writing done."); - item->mpctx->outstanding_async -= 1; - mp_wakeup_core(item->mpctx); - mp_dispatch_unlock(item->mpctx->dispatch); - } + bool ok = img && write_image(img, &opts_copy, filename, mpctx->log); - talloc_free(item); -} + mp_core_lock(mpctx); -static void write_screenshot(struct MPContext *mpctx, struct mp_image *img, - const char *filename, struct image_writer_opts *opts, - bool async) -{ - screenshot_ctx *ctx = mpctx->screenshot_ctx; - struct image_writer_opts *gopts = mpctx->opts->screenshot_image_opts; - - struct screenshot_item *item = talloc_zero(NULL, struct screenshot_item); - *item = (struct screenshot_item){ - .mpctx = mpctx, - .filename = talloc_strdup(item, filename), - .img = talloc_steal(item, mp_image_new_ref(img)), - .opts = opts ? *opts : *gopts, - }; - - if (async) { - if (!ctx->thread_pool) - ctx->thread_pool = mp_thread_pool_create(ctx, 1); - if (ctx->thread_pool) { - item->on_thread = true; - mpctx->outstanding_async += 1; - mp_thread_pool_queue(ctx->thread_pool, write_screenshot_thread, item); - item = NULL; - } + if (ok) { + screenshot_msg(ctx, MSGL_INFO, "Screenshot: '%s'", filename); + } else { + screenshot_msg(ctx, MSGL_ERR, "Error writing screenshot!"); } - - if (item) - write_screenshot_thread(item); + return ok; } #ifdef _WIN32 @@ -432,7 +387,8 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode, return image; } -struct mp_image *screenshot_get_rgb(struct MPContext *mpctx, int mode) +// mode is the same as in screenshot_get() +static struct mp_image *screenshot_get_rgb(struct MPContext *mpctx, int mode) { struct mp_image *mpi = screenshot_get(mpctx, mode, false); if (!mpi) @@ -442,9 +398,13 @@ struct mp_image *screenshot_get_rgb(struct MPContext *mpctx, int mode) return res; } -void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode, - bool osd, bool async) +void cmd_screenshot_to_file(void *p) { + struct mp_cmd_ctx *cmd = p; + struct MPContext *mpctx = cmd->mpctx; + const char *filename = cmd->args[0].v.s; + int mode = cmd->args[1].v.i; + bool osd = cmd->msg_osd; screenshot_ctx *ctx = mpctx->screenshot_ctx; struct image_writer_opts opts = *mpctx->opts->screenshot_image_opts; bool old_osd = ctx->osd; @@ -456,34 +416,45 @@ void screenshot_to_file(struct MPContext *mpctx, const char *filename, int mode, opts.format = format; bool high_depth = image_writer_high_depth(&opts); struct mp_image *image = screenshot_get(mpctx, mode, high_depth); + ctx->osd = old_osd; if (!image) { screenshot_msg(ctx, MSGL_ERR, "Taking screenshot failed."); - goto end; + cmd->success = false; + return; } - write_screenshot(mpctx, image, filename, &opts, async); + cmd->success = write_screenshot(mpctx, image, filename, &opts); talloc_free(image); - -end: - ctx->osd = old_osd; } -void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame, - bool osd, bool async) +void cmd_screenshot(void *p) { + struct mp_cmd_ctx *cmd = p; + struct MPContext *mpctx = cmd->mpctx; + int mode = cmd->args[0].v.i & 3; + bool each_frame_toggle = (cmd->args[0].v.i | cmd->args[1].v.i) & 8; + bool each_frame_mode = cmd->args[0].v.i & 16; + bool osd = cmd->msg_osd; + screenshot_ctx *ctx = mpctx->screenshot_ctx; if (mode == MODE_SUBTITLES && osd_get_render_subs_in_filter(mpctx->osd)) mode = 0; - if (each_frame) { - ctx->each_frame = !ctx->each_frame; - if (!ctx->each_frame) - return; - } else { - ctx->each_frame = false; + if (!each_frame_mode) { + if (each_frame_toggle) { + if (ctx->each_frame) { + TA_FREEP(&ctx->each_frame); + return; + } + ctx->each_frame = talloc_steal(ctx, mp_cmd_clone(cmd->cmd)); + ctx->each_frame->args[0].v.i |= 16; + } else { + TA_FREEP(&ctx->each_frame); + } } - ctx->mode = mode; + cmd->success = false; + ctx->osd = osd; struct image_writer_opts *opts = mpctx->opts->screenshot_image_opts; @@ -494,7 +465,7 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame, if (image) { char *filename = gen_fname(ctx, image_writer_file_ext(opts)); if (filename) - write_screenshot(mpctx, image, filename, NULL, async); + cmd->success = write_screenshot(mpctx, image, filename, NULL); talloc_free(filename); } else { screenshot_msg(ctx, MSGL_ERR, "Taking screenshot failed."); @@ -503,6 +474,42 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame, talloc_free(image); } +void cmd_screenshot_raw(void *p) +{ + struct mp_cmd_ctx *cmd = p; + struct MPContext *mpctx = cmd->mpctx; + struct mpv_node *res = &cmd->result; + + struct mp_image *img = screenshot_get_rgb(mpctx, cmd->args[0].v.i); + if (!img) { + cmd->success = false; + return; + } + + 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); +} + +static void screenshot_fin(struct mp_cmd_ctx *cmd) +{ + void **a = cmd->on_completion_priv; + struct MPContext *mpctx = a[0]; + struct mp_waiter *waiter = a[1]; + + mp_waiter_wakeup(waiter, 0); + mp_wakeup_core(mpctx); +} + void screenshot_flip(struct MPContext *mpctx) { screenshot_ctx *ctx = mpctx->screenshot_ctx; @@ -510,6 +517,14 @@ void screenshot_flip(struct MPContext *mpctx) if (!ctx->each_frame) return; - ctx->each_frame = false; - screenshot_request(mpctx, ctx->mode, true, ctx->osd, false); + struct mp_waiter wait = MP_WAITER_INITIALIZER; + void *a[] = {mpctx, &wait}; + run_command(mpctx, mp_cmd_clone(ctx->each_frame), NULL, screenshot_fin, a); + + // Block (in a reentrant way) until he screenshot was written. Otherwise, + // we could pile up screenshot requests forever. + while (!mp_waiter_poll(&wait)) + mp_idle(mpctx); + + mp_waiter_wait(&wait); } |