Update OSD while paused

When OSD contents change while paused, try to change the OSD drawn in
the currently visible frame. If such OSD updates are not supported
then advance by one frame and draw the OSD normally. Add some support
for OSD redrawing to vo xv.

The new xv code makes a copy of the original frame contents before
drawing the OSD if MPlayer is already paused when the frame is drawn.
If such a copy of the current frame exists then the frame contents can
be restored and a different OSD drawn on top of the same frame.
This commit is contained in:
Uoti Urpala 2008-12-01 19:53:57 +02:00
parent 95f35c4d20
commit 02efad79a2
10 changed files with 115 additions and 26 deletions

View File

@ -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:

View File

@ -6,6 +6,7 @@
#include <malloc.h>
#endif
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#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;

View File

@ -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);

View File

@ -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"

View File

@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#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);

View File

@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#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?

View File

@ -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;

View File

@ -20,6 +20,7 @@ Buffer allocation:
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#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;
}

View File

@ -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 */

View File

@ -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);
}
}