diff --git a/command.c b/command.c index 72fe83c2e7..6487a8b346 100644 --- a/command.c +++ b/command.c @@ -573,10 +573,14 @@ static int mp_property_pause(m_option_t *prop, int action, void *arg, return M_PROPERTY_OK; case M_PROPERTY_STEP_UP: case M_PROPERTY_STEP_DOWN: - if (mpctx->paused) + if (mpctx->paused) { unpause_player(mpctx); - else + mpctx->osd_function = OSD_PLAY; + } + else { pause_player(mpctx); + mpctx->osd_function = OSD_PAUSE; + } return M_PROPERTY_OK; default: return m_property_flag(prop, action, arg, &mpctx->paused); @@ -2520,8 +2524,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) } break; case MP_CMD_FRAME_STEP: - mpctx->step_frames++; - unpause_player(mpctx); + add_step_frame(mpctx); break; case MP_CMD_FILE_FILTER: diff --git a/libmpcodecs/dec_video.c b/libmpcodecs/dec_video.c index 291859abb2..8cdc3e7b1d 100644 --- a/libmpcodecs/dec_video.c +++ b/libmpcodecs/dec_video.c @@ -6,6 +6,7 @@ #include #endif #include +#include #include #include "mp_msg.h" @@ -138,6 +139,14 @@ int set_rectangle(sh_video_t *sh_video, int param, int value) return 0; } +int redraw_osd(struct sh_video *sh_video, struct osd_state *osd) +{ + struct vf_instance *vf = sh_video->vfilter; + if (vf->control(vf, VFCTRL_REDRAW_OSD, osd) == true) + return 0; + return -1; +} + void resync_video_stream(sh_video_t *sh_video) { const struct vd_functions *vd = sh_video->vd_driver; diff --git a/libmpcodecs/dec_video.h b/libmpcodecs/dec_video.h index 42aa56ecb5..463304bde5 100644 --- a/libmpcodecs/dec_video.h +++ b/libmpcodecs/dec_video.h @@ -21,6 +21,7 @@ void set_video_quality(sh_video_t *sh_video, int quality); int get_video_colors(sh_video_t *sh_video, const char *item, int *value); int set_video_colors(sh_video_t *sh_video, const char *item, int value); int set_rectangle(sh_video_t *sh_video, int param, int value); +int redraw_osd(struct sh_video *sh_video, struct osd_state *osd); void resync_video_stream(sh_video_t *sh_video); int get_current_video_decoder_lag(sh_video_t *sh_video); diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index 504c616a73..24d86214d6 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -91,6 +91,7 @@ typedef struct vf_seteq_s /* Hack to make the OSD state object available to vf_expand which accesses * the OSD state outside of normal OSD draw time. */ #define VFCTRL_SET_OSD_OBJ 20 +#define VFCTRL_REDRAW_OSD 21 /* Change user-visible OSD immediately */ #include "vfcap.h" diff --git a/libmpcodecs/vf_expand.c b/libmpcodecs/vf_expand.c index cdde44f82b..dec0c524b6 100644 --- a/libmpcodecs/vf_expand.c +++ b/libmpcodecs/vf_expand.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "config.h" #include "mp_msg.h" @@ -419,6 +420,11 @@ static int control(struct vf_instance* vf, int request, void* data){ break; case VFCTRL_DRAW_OSD: if(vf->priv->osd_enabled) return CONTROL_TRUE; + break; + case VFCTRL_REDRAW_OSD: + if (vf->priv->osd_enabled) + return false; + break; } #endif return vf_next_control(vf,request,data); diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 4f47bc1847..85088487ed 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "config.h" #include "mp_msg.h" @@ -88,6 +89,8 @@ static int control(struct vf_instance* vf, int request, void* data) if(!video_out->config_ok) return CONTROL_FALSE; // vo not configured? vo_draw_osd(video_out, data); return CONTROL_TRUE; + case VFCTRL_REDRAW_OSD: + return vo_control(video_out, VOCTRL_REDRAW_OSD, data) == true; case VFCTRL_FLIP_PAGE: { if(!video_out->config_ok) return CONTROL_FALSE; // vo not configured? diff --git a/libvo/video_out.h b/libvo/video_out.h index cc9544f4fb..308ecb72c9 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -87,6 +87,8 @@ typedef struct { } mp_colorkey_t; #define VOCTRL_XOVERLAY_SET_WIN 23 +#define VOCTRL_REDRAW_OSD 24 + typedef struct { int x,y; int w,h; diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 34f1166f3c..052417422f 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -20,6 +20,7 @@ Buffer allocation: #include #include #include +#include #include "config.h" #include "options.h" @@ -76,8 +77,11 @@ struct xvctx { int current_buf; int current_ip_buf; int num_buffers; + int total_buffers; + int have_visible_image_copy; + int have_next_image_copy; int visible_buf; - XvImage *xvimage[NUM_BUFFERS]; + XvImage *xvimage[NUM_BUFFERS + 1]; uint32_t image_width; uint32_t image_height; uint32_t image_format; @@ -203,6 +207,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, ctx->is_paused = 0; ctx->visible_buf = -1; + ctx->have_visible_image_copy = false; + ctx->have_next_image_copy = false; /* check image formats */ ctx->xv_format = 0; @@ -280,13 +286,14 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, } // In case config has been called before - for (i = 0; i < ctx->num_buffers; i++) + for (i = 0; i < ctx->total_buffers; i++) deallocate_xvimage(vo, i); ctx->num_buffers = vo_doublebuffering ? (vo_directrendering ? NUM_BUFFERS : 2) : 1; + ctx->total_buffers = ctx->num_buffers + 1; - for (i = 0; i < ctx->num_buffers; i++) + for (i = 0; i < ctx->total_buffers; i++) allocate_xvimage(vo, i); ctx->current_buf = 0; @@ -397,6 +404,18 @@ static inline void put_xvimage(struct vo *vo, XvImage *xvi) } } +// Only copies luma for planar formats as draw_alpha doesn't change others */ +void copy_backup_image(struct vo *vo, int dest, int src) +{ + struct xvctx *ctx = vo->priv; + + XvImage *vb = ctx->xvimage[dest]; + XvImage *cp = ctx->xvimage[src]; + memcpy_pic(vb->data + vb->offsets[0], cp->data + cp->offsets[0], + vb->width, vb->height, + vb->pitches[0], cp->pitches[0]); +} + static void check_events(struct vo *vo) { struct xvctx *ctx = vo->priv; @@ -433,6 +452,23 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) ctx->image_height, ctx->draw_alpha_fnc, vo); } +static int redraw_osd(struct vo *vo, struct osd_state *osd) +{ + struct xvctx *ctx = vo->priv; + + // Could check if OSD was empty + if (!ctx->have_visible_image_copy) + return false; + + copy_backup_image(vo, ctx->visible_buf, ctx->num_buffers); + int temp = ctx->current_buf; + ctx->current_buf = ctx->visible_buf; + draw_osd(vo, osd); + ctx->current_buf = temp; + put_xvimage(vo, ctx->xvimage[ctx->visible_buf]); + return true; +} + static void flip_page(struct vo *vo) { struct xvctx *ctx = vo->priv; @@ -441,6 +477,9 @@ static void flip_page(struct vo *vo) /* remember the currently visible buffer */ ctx->visible_buf = ctx->current_buf; + ctx->have_visible_image_copy = ctx->have_next_image_copy; + ctx->have_next_image_copy = false; + if (ctx->num_buffers > 1) { ctx->current_buf = vo_directrendering ? 0 : ((ctx->current_buf + 1) % ctx->num_buffers); @@ -491,26 +530,30 @@ static int draw_frame(struct vo *vo, uint8_t *src[]) static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) { struct xvctx *ctx = vo->priv; - if (mpi->flags & MP_IMGFLAG_DIRECT) { + + ctx->have_next_image_copy = false; + + if (mpi->flags & MP_IMGFLAG_DIRECT) // direct rendering: ctx->current_buf = (int) (mpi->priv); // hack! - return VO_TRUE; - } - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - return VO_TRUE; // done - if (mpi->flags & MP_IMGFLAG_PLANAR) { + else if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) + ; // done + else if (mpi->flags & MP_IMGFLAG_PLANAR) draw_slice(vo, mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0); - return VO_TRUE; - } - if (mpi->flags & MP_IMGFLAG_YUV) { + else if (mpi->flags & MP_IMGFLAG_YUV) // packed YUV: memcpy_pic(ctx->xvimage[ctx->current_buf]->data + ctx->xvimage[ctx->current_buf]->offsets[0], mpi->planes[0], mpi->w * (mpi->bpp / 8), mpi->h, ctx->xvimage[ctx->current_buf]->pitches[0], mpi->stride[0]); - return VO_TRUE; + else + return false; + + if (ctx->is_paused) { + copy_backup_image(vo, ctx->num_buffers, ctx->current_buf); + ctx->have_next_image_copy = true; } - return VO_FALSE; // not (yet) supported + return true; } static uint32_t get_image(struct xvctx *ctx, mp_image_t *mpi) @@ -599,7 +642,7 @@ static void uninit(struct vo *vo) XFree(ctx->fo); ctx->fo = NULL; } - for (i = 0; i < ctx->num_buffers; i++) + for (i = 0; i < ctx->total_buffers; i++) deallocate_xvimage(vo, i); #ifdef CONFIG_XF86VM if (ctx->mode_switched) @@ -800,6 +843,8 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_UPDATE_SCREENINFO: update_xinerama_info(vo); return VO_TRUE; + case VOCTRL_REDRAW_OSD: + return redraw_osd(vo, data); } return VO_NOTIMPL; } diff --git a/mp_core.h b/mp_core.h index 09df4e7719..a346c75dce 100644 --- a/mp_core.h +++ b/mp_core.h @@ -144,5 +144,6 @@ void add_subtitles(struct MPContext *mpctx, char *filename, float fps, int noerr int reinit_video_chain(struct MPContext *mpctx); void pause_player(struct MPContext *mpctx); void unpause_player(struct MPContext *mpctx); +void add_step_frame(struct MPContext *mpctx); #endif /* MPLAYER_MP_CORE_H */ diff --git a/mplayer.c b/mplayer.c index 0ccb31b8aa..36e6c5d5f8 100644 --- a/mplayer.c +++ b/mplayer.c @@ -2322,7 +2322,6 @@ void pause_player(struct MPContext *mpctx) if (mpctx->paused) return; mpctx->paused = 1; - mpctx->osd_function = OSD_PAUSE; mpctx->step_frames = 0; mpctx->time_frame -= get_relative_time(mpctx); @@ -2338,15 +2337,23 @@ void unpause_player(struct MPContext *mpctx) if (!mpctx->paused) return; mpctx->paused = 0; - mpctx->osd_function = OSD_PLAY; if (mpctx->audio_out && mpctx->sh_audio) mpctx->audio_out->resume(); // resume audio - if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok) + if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok + && !mpctx->step_frames) vo_control(mpctx->video_out, VOCTRL_RESUME, NULL); // resume video (void)get_relative_time(mpctx); // ignore time that passed during pause } +void add_step_frame(struct MPContext *mpctx) +{ + mpctx->step_frames++; + if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok) + vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL); + unpause_player(mpctx); +} + static void pause_loop(struct MPContext *mpctx) { mp_cmd_t* cmd; @@ -3781,6 +3788,8 @@ if(!mpctx->sh_video) { mpctx->stop_play = PT_NEXT_ENTRY; goto goto_next_file; } + if (blit_frame) + vo_osd_changed(0); if (frame_time < 0) mpctx->stop_play = AT_END_OF_FILE; else { @@ -3905,11 +3914,20 @@ if(auto_quality>0){ if (mpctx->stop_play) break; } - if (mpctx->paused && !(mpctx->stop_play || mpctx->rel_seek_secs - || mpctx->abs_seek_pos)) - pause_loop(mpctx); - else + if (!mpctx->paused || mpctx->stop_play || mpctx->rel_seek_secs + || mpctx->abs_seek_pos) break; + if (mpctx->sh_video) { + update_osd_msg(mpctx); + int hack = vo_osd_changed(0); + vo_osd_changed(hack); + if (hack) + if (redraw_osd(mpctx->sh_video, mpctx->osd) < 0) { + add_step_frame(mpctx); + break; + } + } + pause_loop(mpctx); } }