diff options
-rw-r--r-- | DOCS/man/en/input.rst | 3 | ||||
-rw-r--r-- | input/input.c | 3 | ||||
-rw-r--r-- | libvo/video_out.h | 2 | ||||
-rw-r--r-- | libvo/vo_xv.c | 1 | ||||
-rw-r--r-- | screenshot.c | 66 | ||||
-rw-r--r-- | screenshot.h | 9 |
6 files changed, 65 insertions, 19 deletions
diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index 74c4929684..63593c53ca 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -104,6 +104,9 @@ screenshot [single|each-frame] [video|window] Save the video image, in its original resolution. Typically without OSD or subtitles, but the exact behavior depends on the selected video output. + <subtitles> + Like ``video``, but add subtitles. Some video outputs may still include + the OSD in the output under certain circumstances. <window> Save the contents of the mplayer window. Typically scaled, with OSD and subtitles. The exact behavior depends on the selected video output, and diff --git a/input/input.c b/input/input.c index f2b601fdbe..ea9d2376b2 100644 --- a/input/input.c +++ b/input/input.c @@ -162,7 +162,8 @@ static const mp_cmd_t mp_cmds[] = { OARG_CHOICE(0, ({"single", 0}, {"0", 0}, {"each-frame", 1}, {"1", 1})), OARG_CHOICE(0, ({"video", 0}, {"0", 0}, - {"window", 1}, {"1", 1})), + {"window", 1}, {"1", 1}, + {"subtitles", 2})), }}, { MP_CMD_LOADFILE, "loadfile", { ARG_STRING, diff --git a/libvo/video_out.h b/libvo/video_out.h index ffb5c0c4f3..1c48b5fb06 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -105,6 +105,8 @@ struct voctrl_screenshot_args { // image data directly. // Is never NULL. (Failure has to be indicated by returning VO_FALSE.) struct mp_image *out_image; + // Whether the VO rendered OSD/subtitles into out_image + bool has_osd; }; typedef struct { diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 92ac9a2461..8095490f4a 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -679,6 +679,7 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_SCREENSHOT: { struct voctrl_screenshot_args *args = data; args->out_image = get_screenshot(vo); + args->has_osd = !ctx->have_image_copy; return true; } } diff --git a/screenshot.c b/screenshot.c index 1f2b0694fc..c60b17649b 100644 --- a/screenshot.c +++ b/screenshot.c @@ -36,13 +36,17 @@ #include "libmpcodecs/vf.h" #include "libvo/video_out.h" #include "image_writer.h" +#include "sub/sub.h" #include "libvo/csputils.h" +#define MODE_FULL_WINDOW 1 +#define MODE_SUBTITLES 2 + typedef struct screenshot_ctx { struct MPContext *mpctx; - int full_window; + int mode; int each_frame; int using_vf_screenshot; @@ -230,7 +234,35 @@ static char *gen_fname(screenshot_ctx *ctx, const char *file_ext) } } -void screenshot_save(struct MPContext *mpctx, struct mp_image *image) +static struct mp_image *add_subs(struct MPContext *mpctx, + struct mp_image *image, + struct mp_csp_details *csp) +{ + if (!(image->flags & MP_IMGFLAG_ALLOCATED)) { + struct mp_image *new_image = alloc_mpi(image->width, image->height, + image->imgfmt); + copy_mpi(new_image, image); + new_image->w = image->w; + new_image->h = image->h; + image = new_image; + } + + double sar = (double)image->width / image->height; + double dar = (double)image->w / image->h; + struct mp_osd_res res = { + .w = image->width, + .h = image->height, + .display_par = sar / dar, + .video_par = dar / sar, + }; + osd_draw_on_image(mpctx->osd, res, mpctx->osd->vo_pts, + OSD_DRAW_SUB_ONLY, image, csp); + + return image; +} + +static void screenshot_save(struct MPContext *mpctx, struct mp_image *image, + bool with_subs) { screenshot_ctx *ctx = mpctx->screenshot_ctx; @@ -239,22 +271,29 @@ void screenshot_save(struct MPContext *mpctx, struct mp_image *image) struct image_writer_opts *opts = mpctx->opts.screenshot_image_opts; + struct mp_image *new_image = image; + if (with_subs) + new_image = add_subs(mpctx, new_image, &colorspace); + char *filename = gen_fname(ctx, image_writer_file_ext(opts)); if (filename) { mp_msg(MSGT_CPLAYER, MSGL_INFO, "*** screenshot '%s' ***\n", filename); - if (!write_image(image, &colorspace, opts, filename)) + if (!write_image(new_image, &colorspace, opts, filename)) mp_msg(MSGT_CPLAYER, MSGL_ERR, "\nError writing screenshot!\n"); talloc_free(filename); } + + if (new_image != image) + free_mp_image(new_image); } static void vf_screenshot_callback(void *pctx, struct mp_image *image) { struct MPContext *mpctx = (struct MPContext *)pctx; screenshot_ctx *ctx = mpctx->screenshot_ctx; - screenshot_save(mpctx, image); + screenshot_save(mpctx, image, ctx->mode); if (ctx->each_frame) - screenshot_request(mpctx, 0, ctx->full_window); + screenshot_request(mpctx, 0, ctx->mode); } static bool force_vf(struct MPContext *mpctx) @@ -270,26 +309,31 @@ static bool force_vf(struct MPContext *mpctx) return false; } -void screenshot_request(struct MPContext *mpctx, bool each_frame, - bool full_window) +void screenshot_request(struct MPContext *mpctx, bool each_frame, int mode) { if (mpctx->video_out && mpctx->video_out->config_ok) { screenshot_ctx *ctx = mpctx->screenshot_ctx; ctx->using_vf_screenshot = 0; + if (mode == MODE_SUBTITLES && mpctx->osd->render_subs_in_filter) + mode = 0; + if (each_frame) { ctx->each_frame = !ctx->each_frame; - ctx->full_window = full_window; + ctx->mode = mode; if (!ctx->each_frame) return; } - struct voctrl_screenshot_args args = { .full_window = full_window }; + struct voctrl_screenshot_args args = + { .full_window = (mode == MODE_FULL_WINDOW) }; if (!force_vf(mpctx) && vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &args) == true) { - screenshot_save(mpctx, args.out_image); + if (args.has_osd) + mode = 0; + screenshot_save(mpctx, args.out_image, mode == MODE_SUBTITLES); free_mp_image(args.out_image); } else { mp_msg(MSGT_CPLAYER, MSGL_INFO, "No VO support for taking" @@ -322,5 +366,5 @@ void screenshot_flip(struct MPContext *mpctx) if (ctx->using_vf_screenshot) return; - screenshot_request(mpctx, 0, ctx->full_window); + screenshot_request(mpctx, 0, ctx->mode); } diff --git a/screenshot.h b/screenshot.h index 6d205990f8..01dd372aa2 100644 --- a/screenshot.h +++ b/screenshot.h @@ -22,7 +22,6 @@ #include <stdbool.h> struct MPContext; -struct mp_image; // One time initialization at program start. void screenshot_init(struct MPContext *mpctx); @@ -30,13 +29,9 @@ void screenshot_init(struct MPContext *mpctx); // Request a taking & saving a screenshot of the currently displayed frame. // each_frame: If set, this toggles per-frame screenshots, exactly like the // screenshot slave command (MP_CMD_SCREENSHOT). -// full_window: If set, save the actual output window contents. +// mode: 0: -, 1: save the actual output window contents, 2: with subtitles. void screenshot_request(struct MPContext *mpctx, bool each_frame, - bool full_window); - -// Save the screenshot contained in the image to disk. -// The image can be in any format supported by libswscale. -void screenshot_save(struct MPContext *mpctx, struct mp_image *image); + int mode); // Called by the playback core code when a new frame is displayed. void screenshot_flip(struct MPContext *mpctx); |