summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-10-20 23:32:45 +0200
committerwm4 <wm4@nowhere>2012-10-24 21:56:34 +0200
commit11ed093182f29c796ba6fd08f6c5c80e8fdb9349 (patch)
tree69f920eab72378a8c4b659d7dfd8b1bb81968029
parent821c01a5f50284a839ab879724a5c67b3f855a84 (diff)
downloadmpv-11ed093182f29c796ba6fd08f6c5c80e8fdb9349.tar.bz2
mpv-11ed093182f29c796ba6fd08f6c5c80e8fdb9349.tar.xz
screenshot: allow taking screenshots with subtitles
This adds a new screenshot mode "subtitles", which basically takes the video frame as decoded, and renders subtitles into it. This may fail for some pixel formats, because libswscale sucks. If this becomes ever a real problem, the code could be changed to convert the image to RGBA first (or whatever the image writer wants), and then render the subtitles into it. This would avoid the additional image copy needed with vo_xv too. But for now, it seems better to go with the current method in the common case: vo_opengl creates an image copy anyway, and drawing bitmaps to yv12 is better, as no color space conversion is involved in draw_bmp.c's up/downsampling conversion.
-rw-r--r--DOCS/man/en/input.rst3
-rw-r--r--input/input.c3
-rw-r--r--libvo/video_out.h2
-rw-r--r--libvo/vo_xv.c1
-rw-r--r--screenshot.c66
-rw-r--r--screenshot.h9
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);