From ed9295c250ddfb845e48f123343e7b02326e8920 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 1 Oct 2013 23:35:51 +0200 Subject: video/out: always support redrawing VO window at any point Before, a VO could easily refuse to respond to VOCTRL_REDRAW_FRAME, which means the VO wouldn't redraw OSD and window contents, and the player would appear frozen to the user. This was a bit stupid, and makes dealing with some corner cases much harder (think of --keep-open, which was hard to implement, because the VO gets into this state if there are no new video frames after a seek reset). Change this, and require VOs to always react to VOCTRL_REDRAW_FRAME. There are two aspects of this: First, behavior after a (successful) vo_reconfig() call, but before any video frame has been displayed. Second, behavior after a vo_seek_reset(). For the first issue, we define that sending VOCTRL_REDRAW_FRAME after vo_reconfig() should clear the window with black. This requires minor changes to some VOs. In particular vaapi makes this horribly complicated, because OSD rendering is bound to a video surface. We create a black dummy surface for this purpose. The second issue is much simpler and works already with most VOs: they simply redraw whatever has been uploaded previously. The exception is vdpau, which has a complicated mechanism to track and filter video frames. The state associated with this mechanism is completely cleared with vo_seek_reset(), so implementing this to work as expected is not trivial. For now, we just clear the window with black. --- video/out/gl_video.c | 12 +++++++++++- video/out/vo.c | 5 ++--- video/out/vo_direct3d.c | 12 ++++++++++++ video/out/vo_vaapi.c | 38 ++++++++++++++++++++++++++++++++------ video/out/vo_vdpau.c | 9 ++++++++- video/out/vo_x11.c | 7 +++++-- video/out/vo_xv.c | 3 ++- video/vaapi.c | 2 +- 8 files changed, 73 insertions(+), 15 deletions(-) (limited to 'video') diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 21efc6dd56..3bab03c8aa 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -179,6 +179,7 @@ struct gl_video { int plane_count; struct video_image image; + bool have_image; struct fbotex indirect_fbo; // RGB target struct fbotex scale_sep_fbo; // first pass when doing 2 pass scaling @@ -1353,6 +1354,11 @@ void gl_video_render_frame(struct gl_video *p) gl->Clear(GL_COLOR_BUFFER_BIT); } + if (!p->have_image) { + gl->Clear(GL_COLOR_BUFFER_BIT); + return; + } + // Order of processing: // [indirect -> [scale_sep ->]] final @@ -1571,6 +1577,8 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) } gl->ActiveTexture(GL_TEXTURE0); gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + p->have_image = true; } struct mp_image *gl_video_download_image(struct gl_video *p) @@ -1579,7 +1587,7 @@ struct mp_image *gl_video_download_image(struct gl_video *p) struct video_image *vimg = &p->image; - if (!vimg->planes[0].gl_texture) + if (!p->have_image || !vimg->planes[0].gl_texture) return NULL; assert(p->image_format == p->image_params.imgfmt); @@ -1991,6 +1999,8 @@ void gl_video_config(struct gl_video *p, struct mp_image_params *params) csp.levels_out = params->outputlevels; csp.format = params->colorspace; p->colorspace = csp; + + p->have_image = false; } void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b) diff --git a/video/out/vo.c b/video/out/vo.c index 6f876d1898..a069c442df 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -202,7 +202,7 @@ void vo_queue_image(struct vo *vo, struct mp_image *mpi) int vo_redraw_frame(struct vo *vo) { - if (!vo->config_ok || !vo->hasframe) + if (!vo->config_ok) return -1; if (vo_control(vo, VOCTRL_REDRAW_FRAME, NULL) == true) { vo->want_redraw = false; @@ -214,7 +214,7 @@ int vo_redraw_frame(struct vo *vo) bool vo_get_want_redraw(struct vo *vo) { - if (!vo->config_ok || !vo->hasframe) + if (!vo->config_ok) return false; return vo->want_redraw; } @@ -289,7 +289,6 @@ void vo_seek_reset(struct vo *vo) { vo_control(vo, VOCTRL_RESET, NULL); vo->frame_loaded = false; - vo->hasframe = false; mp_image_unrefp(&vo->waiting_mpi); } diff --git a/video/out/vo_direct3d.c b/video/out/vo_direct3d.c index e265b0b38f..f16ac87703 100644 --- a/video/out/vo_direct3d.c +++ b/video/out/vo_direct3d.c @@ -130,6 +130,8 @@ typedef struct d3d_priv { struct vo *vo; + bool have_image; + D3DLOCKED_RECT locked_rect; /**< The locked offscreen surface */ RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed in fullscreen */ @@ -842,6 +844,9 @@ static uint32_t d3d_draw_frame(d3d_priv *priv) IDirect3DDevice9_Clear(priv->d3d_device, 0, NULL, D3DCLEAR_TARGET, 0, 0, 0); + if (!priv->have_image) + return VO_TRUE; + if (priv->use_textures) { for (n = 0; n < priv->plane_count; n++) { @@ -1271,6 +1276,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, { d3d_priv *priv = vo->priv; + priv->have_image = false; + /* w32_common framework call. Creates window on the screen with * the given coordinates. */ @@ -1412,6 +1419,8 @@ static void draw_image(struct vo *vo, mp_image_t *mpi) } } + priv->have_image = true; + d3d_draw_frame(priv); } @@ -1420,6 +1429,9 @@ static mp_image_t *get_screenshot(d3d_priv *priv) if (!priv->d3d_device) return NULL; + if (!priv->have_image) + return NULL; + struct mp_image buffer; if (!get_video_buffer(priv, &buffer)) return NULL; diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c index 6973882176..7dab1ed058 100644 --- a/video/out/vo_vaapi.c +++ b/video/out/vo_vaapi.c @@ -91,6 +91,9 @@ struct priv { struct va_surface_pool *pool; struct va_image_formats *va_image_formats; + + struct va_surface *black_surface; + VAImageFormat *va_subpic_formats; unsigned int *va_subpic_flags; int va_num_subpic_formats; @@ -119,6 +122,8 @@ static void free_video_specific(struct priv *p) { flush_output_surfaces(p); + va_surface_releasep(&p->black_surface); + for (int n = 0; n < MAX_OUTPUT_SURFACES; n++) mp_image_unrefp(&p->swdec_surfaces[n]); } @@ -149,6 +154,8 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags) { struct priv *p = vo->priv; + free_video_specific(p); + vo_x11_config_vo_window(vo, NULL, vo->dx, vo->dy, vo->dwidth, vo->dheight, flags, "vaapi"); @@ -173,10 +180,29 @@ static int query_format(struct vo *vo, uint32_t imgfmt) static bool render_to_screen(struct priv *p, struct mp_image *mpi) { - bool res = true; VAStatus status; VASurfaceID surface = va_surface_id_in_mp_image(mpi); + if (surface == VA_INVALID_ID) { + if (!p->black_surface) { + int w = p->image_params.w, h = p->image_params.h; + // 4:2:0 should work everywhere + int fmt = IMGFMT_420P; + p->black_surface = + va_surface_pool_get_by_imgfmt(p->pool, p->va_image_formats, + fmt, w, h); + if (p->black_surface) { + struct mp_image *img = mp_image_alloc(fmt, w, h); + mp_image_clear(img, 0, 0, w, h); + if (!va_surface_upload(p->black_surface, img)) + va_surface_releasep(&p->black_surface); + talloc_free(img); + } + } + surface = va_surface_id(p->black_surface); + } + + int fields = mpi ? mpi->fields : 0; if (surface == VA_INVALID_ID) return false; @@ -199,9 +225,8 @@ static bool render_to_screen(struct priv *p, struct mp_image *mpi) } int flags = va_get_colorspace_flag(p->image_params.colorspace) | p->scaling; - if (p->deint && (mpi->fields & MP_IMGFIELD_INTERLACED)) { - flags |= (mpi->fields & MP_IMGFIELD_TOP_FIRST) ? - VA_BOTTOM_FIELD : VA_TOP_FIELD; + if (p->deint && (fields & MP_IMGFIELD_INTERLACED)) { + flags |= (fields & MP_IMGFIELD_TOP_FIRST) ? VA_BOTTOM_FIELD : VA_TOP_FIELD; } else { flags |= VA_FRAME_PICTURE; } @@ -230,7 +255,7 @@ static bool render_to_screen(struct priv *p, struct mp_image *mpi) } } - return res; + return true; } static void flip_page(struct vo *vo) @@ -505,7 +530,8 @@ static int control(struct vo *vo, uint32_t request, void *data) return get_equalizer(p, eq->name, eq->valueptr); } case VOCTRL_REDRAW_FRAME: - return redraw_frame(p); + redraw_frame(p); + return true; case VOCTRL_SCREENSHOT: { struct voctrl_screenshot_args *args = data; args->out_image = get_screenshot(p); diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index 5045ecce1f..581daf2659 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -222,8 +222,15 @@ static int render_video_to_output_surface(struct vo *vo, struct vdp_functions *vdp = vc->vdp; VdpTime dummy; VdpStatus vdp_st; - if (vc->deint_queue_pos < 0) + if (vc->deint_queue_pos < 0) { + // At least clear the screen if there is nothing to render + int flags = VDP_OUTPUT_SURFACE_RENDER_ROTATE_0; + vdp_st = vdp->output_surface_render_output_surface(output_surface, + NULL, vc->black_pixel, + NULL, NULL, NULL, + flags); return -1; + } struct buffered_video_surface *bv = vc->buffered_video; unsigned int dp = vc->deint_queue_pos; diff --git a/video/out/vo_x11.c b/video/out/vo_x11.c index 98d7a23534..6932cb68f2 100644 --- a/video/out/vo_x11.c +++ b/video/out/vo_x11.c @@ -490,8 +490,10 @@ static int redraw_frame(struct vo *vo) { struct priv *p = vo->priv; - if (!p->original_image) + if (!p->original_image) { + vo_x11_clear_background(vo, &(struct mp_rect){0, 0, vo->dwidth, vo->dheight}); return false; + } draw_image(vo, p->original_image); return true; @@ -628,7 +630,8 @@ static int control(struct vo *vo, uint32_t request, void *data) resize(vo); return VO_TRUE; case VOCTRL_REDRAW_FRAME: - return redraw_frame(vo); + redraw_frame(vo); + return true; case VOCTRL_WINDOW_TO_OSD_COORDS: { // OSD is rendered into the scaled image float *c = data; diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c index 731710d0af..d0de5efe9e 100644 --- a/video/out/vo_xv.c +++ b/video/out/vo_xv.c @@ -848,7 +848,8 @@ static int control(struct vo *vo, uint32_t request, void *data) *cspc = ctx->cached_csp; return true; case VOCTRL_REDRAW_FRAME: - return redraw_frame(vo); + redraw_frame(vo); + return true; case VOCTRL_SCREENSHOT: { struct voctrl_screenshot_args *args = data; args->out_image = get_screenshot(vo); diff --git a/video/vaapi.c b/video/vaapi.c index 9a8ab1ac29..fc6a7819e2 100644 --- a/video/vaapi.c +++ b/video/vaapi.c @@ -417,7 +417,7 @@ struct va_surface *va_surface_in_mp_image(struct mp_image *mpi) VASurfaceID va_surface_id(const struct va_surface *surface) { - return surface->id; + return surface ? surface->id : VA_INVALID_ID; } bool va_image_map(VADisplay display, VAImage *image, struct mp_image *mpi) -- cgit v1.2.3