vo: simplify VOs by adding generic screenshot support

At the time screenshot support was added, images weren't refcounted yet,
so screenshots required specialized implementations in the VOs. But now
we can handle these things much simpler. Also see commit 5bb24980.

If there are VOs in the future which can't do this (e.g. they need to
write to the image passed to vo_driver->draw_image), this still could be
disabled on a per-VO basis etc., so we lose no potential performance
advantages.
This commit is contained in:
wm4 2015-01-24 22:56:02 +01:00
parent 047788e3b1
commit 2858232220
15 changed files with 39 additions and 135 deletions

View File

@ -337,7 +337,7 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode)
vo_wait_frame(mpctx->video_out); // important for each-frame mode
if (mode != MODE_FULL_WINDOW)
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &image);
image = vo_get_current_frame(mpctx->video_out);
if (!image) {
vo_control(mpctx->video_out, VOCTRL_SCREENSHOT_WIN, &image);
mode = MODE_FULL_WINDOW;

View File

@ -252,6 +252,9 @@ void mp_image_steal_data(struct mp_image *dst, struct mp_image *src)
// while img is left untouched.
struct mp_image *mp_image_new_ref(struct mp_image *img)
{
if (!img)
return NULL;
if (!img->refcount)
return mp_image_new_copy(img);

View File

@ -2188,12 +2188,6 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
struct mp_image *gl_video_download_image(struct gl_video *p)
{
struct video_image *vimg = &p->image;
return vimg->mpi ? mp_image_new_ref(vimg->mpi) : NULL;
}
static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs)
{
struct gl_video *p = ctx;

View File

@ -72,7 +72,6 @@ void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d);
void gl_video_upload_image(struct gl_video *p, struct mp_image *img);
void gl_video_render_frame(struct gl_video *p, int fbo, struct frame_timing *t);
struct mp_image *gl_video_download_image(struct gl_video *p);
void gl_video_resize(struct gl_video *p, struct mp_rect *window,
struct mp_rect *src, struct mp_rect *dst,
struct mp_osd_res *osd, bool vflip);

View File

@ -135,7 +135,8 @@ struct vo_internal {
int64_t drop_count;
bool dropped_frame; // the previous frame was dropped
struct mp_image *dropped_image; // used to possibly redraw the dropped frame
struct mp_image *current_frame; // last frame queued to the VO
int64_t wakeup_pts; // time at which to pull frame from decoder
@ -333,6 +334,8 @@ static void run_reconfig(void *p)
int flags = *(int *)pp[2];
int *ret = pp[3];
struct vo_internal *in = vo->in;
vo->dwidth = params->d_w;
vo->dheight = params->d_h;
@ -347,7 +350,11 @@ static void run_reconfig(void *p)
talloc_free(vo->params);
vo->params = NULL;
}
forget_frames(vo); // implicitly synchronized
pthread_mutex_lock(&in->lock);
mp_image_unrefp(&in->current_frame);
forget_frames(vo);
pthread_mutex_unlock(&in->lock);
update_display_fps(vo);
}
@ -388,7 +395,7 @@ static void forget_frames(struct vo *vo)
in->hasframe_rendered = false;
in->drop_count = 0;
mp_image_unrefp(&in->frame_queued);
mp_image_unrefp(&in->dropped_image);
// don't unref current_frame; we always want to be able to redraw it
}
#ifndef __MINGW32__
@ -555,7 +562,8 @@ static bool render_frame(struct vo *vo)
if (in->vsync_timed && !in->hasframe)
goto nothing_done;
mp_image_unrefp(&in->dropped_image);
if (img)
mp_image_setrefp(&in->current_frame, img);
in->rendering = true;
in->frame_queued = NULL;
@ -598,7 +606,7 @@ static bool render_frame(struct vo *vo)
}
if (in->dropped_frame) {
in->dropped_image = img;
talloc_free(img);
} else {
in->hasframe_rendered = true;
pthread_mutex_unlock(&in->lock);
@ -679,20 +687,21 @@ static void do_redraw(struct vo *vo)
pthread_mutex_lock(&in->lock);
in->request_redraw = false;
in->want_redraw = false;
bool skip = !in->paused && in->dropped_frame;
struct mp_image *img = in->dropped_image;
if (!skip) {
in->dropped_image = NULL;
bool force_full_redraw = in->dropped_frame;
struct mp_image *img = NULL;
if (vo->config_ok)
img = mp_image_new_ref(in->current_frame);
if (img)
in->dropped_frame = false;
}
pthread_mutex_unlock(&in->lock);
if (!vo->config_ok || skip)
if (!img)
return;
if (img) {
if (force_full_redraw) {
vo->driver->draw_image(vo, img);
} else {
talloc_free(img);
if (vo->driver->control(vo, VOCTRL_REDRAW_FRAME, NULL) < 1)
return;
}
@ -749,6 +758,7 @@ static void *vo_thread(void *ptr)
wait_vo(vo, wait_until);
}
forget_frames(vo); // implicitly synchronized
mp_image_unrefp(&in->current_frame);
vo->driver->uninit(vo);
return NULL;
}
@ -920,6 +930,15 @@ int vo_query_and_reset_events(struct vo *vo, int events)
return r;
}
struct mp_image *vo_get_current_frame(struct vo *vo)
{
struct vo_internal *in = vo->in;
pthread_mutex_lock(&in->lock);
struct mp_image *r = mp_image_new_ref(vo->in->current_frame);
pthread_mutex_unlock(&in->lock);
return r;
}
/**
* \brief lookup an integer in a table, table must have 0 as the last key
* \param key key to search for

View File

@ -97,9 +97,7 @@ enum mp_voctrl {
// imgfmt/w/h/d_w/d_h can be omitted for convenience.
VOCTRL_GET_COLORSPACE, // struct mp_image_params*
// Retrieve original image.
VOCTRL_SCREENSHOT, // struct mp_image**
// Retrieve window contents.
// Retrieve window contents. (Normal screenshots use vo_get_current_frame().)
VOCTRL_SCREENSHOT_WIN, // struct mp_image**
VOCTRL_SET_COMMAND_LINE, // char**
@ -319,6 +317,7 @@ void vo_increment_drop_count(struct vo *vo, int64_t n);
void vo_query_formats(struct vo *vo, uint8_t *list);
void vo_event(struct vo *vo, int event);
int vo_query_and_reset_events(struct vo *vo, int events);
struct mp_image *vo_get_current_frame(struct vo *vo);
void vo_set_flip_queue_params(struct vo *vo, int64_t offset_us, bool vsync_timed);
int64_t vo_get_vsync_interval(struct vo *vo);

View File

@ -225,7 +225,6 @@ static void d3d_clear_video_textures(d3d_priv *priv);
static bool resize_d3d(d3d_priv *priv);
static void uninit(struct vo *vo);
static void flip_page(struct vo *vo);
static mp_image_t *get_screenshot(d3d_priv *priv);
static mp_image_t *get_window_screenshot(d3d_priv *priv);
static void draw_osd(struct vo *vo);
static bool change_d3d_backbuffer(d3d_priv *priv);
@ -1260,9 +1259,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
return VO_TRUE;
case VOCTRL_GET_PANSCAN:
return VO_TRUE;
case VOCTRL_SCREENSHOT:
*(struct mp_image **)data = get_screenshot(priv);
return VO_TRUE;
case VOCTRL_SCREENSHOT_WIN:
*(struct mp_image **)data = get_window_screenshot(priv);
return VO_TRUE;
@ -1445,29 +1441,6 @@ done:
talloc_free(mpi);
}
static mp_image_t *get_screenshot(d3d_priv *priv)
{
if (!priv->d3d_device)
return NULL;
if (!priv->have_image)
return NULL;
if (!priv->vo->params)
return NULL;
struct mp_image buffer;
if (!get_video_buffer(priv, &buffer))
return NULL;
struct mp_image *image = mp_image_new_copy(&buffer);
if (image)
mp_image_set_attributes(image, priv->vo->params);
d3d_unlock_video_objects(priv);
return image;
}
static mp_image_t *get_window_screenshot(d3d_priv *priv)
{
D3DDISPLAYMODE mode;

View File

@ -349,15 +349,10 @@ static int control(struct vo *vo, uint32_t request, void *data)
mpgl_unlock(p->glctx);
return VO_TRUE;
case VOCTRL_SCREENSHOT_WIN:
case VOCTRL_SCREENSHOT:
{
mpgl_lock(p->glctx);
*(struct mp_image **)data = request == VOCTRL_SCREENSHOT
? gl_video_download_image(p->renderer)
: glGetWindowScreenshot(p->gl);
*(struct mp_image **)data = glGetWindowScreenshot(p->gl);
mpgl_unlock(p->glctx);
return true;
}
case VOCTRL_GET_HWDEC_INFO: {
struct mp_hwdec_info **arg = data;
*arg = &p->hwdec_info;

View File

@ -64,7 +64,6 @@ struct mpv_opengl_cb_context {
mpv_opengl_cb_update_fn update_cb;
void *update_cb_ctx;
struct mp_image *waiting_frame;
struct mp_image *displayed_frame;
struct mp_image **frame_queue;
int queued_frames;
struct mp_image_params img_params;
@ -358,7 +357,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
pthread_mutex_lock(&p->ctx->lock);
mp_image_setrefp(&p->ctx->waiting_frame, mpi);
mp_image_setrefp(&p->ctx->displayed_frame, mpi);
talloc_free(mpi);
pthread_mutex_unlock(&p->ctx->lock);
}
@ -488,12 +486,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
update(p);
pthread_mutex_unlock(&p->ctx->lock);
return VO_TRUE;
case VOCTRL_SCREENSHOT: {
pthread_mutex_lock(&p->ctx->lock);
*(struct mp_image **)data = mp_image_new_ref(p->ctx->displayed_frame);
pthread_mutex_unlock(&p->ctx->lock);
return VO_TRUE;
}
case VOCTRL_SET_COMMAND_LINE: {
char *arg = data;
return reparse_cmdline(p, arg);
@ -514,7 +506,6 @@ static void uninit(struct vo *vo)
pthread_mutex_lock(&p->ctx->lock);
forget_frames(p->ctx);
mp_image_unrefp(&p->ctx->displayed_frame);
p->ctx->img_params = (struct mp_image_params){0};
p->ctx->reconfigured = true;
p->ctx->active = NULL;

View File

@ -172,7 +172,6 @@ struct priv {
SDL_Texture *tex;
int tex_swapped;
struct mp_image_params params;
mp_image_t *ssmpi;
struct mp_rect src_rect;
struct mp_rect dst_rect;
struct mp_osd_res osd_res;
@ -638,7 +637,6 @@ static void uninit(struct vo *vo)
{
struct priv *vc = vo->priv;
destroy_renderer(vo);
talloc_free(vc->ssmpi);
SDL_QuitSubSystem(SDL_INIT_VIDEO);
talloc_free(vc);
}
@ -913,9 +911,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
mp_image_copy(&texmpi, mpi);
SDL_UnlockTexture(vc->tex);
talloc_free(vc->ssmpi);
vc->ssmpi = mpi;
}
SDL_Rect src, dst;
@ -941,12 +936,6 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
draw_osd(vo);
}
static struct mp_image *get_screenshot(struct vo *vo)
{
struct priv *vc = vo->priv;
return vc->ssmpi ? mp_image_new_ref(vc->ssmpi) : NULL;
}
static struct mp_image *get_window_screenshot(struct vo *vo)
{
struct priv *vc = vo->priv;
@ -1018,9 +1007,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
struct voctrl_get_equalizer_args *args = data;
return get_eq(vo, args->name, args->valueptr);
}
case VOCTRL_SCREENSHOT:
*(struct mp_image **)data = get_screenshot(vo);
return true;
case VOCTRL_SCREENSHOT_WIN:
*(struct mp_image **)data = get_window_screenshot(vo);
return true;

View File

@ -298,14 +298,6 @@ static void draw_image(struct vo *vo, struct mp_image *mpi)
draw_osd(vo);
}
static struct mp_image *get_screenshot(struct priv *p)
{
struct mp_image *hwimg = p->output_surfaces[p->visible_surface];
if (!hwimg)
return NULL;
return mp_image_new_ref(hwimg);
}
static void free_subpicture(struct priv *p, struct vaapi_osd_image *img)
{
if (img->image.image_id != VA_INVALID_ID)
@ -541,9 +533,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
p->output_surface = p->visible_surface;
draw_osd(vo);
return true;
case VOCTRL_SCREENSHOT:
*(struct mp_image **)data = get_screenshot(p);
return true;
case VOCTRL_GET_PANSCAN:
return VO_TRUE;
case VOCTRL_SET_PANSCAN:

View File

@ -1049,18 +1049,10 @@ static int control(struct vo *vo, uint32_t request, void *data)
forget_frames(vo, true);
return true;
case VOCTRL_SCREENSHOT_WIN:
case VOCTRL_SCREENSHOT:
{
if (!status_ok(vo))
return false;
if (request == VOCTRL_SCREENSHOT_WIN) {
*(struct mp_image **)data = get_window_screenshot(vo);
} else {
*(struct mp_image **)data =
vc->current_image ? mp_image_new_ref(vc->current_image) : NULL;
}
*(struct mp_image **)data = get_window_screenshot(vo);
return true;
}
case VOCTRL_GET_PREF_DEINT:
*(int *)data = vc->deint;
return true;

View File

@ -268,14 +268,6 @@ static bool redraw_frame(struct priv *p)
return true;
}
static mp_image_t *get_screenshot(struct priv *p)
{
if (!p->original_image)
return NULL;
return mp_image_new_ref(p->original_image);
}
static bool resize(struct priv *p)
{
struct vo_wayland_state *wl = p->wl;
@ -689,9 +681,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
}
case VOCTRL_REDRAW_FRAME:
return redraw_frame(p);
case VOCTRL_SCREENSHOT:
*(struct mp_image **)data = get_screenshot(p);
return true;
case VOCTRL_GET_RECENT_FLIP_TIME:
{
*(int64_t*) data = p->recent_flip_time;

View File

@ -423,16 +423,6 @@ static struct mp_image get_x_buffer(struct priv *p, int buf_index)
return img;
}
static mp_image_t *get_screenshot(struct vo *vo)
{
struct priv *p = vo->priv;
if (!p->original_image)
return NULL;
return mp_image_new_ref(p->original_image);
}
static void wait_for_completion(struct vo *vo, int max_outstanding)
{
#if HAVE_SHM && HAVE_XEXT
@ -619,9 +609,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
case VOCTRL_REDRAW_FRAME:
draw_image(vo, p->original_image);
return true;
case VOCTRL_SCREENSHOT:
*(struct mp_image **)data = get_screenshot(vo);
return true;
}
int events = 0;

View File

@ -648,15 +648,6 @@ static void flip_page(struct vo *vo)
XSync(vo->x11->display, False);
}
static mp_image_t *get_screenshot(struct vo *vo)
{
struct xvctx *ctx = vo->priv;
if (!ctx->original_image)
return NULL;
return mp_image_new_ref(ctx->original_image);
}
// Note: REDRAW_FRAME can call this with NULL.
static void draw_image(struct vo *vo, mp_image_t *mpi)
{
@ -839,9 +830,6 @@ static int control(struct vo *vo, uint32_t request, void *data)
case VOCTRL_REDRAW_FRAME:
draw_image(vo, ctx->original_image);
return true;
case VOCTRL_SCREENSHOT:
*(struct mp_image **)data = get_screenshot(vo);
return true;
}
int events = 0;
int r = vo_x11_control(vo, &events, request, data);