From 77c709ad31ebe997dbd824506c145a0ac24581d0 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sat, 29 Nov 2008 08:09:57 +0200 Subject: [PATCH 1/9] Start pause handling changes Add separate pause_player() / unpause_player functions(), move some pausing-related state into explicit variables and make commands while paused not unpause. Not everything works properly while paused yet (no screen updates etc). --- command.c | 44 +++++++++++++++++++---------- mp_core.h | 8 +++++- mplayer.c | 84 ++++++++++++++++++++++++++++++++++--------------------- 3 files changed, 88 insertions(+), 48 deletions(-) diff --git a/command.c b/command.c index 9d4c38726b..e642944ada 100644 --- a/command.c +++ b/command.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "config.h" #include "command.h" @@ -559,10 +560,27 @@ static int mp_property_metadata(m_option_t *prop, int action, void *arg, return M_PROPERTY_NOT_IMPLEMENTED; } -static int mp_property_pause(m_option_t * prop, int action, void *arg, - MPContext * mpctx) +static int mp_property_pause(m_option_t *prop, int action, void *arg, + void *ctx) { - return m_property_flag_ro(prop, action, arg, mpctx->osd_function == OSD_PAUSE); + MPContext *mpctx = ctx; + + switch (action) { + case M_PROPERTY_SET: + if (!arg) + return M_PROPERTY_ERROR; + if (mpctx->paused == (bool)*(int *) arg) + return M_PROPERTY_OK; + case M_PROPERTY_STEP_UP: + case M_PROPERTY_STEP_DOWN: + if (mpctx->paused) + unpause_player(mpctx); + else + pause_player(mpctx); + return M_PROPERTY_OK; + default: + return m_property_flag(prop, action, arg, &mpctx->paused); + } } @@ -2212,6 +2230,7 @@ static struct { { "loop", MP_CMD_LOOP, 0, 0, -1, MSGTR_LoopStatus }, { "chapter", MP_CMD_SEEK_CHAPTER, 0, 0, -1, NULL }, { "angle", MP_CMD_SWITCH_ANGLE, 0, 0, -1, NULL }, + { "pause", MP_CMD_PAUSE, 0, 0, -1, NULL }, // audio { "volume", MP_CMD_VOLUME, 0, OSD_VOLUME, -1, MSGTR_Volume }, { "mute", MP_CMD_MUTE, 1, 0, -1, MSGTR_MuteStatus }, @@ -2503,9 +2522,8 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) } break; case MP_CMD_FRAME_STEP: - case MP_CMD_PAUSE: - cmd->pausing = 1; - brk_cmd = 1; + mpctx->step_frames++; + unpause_player(mpctx); break; case MP_CMD_FILE_FILTER: @@ -3215,18 +3233,14 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) switch (cmd->pausing) { case 1: // "pausing" - mpctx->osd_function = OSD_PAUSE; + pause_player(mpctx); break; case 3: // "pausing_toggle" - mpctx->was_paused = !mpctx->was_paused; - if (mpctx->was_paused) - mpctx->osd_function = OSD_PAUSE; - else if (mpctx->osd_function == OSD_PAUSE) - mpctx->osd_function = OSD_PLAY; + if (mpctx->paused) + unpause_player(mpctx); + else + pause_player(mpctx); break; - case 2: // "pausing_keep" - if (mpctx->was_paused) - mpctx->osd_function = OSD_PAUSE; } return brk_cmd; } diff --git a/mp_core.h b/mp_core.h index 1287d9ad2b..09df4e7719 100644 --- a/mp_core.h +++ b/mp_core.h @@ -82,6 +82,8 @@ typedef struct MPContext { // In the audio-only case used as a timer since the last seek // by the audio CPU usage meter. double delay; + // AV sync: time until next frame should be shown + float time_frame; // Timestamp from the last time some timing functions read the // current time, in (occasionally wrapping) microseconds. Used @@ -112,7 +114,9 @@ typedef struct MPContext { int last_dvb_step; int dvbin_reopen; - int was_paused; + int paused; + // step this many frames, then pause + int step_frames; #ifdef CONFIG_DVDNAV struct mp_image *nav_smpi; ///< last decoded dvdnav video image @@ -138,5 +142,7 @@ double playing_audio_pts(struct MPContext *mpctx); void exit_player_with_rc(struct MPContext *mpctx, exit_reason_t how, int rc); 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); #endif /* MPLAYER_MP_CORE_H */ diff --git a/mplayer.c b/mplayer.c index caa96b143e..04e8dc54b4 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1696,8 +1696,7 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time) { ++total_frame_cnt; // we should avoid dropping too many frames in sequence unless we // are too late. and we allow 100ms A-V delay here: - if (d < -dropped_frames*frame_time-0.100 && - mpctx->osd_function != OSD_PAUSE) { + if (d < -dropped_frames*frame_time-0.100 && !mpctx->paused) { ++drop_frame_cnt; ++dropped_frames; return frame_dropping; @@ -2318,6 +2317,36 @@ static double update_video(struct MPContext *mpctx, int *blit_frame) return frame_time; } +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); + + if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok) + vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL); + + if (mpctx->audio_out && mpctx->sh_audio) + mpctx->audio_out->pause(); // pause audio, keep data if possible +} + +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) + vo_control(mpctx->video_out, VOCTRL_RESUME, NULL); // resume video + (void)get_relative_time(mpctx); // ignore time that passed during pause +} + static void pause_loop(struct MPContext *mpctx) { mp_cmd_t* cmd; @@ -2339,11 +2368,6 @@ static void pause_loop(struct MPContext *mpctx) if (use_gui) guiGetEvent(guiCEvent, (char *)guiSetPause); #endif - if (mpctx->video_out && mpctx->sh_video && mpctx->video_out->config_ok) - vo_control(mpctx->video_out, VOCTRL_PAUSE, NULL); - - if (mpctx->audio_out && mpctx->sh_audio) - mpctx->audio_out->pause(); // pause audio, keep data if possible while ( (cmd = mp_input_get_cmd(mpctx->input, 20, 1, 1)) == NULL || cmd->id == MP_CMD_SET_MOUSE_POS || cmd->pausing == 4) { @@ -2369,16 +2393,6 @@ static void pause_loop(struct MPContext *mpctx) #endif usec_sleep(20000); } - if (cmd && cmd->id == MP_CMD_PAUSE) { - cmd = mp_input_get_cmd(mpctx->input, 0,1,0); - mp_cmd_free(cmd); - } - 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) - vo_control(mpctx->video_out, VOCTRL_RESUME, NULL); // resume video - (void)get_relative_time(mpctx); // ignore time that passed during pause #ifdef CONFIG_GUI if (use_gui) { if (guiIntfStruct.Playing == guiSetStop) @@ -3601,7 +3615,6 @@ if(verbose) term_osd = 0; { //int frame_corr_num=0; // //float v_frame=0; // Video -float time_frame=0; // Timer //float num_frames=0; // number of frames played int frame_time_remaining=0; // flag @@ -3711,6 +3724,7 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) { #endif get_relative_time(mpctx); // reset current delta + mpctx->time_frame = 0; while(!mpctx->stop_play){ float aq_sleep_time=0; @@ -3771,7 +3785,7 @@ if(!mpctx->sh_video) { else { // might return with !eof && !blit_frame if !correct_pts mpctx->num_buffered_frames += blit_frame; - time_frame += frame_time / opts->playback_speed; // for nosound + mpctx->time_frame += frame_time / opts->playback_speed; // for nosound } } @@ -3802,7 +3816,7 @@ if(!mpctx->sh_video) { } } - frame_time_remaining = sleep_until_update(mpctx, &time_frame, &aq_sleep_time); + frame_time_remaining = sleep_until_update(mpctx, &mpctx->time_frame, &aq_sleep_time); //====================== FLIP PAGE (VIDEO BLT): ========================= @@ -3817,7 +3831,7 @@ if(!mpctx->sh_video) { } //====================== A-V TIMESTAMP CORRECTION: ========================= - adjust_sync_and_print_status(mpctx, frame_time_remaining, time_frame); + adjust_sync_and_print_status(mpctx, frame_time_remaining, mpctx->time_frame); //============================ Auto QUALITY ============================ @@ -3839,9 +3853,17 @@ if(auto_quality>0){ set_video_quality(mpctx->sh_video,output_quality); } - if (play_n_frames >= 0 && !frame_time_remaining && blit_frame) { - --play_n_frames; - if (play_n_frames <= 0) mpctx->stop_play = PT_NEXT_ENTRY; + if (!frame_time_remaining && blit_frame) { + if (play_n_frames >= 0) { + --play_n_frames; + if (play_n_frames <= 0) + mpctx->stop_play = PT_NEXT_ENTRY; + } + if (mpctx->step_frames > 0) { + mpctx->step_frames--; + if (mpctx->step_frames == 0) + pause_player(mpctx); + } } @@ -3871,13 +3893,6 @@ if(auto_quality>0){ //============================ Handle PAUSE =============================== - current_module="pause"; - - if (mpctx->osd_function == OSD_PAUSE) { - mpctx->was_paused = 1; - pause_loop(mpctx); - } - // handle -sstep if(step_sec>0) { mpctx->osd_function=OSD_FFW; @@ -3891,6 +3906,7 @@ if(step_sec>0) { current_module="key_events"; { + while (1) { mp_cmd_t* cmd; int brk_cmd = 0; while( !brk_cmd && (cmd = mp_input_get_cmd(mpctx->input, 0,0,0)) != NULL) { @@ -3899,8 +3915,12 @@ if(step_sec>0) { if (brk_cmd == 2) goto goto_enable_cache; } + if (mpctx->paused && !mpctx->stop_play) + pause_loop(mpctx); + else + break; + } } - mpctx->was_paused = 0; /* Looping. */ if(mpctx->stop_play==AT_END_OF_FILE && opts->loop_times>=0) { From 6fec7ec734c25424e268465ae806063273c4e5be Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 30 Nov 2008 03:19:46 +0200 Subject: [PATCH 2/9] Allow seeking while paused Screen is now updated immediately (doesn't always work without correct-pts yet though). Doing audio unpause after the seek reset can display errors. Main loop code now checks for possible reasons to stop command processing instead of relying on each command to also set an explicit 'break' flag. --- command.c | 11 +---------- command.h | 2 +- mplayer.c | 33 ++++++++++++++++----------------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/command.c b/command.c index e642944ada..72fe83c2e7 100644 --- a/command.c +++ b/command.c @@ -2367,12 +2367,11 @@ static const struct { }; #endif -int run_command(MPContext *mpctx, mp_cmd_t *cmd) +void run_command(MPContext *mpctx, mp_cmd_t *cmd) { struct MPOpts *opts = &mpctx->opts; sh_audio_t * const sh_audio = mpctx->sh_audio; sh_video_t * const sh_video = mpctx->sh_video; - int brk_cmd = 0; if (!set_property_command(mpctx, cmd)) switch (cmd->id) { case MP_CMD_SEEK:{ @@ -2397,7 +2396,6 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) mpctx->rel_seek_secs += v; mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW; } - brk_cmd = 1; } break; @@ -2562,7 +2560,6 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) mpctx->stop_play = (n > 0) ? PT_NEXT_ENTRY : PT_PREV_ENTRY; if (mpctx->stop_play) mpctx->play_tree_step = n; - brk_cmd = 1; } } break; @@ -2579,7 +2576,6 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) play_tree_iter_free(i); } else mpctx->stop_play = (n > 0) ? PT_UP_NEXT : PT_UP_PREV; - brk_cmd = 1; } break; @@ -2593,7 +2589,6 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) else if (v < 0 && mpctx->playtree_iter->file > 1) mpctx->stop_play = PT_PREV_SRC; } - brk_cmd = 1; break; case MP_CMD_SUB_STEP: @@ -2676,7 +2671,6 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) pt_iter_goto_head(mpctx->playtree_iter); mpctx->stop_play = PT_NEXT_SRC; } - brk_cmd = 1; } break; @@ -2700,7 +2694,6 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) mpctx->stop_play = PT_NEXT_SRC; } } - brk_cmd = 1; } break; @@ -2710,7 +2703,6 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) (mpctx->playtree_iter, 0, 1) != PLAY_TREE_ITER_END) /* NOP */ ; mpctx->stop_play = PT_STOP; - brk_cmd = 1; break; #ifdef CONFIG_RADIO @@ -3242,5 +3234,4 @@ int run_command(MPContext *mpctx, mp_cmd_t *cmd) pause_player(mpctx); break; } - return brk_cmd; } diff --git a/command.h b/command.h index f87c5a00ca..ee8c451a7c 100644 --- a/command.h +++ b/command.h @@ -4,7 +4,7 @@ struct MPContext; struct mp_cmd; -int run_command(struct MPContext *mpctx, struct mp_cmd *cmd); +void run_command(struct MPContext *mpctx, struct mp_cmd *cmd); char *property_expand_string(struct MPContext *mpctx, char *str); void property_print_help(void); diff --git a/mplayer.c b/mplayer.c index 04e8dc54b4..0ccb31b8aa 100644 --- a/mplayer.c +++ b/mplayer.c @@ -2514,6 +2514,7 @@ static int seek(MPContext *mpctx, double amount, int style) mpctx->sh_video->last_pts = MP_NOPTS_VALUE; mpctx->num_buffered_frames = 0; mpctx->delay = 0; + mpctx->time_frame = 0; // Not all demuxers set d_video->pts during seek, so this value // (which is used by at least vobsub and edl code below) may // be completely wrong (probably 0). @@ -3743,7 +3744,7 @@ if(!mpctx->sh_audio && mpctx->d_audio->sh) { /*========================== PLAY AUDIO ============================*/ -if (mpctx->sh_audio) +if (mpctx->sh_audio && !mpctx->paused) if (!fill_audio_out_buffers(mpctx)) // at eof, all audio at least written to ao if (!mpctx->sh_video) @@ -3891,16 +3892,6 @@ if(auto_quality>0){ } #endif -//============================ Handle PAUSE =============================== - -// handle -sstep -if(step_sec>0) { - mpctx->osd_function=OSD_FFW; - mpctx->rel_seek_secs+=step_sec; -} - - edl_update(mpctx); - //================= Keyboard events, SEEKing ==================== current_module="key_events"; @@ -3908,20 +3899,28 @@ if(step_sec>0) { { while (1) { mp_cmd_t* cmd; - int brk_cmd = 0; - while( !brk_cmd && (cmd = mp_input_get_cmd(mpctx->input, 0,0,0)) != NULL) { - brk_cmd = run_command(mpctx, cmd); + while ((cmd = mp_input_get_cmd(mpctx->input, 0,0,0)) != NULL) { + run_command(mpctx, cmd); mp_cmd_free(cmd); - if (brk_cmd == 2) - goto goto_enable_cache; + if (mpctx->stop_play) + break; } - if (mpctx->paused && !mpctx->stop_play) + if (mpctx->paused && !(mpctx->stop_play || mpctx->rel_seek_secs + || mpctx->abs_seek_pos)) pause_loop(mpctx); else break; } } +// handle -sstep +if (step_sec > 0 && !mpctx->paused) { + mpctx->osd_function=OSD_FFW; + mpctx->rel_seek_secs+=step_sec; +} + + edl_update(mpctx); + /* Looping. */ if(mpctx->stop_play==AT_END_OF_FILE && opts->loop_times>=0) { mp_msg(MSGT_CPLAYER,MSGL_V,"loop_times = %d\n", opts->loop_times); From 95f35c4d205daafe4797f28d7ec79f3ebb1952a1 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Mon, 1 Dec 2008 16:15:17 +0200 Subject: [PATCH 3/9] vo_xv: Reformat code Reformat vo_xv.c completely to K & R style and remove a couple of outdated comments. --- libvo/vo_xv.c | 485 +++++++++++++++++++++++--------------------------- 1 file changed, 219 insertions(+), 266 deletions(-) diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index f95ea82b53..34f1166f3c 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -95,11 +95,9 @@ struct xvctx { #endif }; -// FIXME: dynamically allocate this stuff static void allocate_xvimage(struct vo *, int); - static void draw_alpha_yv12(void *p, int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) @@ -154,21 +152,22 @@ static void draw_alpha_null(void *p, int x0, int y0, int w, int h, static void deallocate_xvimage(struct vo *vo, int foo); -static void calc_drwXY(struct vo *vo, uint32_t *drwX, uint32_t *drwY) { +static void calc_drwXY(struct vo *vo, uint32_t *drwX, uint32_t *drwY) +{ struct MPOpts *opts = vo->opts; - *drwX = *drwY = 0; - if (vo_fs) { - aspect(vo, &vo->dwidth, &vo->dheight, A_ZOOM); - vo->dwidth = FFMIN(vo->dwidth, opts->vo_screenwidth); - vo->dheight = FFMIN(vo->dheight, opts->vo_screenheight); - *drwX = (opts->vo_screenwidth - vo->dwidth) / 2; - *drwY = (opts->vo_screenheight - vo->dheight) / 2; - mp_msg(MSGT_VO, MSGL_V, "[xv-fs] dx: %d dy: %d dw: %d dh: %d\n", - *drwX, *drwY, vo->dwidth, vo->dheight); - } else if (WinID == 0) { - *drwX = vo->dx; - *drwY = vo->dy; - } + *drwX = *drwY = 0; + if (vo_fs) { + aspect(vo, &vo->dwidth, &vo->dheight, A_ZOOM); + vo->dwidth = FFMIN(vo->dwidth, opts->vo_screenwidth); + vo->dheight = FFMIN(vo->dheight, opts->vo_screenheight); + *drwX = (opts->vo_screenwidth - vo->dwidth) / 2; + *drwY = (opts->vo_screenheight - vo->dheight) / 2; + mp_msg(MSGT_VO, MSGL_V, "[xv-fs] dx: %d dy: %d dw: %d dh: %d\n", *drwX, + *drwY, vo->dwidth, vo->dheight); + } else if (WinID == 0) { + *drwX = vo->dx; + *drwY = vo->dy; + } } /* @@ -193,11 +192,12 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, ctx->image_width = width; ctx->image_format = format; - if ((ctx->max_width != 0 && ctx->max_height != 0) && - (ctx->image_width > ctx->max_width || ctx->image_height > ctx->max_height)) - { - mp_msg( MSGT_VO, MSGL_ERR, MSGTR_VO_XV_ImagedimTooHigh, - ctx->image_width, ctx->image_height, ctx->max_width, ctx->max_height); + if ((ctx->max_width != 0 && ctx->max_height != 0) + && (ctx->image_width > ctx->max_width + || ctx->image_height > ctx->max_height)) { + mp_msg(MSGT_VO, MSGL_ERR, MSGTR_VO_XV_ImagedimTooHigh, + ctx->image_width, ctx->image_height, ctx->max_width, + ctx->max_height); return -1; } @@ -207,9 +207,8 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, /* check image formats */ ctx->xv_format = 0; for (i = 0; i < ctx->formats; i++) { - mp_msg(MSGT_VO, MSGL_V, - "Xvideo image format: 0x%x (%4.4s) %s\n", ctx->fo[i].id, - (char *) &ctx->fo[i].id, + mp_msg(MSGT_VO, MSGL_V, "Xvideo image format: 0x%x (%4.4s) %s\n", + ctx->fo[i].id, (char *) &ctx->fo[i].id, (ctx->fo[i].format == XvPacked) ? "packed" : "planar"); if (ctx->fo[i].id == format) ctx->xv_format = ctx->fo[i].id; @@ -225,8 +224,7 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, { #ifdef CONFIG_XF86VM int vm = flags & VOFLAG_MODESWITCHING; - if (vm) - { + if (vm) { vo_vm_switch(vo); ctx->mode_switched = 1; } @@ -240,25 +238,23 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, xswa.background_pixel = 0; if (x11->xv_ck_info.method == CK_METHOD_BACKGROUND) - { - xswa.background_pixel = x11->xv_colorkey; - } + xswa.background_pixel = x11->xv_colorkey; xswa.border_pixel = 0; xswamask = CWBackPixel | CWBorderPixel; - vo_x11_create_vo_window(vo, &vinfo, vo->dx, vo->dy, vo->dwidth, vo->dheight, - flags, CopyFromParent, "xv", title); - XChangeWindowAttributes(x11->display, x11->window, xswamask, &xswa); + vo_x11_create_vo_window(vo, &vinfo, vo->dx, vo->dy, vo->dwidth, + vo->dheight, flags, CopyFromParent, "xv", + title); + XChangeWindowAttributes(x11->display, x11->window, xswamask, &xswa); #ifdef CONFIG_XF86VM - if (vm) - { + if (vm) { /* Grab the mouse pointer in our window */ if (vo_grabpointer) - XGrabPointer(x11->display, x11->window, True, 0, - GrabModeAsync, GrabModeAsync, - x11->window, None, CurrentTime); - XSetInputFocus(x11->display, x11->window, RevertToNone, CurrentTime); + XGrabPointer(x11->display, x11->window, True, 0, GrabModeAsync, + GrabModeAsync, x11->window, None, CurrentTime); + XSetInputFocus(x11->display, x11->window, RevertToNone, + CurrentTime); } #endif } @@ -266,22 +262,21 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, mp_msg(MSGT_VO, MSGL_V, "using Xvideo port %d for hw scaling\n", x11->xv_port); - switch (ctx->xv_format) - { - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_IYUV: - ctx->draw_alpha_fnc = draw_alpha_yv12; - break; - case IMGFMT_YUY2: - case IMGFMT_YVYU: - ctx->draw_alpha_fnc = draw_alpha_yuy2; - break; - case IMGFMT_UYVY: - ctx->draw_alpha_fnc = draw_alpha_uyvy; - break; - default: - ctx->draw_alpha_fnc = draw_alpha_null; + switch (ctx->xv_format) { + case IMGFMT_YV12: + case IMGFMT_I420: + case IMGFMT_IYUV: + ctx->draw_alpha_fnc = draw_alpha_yv12; + break; + case IMGFMT_YUY2: + case IMGFMT_YVYU: + ctx->draw_alpha_fnc = draw_alpha_yuy2; + break; + case IMGFMT_UYVY: + ctx->draw_alpha_fnc = draw_alpha_uyvy; + break; + default: + ctx->draw_alpha_fnc = draw_alpha_null; } // In case config has been called before @@ -297,11 +292,12 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, ctx->current_buf = 0; ctx->current_ip_buf = 0; - if ((flags & VOFLAG_FULLSCREEN) && WinID <= 0) vo_fs = 1; + if ((flags & VOFLAG_FULLSCREEN) && WinID <= 0) + vo_fs = 1; calc_drwXY(vo, &ctx->drwX, &ctx->drwY); panscan_calc(vo); - + vo_xv_draw_colorkey(vo, ctx->drwX - (vo->panscan_x >> 1), ctx->drwY - (vo->panscan_y >> 1), vo->dwidth + vo->panscan_x - 1, @@ -324,22 +320,22 @@ static void allocate_xvimage(struct vo *vo, int foo) #ifdef HAVE_SHM if (x11->display_is_local && XShmQueryExtension(x11->display)) ctx->Shmem_Flag = 1; - else - { + else { ctx->Shmem_Flag = 0; - mp_msg(MSGT_VO, MSGL_INFO, - MSGTR_LIBVO_XV_SharedMemoryNotSupported); + mp_msg(MSGT_VO, MSGL_INFO, MSGTR_LIBVO_XV_SharedMemoryNotSupported); } - if (ctx->Shmem_Flag) - { + if (ctx->Shmem_Flag) { ctx->xvimage[foo] = - (XvImage *) XvShmCreateImage(x11->display, x11->xv_port, ctx->xv_format, - NULL, ctx->image_width, ctx->image_height, + (XvImage *) XvShmCreateImage(x11->display, x11->xv_port, + ctx->xv_format, NULL, + ctx->image_width, ctx->image_height, &ctx->Shminfo[foo]); - ctx->Shminfo[foo].shmid = - shmget(IPC_PRIVATE, ctx->xvimage[foo]->data_size, IPC_CREAT | 0777); - ctx->Shminfo[foo].shmaddr = (char *) shmat(ctx->Shminfo[foo].shmid, 0, 0); + ctx->Shminfo[foo].shmid = shmget(IPC_PRIVATE, + ctx->xvimage[foo]->data_size, + IPC_CREAT | 0777); + ctx->Shminfo[foo].shmaddr = (char *) shmat(ctx->Shminfo[foo].shmid, 0, + 0); ctx->Shminfo[foo].readOnly = False; ctx->xvimage[foo]->data = ctx->Shminfo[foo].shmaddr; @@ -350,8 +346,9 @@ static void allocate_xvimage(struct vo *vo, int foo) #endif { ctx->xvimage[foo] = - (XvImage *) XvCreateImage(x11->display, x11->xv_port, ctx->xv_format, NULL, - ctx->image_width, ctx->image_height); + (XvImage *) XvCreateImage(x11->display, x11->xv_port, + ctx->xv_format, NULL, ctx->image_width, + ctx->image_height); ctx->xvimage[foo]->data = malloc(ctx->xvimage[foo]->data_size); XSync(x11->display, False); } @@ -363,8 +360,7 @@ static void deallocate_xvimage(struct vo *vo, int foo) { struct xvctx *ctx = vo->priv; #ifdef HAVE_SHM - if (ctx->Shmem_Flag) - { + if (ctx->Shmem_Flag) { XShmDetach(vo->x11->display, &ctx->Shminfo[foo]); shmdt(ctx->Shminfo[foo].shmaddr); } else @@ -383,22 +379,21 @@ static inline void put_xvimage(struct vo *vo, XvImage *xvi) struct xvctx *ctx = vo->priv; struct vo_x11_state *x11 = vo->x11; #ifdef HAVE_SHM - if (ctx->Shmem_Flag) - { - XvShmPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, - xvi, 0, 0, ctx->image_width, - ctx->image_height, ctx->drwX - (vo->panscan_x >> 1), - ctx->drwY - (vo->panscan_y >> 1), vo->dwidth + vo->panscan_x, - vo->dheight + vo->panscan_y, + if (ctx->Shmem_Flag) { + XvShmPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, xvi, + 0, 0, ctx->image_width, ctx->image_height, + ctx->drwX - (vo->panscan_x >> 1), + ctx->drwY - (vo->panscan_y >> 1), + vo->dwidth + vo->panscan_x, vo->dheight + vo->panscan_y, False); } else #endif { - XvPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, - xvi, 0, 0, ctx->image_width, ctx->image_height, - ctx->drwX - (vo->panscan_x >> 1), ctx->drwY - (vo->panscan_y >> 1), - vo->dwidth + vo->panscan_x, - vo->dheight + vo->panscan_y); + XvPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, xvi, 0, + 0, ctx->image_width, ctx->image_height, + ctx->drwX - (vo->panscan_x >> 1), + ctx->drwY - (vo->panscan_y >> 1), + vo->dwidth + vo->panscan_x, vo->dheight + vo->panscan_y); } } @@ -411,21 +406,18 @@ static void check_events(struct vo *vo) if (e & VO_EVENT_RESIZE) calc_drwXY(vo, &ctx->drwX, &ctx->drwY); - if (e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) - { - vo_xv_draw_colorkey(vo, ctx->drwX - (vo->panscan_x >> 1), - ctx->drwY - (vo->panscan_y >> 1), - vo->dwidth + vo->panscan_x - 1, - vo->dheight + vo->panscan_y - 1); + if (e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) { + vo_xv_draw_colorkey(vo, ctx->drwX - (vo->panscan_x >> 1), + ctx->drwY - (vo->panscan_y >> 1), + vo->dwidth + vo->panscan_x - 1, + vo->dheight + vo->panscan_y - 1); } - if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && ctx->is_paused) - { + if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && ctx->is_paused) { /* did we already draw a buffer */ - if ( ctx->visible_buf != -1 ) - { - /* redraw the last visible buffer */ - put_xvimage(vo, ctx->xvimage[ctx->visible_buf]); + if (ctx->visible_buf != -1) { + /* redraw the last visible buffer */ + put_xvimage(vo, ctx->xvimage[ctx->visible_buf]); } } } @@ -434,8 +426,10 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) { struct xvctx *ctx = vo->priv; - osd_draw_text(osd, ctx->image_width - - ctx->image_width * vo->panscan_x / (vo->dwidth + vo->panscan_x), + osd_draw_text(osd, + ctx->image_width - + ctx->image_width * vo->panscan_x / (vo->dwidth + + vo->panscan_x), ctx->image_height, ctx->draw_alpha_fnc, vo); } @@ -447,77 +441,68 @@ static void flip_page(struct vo *vo) /* remember the currently visible buffer */ ctx->visible_buf = ctx->current_buf; - if (ctx->num_buffers > 1) - { - ctx->current_buf = - vo_directrendering ? 0 : ((ctx->current_buf + 1) % ctx->num_buffers); + if (ctx->num_buffers > 1) { + ctx->current_buf = vo_directrendering ? 0 : ((ctx->current_buf + 1) % + ctx->num_buffers); XFlush(vo->x11->display); } else XSync(vo->x11->display, False); return; } -static int draw_slice(struct vo *vo, uint8_t * image[], int stride[], int w, +static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], int w, int h, int x, int y) { struct xvctx *ctx = vo->priv; uint8_t *dst; XvImage *current_image = ctx->xvimage[ctx->current_buf]; - dst = current_image->data + current_image->offsets[0] + - current_image->pitches[0] * y + x; - memcpy_pic(dst, image[0], w, h, current_image->pitches[0], - stride[0]); + dst = current_image->data + current_image->offsets[0] + + current_image->pitches[0] * y + x; + memcpy_pic(dst, image[0], w, h, current_image->pitches[0], stride[0]); x /= 2; y /= 2; w /= 2; h /= 2; - dst = current_image->data + current_image->offsets[1] + - current_image->pitches[1] * y + x; + dst = current_image->data + current_image->offsets[1] + + current_image->pitches[1] * y + x; if (ctx->image_format != IMGFMT_YV12) - memcpy_pic(dst, image[1], w, h, current_image->pitches[1], - stride[1]); + memcpy_pic(dst, image[1], w, h, current_image->pitches[1], stride[1]); else - memcpy_pic(dst, image[2], w, h, current_image->pitches[1], - stride[2]); + memcpy_pic(dst, image[2], w, h, current_image->pitches[1], stride[2]); - dst = current_image->data + current_image->offsets[2] + - current_image->pitches[2] * y + x; + dst = current_image->data + current_image->offsets[2] + + current_image->pitches[2] * y + x; if (ctx->image_format == IMGFMT_YV12) - memcpy_pic(dst, image[1], w, h, current_image->pitches[1], - stride[1]); + memcpy_pic(dst, image[1], w, h, current_image->pitches[1], stride[1]); else - memcpy_pic(dst, image[2], w, h, current_image->pitches[1], - stride[2]); + memcpy_pic(dst, image[2], w, h, current_image->pitches[1], stride[2]); return 0; } -static int draw_frame(struct vo *vo, uint8_t * src[]) +static int draw_frame(struct vo *vo, uint8_t *src[]) { return VO_ERROR; } -static uint32_t draw_image(struct vo *vo, mp_image_t * mpi) +static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) { struct xvctx *ctx = vo->priv; - if (mpi->flags & MP_IMGFLAG_DIRECT) - { + 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) - { + 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) - { + 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], @@ -528,18 +513,17 @@ static uint32_t draw_image(struct vo *vo, mp_image_t * mpi) return VO_FALSE; // not (yet) supported } -static uint32_t get_image(struct xvctx *ctx, mp_image_t * mpi) +static uint32_t get_image(struct xvctx *ctx, mp_image_t *mpi) { - int buf = ctx->current_buf; // we shouldn't change current_buf unless we do DR! + // we shouldn't change current_buf unless we do DR! + int buf = ctx->current_buf; if (mpi->type == MP_IMGTYPE_STATIC && ctx->num_buffers > 1) return VO_FALSE; // it is not static if (mpi->imgfmt != ctx->image_format) return VO_FALSE; // needs conversion :( -// if(mpi->flags&MP_IMGFLAG_READABLE) return VO_FALSE; // slow video ram - if (mpi->flags & MP_IMGFLAG_READABLE && - (mpi->type == MP_IMGTYPE_IPB || mpi->type == MP_IMGTYPE_IP)) - { + if (mpi->flags & MP_IMGFLAG_READABLE + && (mpi->type == MP_IMGTYPE_IPB || mpi->type == MP_IMGTYPE_IP)) { // reference (I/P) frame of IP or IPB: if (ctx->num_buffers < 2) return VO_FALSE; // not enough @@ -557,42 +541,33 @@ static uint32_t get_image(struct xvctx *ctx, mp_image_t * mpi) if (mpi->width * (mpi->bpp / 8) > ctx->xvimage[buf]->pitches[0]) return VO_FALSE; //buffer to small if ((mpi->flags & (MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_ACCEPT_WIDTH)) - || (mpi->width * (mpi->bpp / 8) == ctx->xvimage[buf]->pitches[0])) - { + || (mpi->width * (mpi->bpp / 8) == ctx->xvimage[buf]->pitches[0])) { ctx->current_buf = buf; XvImage *current_image = ctx->xvimage[ctx->current_buf]; mpi->planes[0] = current_image->data + current_image->offsets[0]; mpi->stride[0] = current_image->pitches[0]; mpi->width = mpi->stride[0] / (mpi->bpp / 8); - if (mpi->flags & MP_IMGFLAG_PLANAR) - { - if (mpi->flags & MP_IMGFLAG_SWAPPED) - { + if (mpi->flags & MP_IMGFLAG_PLANAR) { + if (mpi->flags & MP_IMGFLAG_SWAPPED) { // I420 - mpi->planes[1] = - current_image->data + - current_image->offsets[1]; - mpi->planes[2] = - current_image->data + - current_image->offsets[2]; + mpi->planes[1] = current_image->data + + current_image->offsets[1]; + mpi->planes[2] = current_image->data + + current_image->offsets[2]; mpi->stride[1] = current_image->pitches[1]; mpi->stride[2] = current_image->pitches[2]; - } else - { + } else { // YV12 - mpi->planes[1] = - current_image->data + - current_image->offsets[2]; - mpi->planes[2] = - current_image->data + - current_image->offsets[1]; + mpi->planes[1] = current_image->data + + current_image->offsets[2]; + mpi->planes[2] = current_image->data + + current_image->offsets[1]; mpi->stride[1] = current_image->pitches[2]; mpi->stride[2] = current_image->pitches[1]; } } mpi->flags |= MP_IMGFLAG_DIRECT; mpi->priv = (void *) ctx->current_buf; -// printf("mga: get_image() SUCCESS -> Direct Rendering ENABLED\n"); return VO_TRUE; } return VO_FALSE; @@ -604,8 +579,7 @@ static int query_format(struct xvctx *ctx, uint32_t format) int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN /* check image formats */ - for (i = 0; i < ctx->formats; i++) - { + for (i = 0; i < ctx->formats; i++) { if (ctx->fo[i].id == format) return flag; //xv_format = fo[i].id; } @@ -656,22 +630,20 @@ static int preinit(struct vo *vo, const char *arg) struct vo_x11_state *x11 = vo->x11; int xv_adaptor = -1; - opt_t subopts[] = - { - /* name arg type arg var test */ - { "port", OPT_ARG_INT, &x11->xv_port, (opt_test_f)int_pos }, - { "adaptor", OPT_ARG_INT, &xv_adaptor, (opt_test_f)int_non_neg }, - { "ck", OPT_ARG_STR, &ck_src_arg, xv_test_ck }, - { "ck-method", OPT_ARG_STR, &ck_method_arg, xv_test_ckm }, - { NULL } + opt_t subopts[] = { + /* name arg type arg var test */ + {"port", OPT_ARG_INT, &x11->xv_port, (opt_test_f) int_pos}, + {"adaptor", OPT_ARG_INT, &xv_adaptor, (opt_test_f) int_non_neg}, + {"ck", OPT_ARG_STR, &ck_src_arg, xv_test_ck}, + {"ck-method", OPT_ARG_STR, &ck_method_arg, xv_test_ckm}, + {NULL} }; x11->xv_port = 0; /* parse suboptions */ - if ( subopt_parse( arg, subopts ) != 0 ) - { - return -1; + if (subopt_parse(arg, subopts) != 0) { + return -1; } /* modify colorkey settings according to the given options */ @@ -682,105 +654,90 @@ static int preinit(struct vo *vo, const char *arg) /* check for Xvideo extension */ unsigned int ver, rel, req, ev, err; - if (Success != XvQueryExtension(x11->display, &ver, &rel, &req, &ev, &err)) - { - mp_msg(MSGT_VO, MSGL_ERR, - MSGTR_LIBVO_XV_XvNotSupportedByX11); + if (Success != XvQueryExtension(x11->display, &ver, &rel, &req, &ev, &err)) { + mp_msg(MSGT_VO, MSGL_ERR, MSGTR_LIBVO_XV_XvNotSupportedByX11); goto error; } /* check for Xvideo support */ if (Success != - XvQueryAdaptors(x11->display, DefaultRootWindow(x11->display), &ctx->adaptors, - &ctx->ai)) - { + XvQueryAdaptors(x11->display, DefaultRootWindow(x11->display), + &ctx->adaptors, &ctx->ai)) { mp_msg(MSGT_VO, MSGL_ERR, MSGTR_LIBVO_XV_XvQueryAdaptorsFailed); goto error; } /* check adaptors */ - if (x11->xv_port) - { + if (x11->xv_port) { int port_found; - for (port_found = 0, i = 0; !port_found && i < ctx->adaptors; i++) - { - if ((ctx->ai[i].type & XvInputMask) && (ctx->ai[i].type & XvImageMask)) - { + for (port_found = 0, i = 0; !port_found && i < ctx->adaptors; i++) { + if ((ctx->ai[i].type & XvInputMask) + && (ctx->ai[i].type & XvImageMask)) { for (xv_p = ctx->ai[i].base_id; - xv_p < ctx->ai[i].base_id + ctx->ai[i].num_ports; ++xv_p) - { - if (xv_p == x11->xv_port) - { + xv_p < ctx->ai[i].base_id + ctx->ai[i].num_ports; + ++xv_p) { + if (xv_p == x11->xv_port) { port_found = 1; break; } } } } - if (port_found) - { + if (port_found) { if (XvGrabPort(x11->display, x11->xv_port, CurrentTime)) x11->xv_port = 0; - } else - { - mp_msg(MSGT_VO, MSGL_WARN, - MSGTR_LIBVO_XV_InvalidPortParameter); + } else { + mp_msg(MSGT_VO, MSGL_WARN, MSGTR_LIBVO_XV_InvalidPortParameter); x11->xv_port = 0; } } - for (i = 0; i < ctx->adaptors && x11->xv_port == 0; i++) - { + for (i = 0; i < ctx->adaptors && x11->xv_port == 0; i++) { /* check if adaptor number has been specified */ if (xv_adaptor != -1 && xv_adaptor != i) - continue; + continue; - if ((ctx->ai[i].type & XvInputMask) && (ctx->ai[i].type & XvImageMask)) - { + if ((ctx->ai[i].type & XvInputMask) && (ctx->ai[i].type & XvImageMask)) { for (xv_p = ctx->ai[i].base_id; xv_p < ctx->ai[i].base_id + ctx->ai[i].num_ports; ++xv_p) - if (!XvGrabPort(x11->display, xv_p, CurrentTime)) - { + if (!XvGrabPort(x11->display, xv_p, CurrentTime)) { x11->xv_port = xv_p; mp_msg(MSGT_VO, MSGL_V, "[VO_XV] Using Xv Adapter #%d (%s)\n", i, ctx->ai[i].name); break; - } else - { - mp_msg(MSGT_VO, MSGL_WARN, - MSGTR_LIBVO_XV_CouldNotGrabPort, (int) xv_p); + } else { + mp_msg(MSGT_VO, MSGL_WARN, MSGTR_LIBVO_XV_CouldNotGrabPort, + (int) xv_p); ++busy_ports; } } } - if (!x11->xv_port) - { + if (!x11->xv_port) { if (busy_ports) - mp_msg(MSGT_VO, MSGL_ERR, - MSGTR_LIBVO_XV_CouldNotFindFreePort); + mp_msg(MSGT_VO, MSGL_ERR, MSGTR_LIBVO_XV_CouldNotFindFreePort); else - mp_msg(MSGT_VO, MSGL_ERR, - MSGTR_LIBVO_XV_NoXvideoSupport); + mp_msg(MSGT_VO, MSGL_ERR, MSGTR_LIBVO_XV_NoXvideoSupport); goto error; } if (!vo_xv_init_colorkey(vo)) { - goto error; // bail out, colorkey setup failed + goto error; // bail out, colorkey setup failed } vo_xv_enable_vsync(vo); vo_xv_get_max_img_dim(vo, &ctx->max_width, &ctx->max_height); - ctx->fo = XvListImageFormats(x11->display, x11->xv_port, (int *) &ctx->formats); + ctx->fo = XvListImageFormats(x11->display, x11->xv_port, + (int *) &ctx->formats); mp_input_add_key_fd(vo->input_ctx, ConnectionNumber(x11->display), 1, x11_fd_callback, NULL, vo); ctx->event_fd_registered = 1; return 0; - error: - uninit(vo); // free resources + error: + uninit(vo); // free resources return -1; } @@ -788,65 +745,61 @@ static int control(struct vo *vo, uint32_t request, void *data) { struct xvctx *ctx = vo->priv; struct vo_x11_state *x11 = vo->x11; - switch (request) - { - case VOCTRL_PAUSE: - return (ctx->is_paused = 1); - case VOCTRL_RESUME: - return (ctx->is_paused = 0); - case VOCTRL_QUERY_FORMAT: - return query_format(ctx, *((uint32_t *) data)); - case VOCTRL_GET_IMAGE: - return get_image(ctx, data); - case VOCTRL_DRAW_IMAGE: - return draw_image(vo, data); - case VOCTRL_GUISUPPORT: - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - if (!vo->config_ok || !vo_fs) - return VO_FALSE; - return VO_TRUE; - case VOCTRL_FULLSCREEN: - vo_x11_fullscreen(vo); - /* indended, fallthrough to update panscan on fullscreen/windowed switch */ - case VOCTRL_SET_PANSCAN: - if ((vo_fs && (vo_panscan != vo->panscan_amount)) - || (!vo_fs && vo->panscan_amount)) - { - int old_y = vo->panscan_y; + switch (request) { + case VOCTRL_PAUSE: + return (ctx->is_paused = 1); + case VOCTRL_RESUME: + return (ctx->is_paused = 0); + case VOCTRL_QUERY_FORMAT: + return query_format(ctx, *((uint32_t *) data)); + case VOCTRL_GET_IMAGE: + return get_image(ctx, data); + case VOCTRL_DRAW_IMAGE: + return draw_image(vo, data); + case VOCTRL_GUISUPPORT: + return VO_TRUE; + case VOCTRL_GET_PANSCAN: + if (!vo->config_ok || !vo_fs) + return VO_FALSE; + return VO_TRUE; + case VOCTRL_FULLSCREEN: + vo_x11_fullscreen(vo); + /* indended, fallthrough to update panscan on fullscreen/windowed switch */ + case VOCTRL_SET_PANSCAN: + if ((vo_fs && (vo_panscan != vo->panscan_amount)) + || (!vo_fs && vo->panscan_amount)) { + int old_y = vo->panscan_y; - panscan_calc(vo); + panscan_calc(vo); - if (old_y != vo->panscan_y) - { - vo_x11_clearwindow_part(vo, x11->window, - vo->dwidth + vo->panscan_x - 1, - vo->dheight + vo->panscan_y - 1, - 1); - vo_xv_draw_colorkey(vo, ctx->drwX - (vo->panscan_x >> 1), - ctx->drwY - (vo->panscan_y >> 1), - vo->dwidth + vo->panscan_x - 1, - vo->dheight + vo->panscan_y - 1); - flip_page(vo); - } + if (old_y != vo->panscan_y) { + vo_x11_clearwindow_part(vo, x11->window, + vo->dwidth + vo->panscan_x - 1, + vo->dheight + vo->panscan_y - 1, 1); + vo_xv_draw_colorkey(vo, ctx->drwX - (vo->panscan_x >> 1), + ctx->drwY - (vo->panscan_y >> 1), + vo->dwidth + vo->panscan_x - 1, + vo->dheight + vo->panscan_y - 1); + flip_page(vo); } - return VO_TRUE; - case VOCTRL_SET_EQUALIZER: - { - struct voctrl_set_equalizer_args *args = data; - return vo_xv_set_eq(vo, x11->xv_port, args->name, args->value); - } - case VOCTRL_GET_EQUALIZER: - { - struct voctrl_get_equalizer_args *args = data; - return vo_xv_get_eq(vo, x11->xv_port, args->name, args->valueptr); - } - case VOCTRL_ONTOP: - vo_x11_ontop(vo); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - update_xinerama_info(vo); - return VO_TRUE; + } + return VO_TRUE; + case VOCTRL_SET_EQUALIZER: + { + struct voctrl_set_equalizer_args *args = data; + return vo_xv_set_eq(vo, x11->xv_port, args->name, args->value); + } + case VOCTRL_GET_EQUALIZER: + { + struct voctrl_get_equalizer_args *args = data; + return vo_xv_get_eq(vo, x11->xv_port, args->name, args->valueptr); + } + case VOCTRL_ONTOP: + vo_x11_ontop(vo); + return VO_TRUE; + case VOCTRL_UPDATE_SCREENINFO: + update_xinerama_info(vo); + return VO_TRUE; } return VO_NOTIMPL; } From 02efad79a28345e5814af1b60e0bb3c40cb5a941 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Mon, 1 Dec 2008 19:53:57 +0200 Subject: [PATCH 4/9] 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. --- command.c | 11 +++--- libmpcodecs/dec_video.c | 9 +++++ libmpcodecs/dec_video.h | 1 + libmpcodecs/vf.h | 1 + libmpcodecs/vf_expand.c | 6 ++++ libmpcodecs/vf_vo.c | 3 ++ libvo/video_out.h | 2 ++ libvo/vo_xv.c | 75 ++++++++++++++++++++++++++++++++--------- mp_core.h | 1 + mplayer.c | 32 ++++++++++++++---- 10 files changed, 115 insertions(+), 26 deletions(-) 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); } } From 5204fda1213f1bb876fd71f16f44767edc8eae46 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Tue, 2 Dec 2008 01:02:52 +0200 Subject: [PATCH 5/9] vo_xv: Always support updating OSD if none was drawn yet If the main image buffer was not altered for OSD then allow updating OSD even if no separate OSD-less copy was made. The code now makes a copy at that time (another possibility would be to not make a copy and disallow further updates). --- libvo/vo_xv.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 052417422f..9c4dd391df 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -80,6 +80,8 @@ struct xvctx { int total_buffers; int have_visible_image_copy; int have_next_image_copy; + int unchanged_visible_image; + int unchanged_next_image; int visible_buf; XvImage *xvimage[NUM_BUFFERS + 1]; uint32_t image_width; @@ -90,6 +92,7 @@ struct xvctx { uint32_t max_width, max_height; // zero means: not set int event_fd_registered; // for uninit called from preinit int mode_switched; + int osd_objects_drawn; void (*draw_alpha_fnc)(void *ctx, int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride); @@ -115,6 +118,7 @@ static void draw_alpha_yv12(void *p, int x0, int y0, int w, int h, ctx->xvimage[ctx->current_buf]->offsets[0] + ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + x0, ctx->xvimage[ctx->current_buf]->pitches[0]); + ctx->osd_objects_drawn++; } static void draw_alpha_yuy2(void *p, int x0, int y0, int w, int h, @@ -130,6 +134,7 @@ static void draw_alpha_yuy2(void *p, int x0, int y0, int w, int h, ctx->xvimage[ctx->current_buf]->offsets[0] + ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + 2 * x0, ctx->xvimage[ctx->current_buf]->pitches[0]); + ctx->osd_objects_drawn++; } static void draw_alpha_uyvy(void *p, int x0, int y0, int w, int h, @@ -145,6 +150,7 @@ static void draw_alpha_uyvy(void *p, int x0, int y0, int w, int h, ctx->xvimage[ctx->current_buf]->offsets[0] + ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + 2 * x0 + 1, ctx->xvimage[ctx->current_buf]->pitches[0]); + ctx->osd_objects_drawn++; } static void draw_alpha_null(void *p, int x0, int y0, int w, int h, @@ -445,22 +451,28 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) { struct xvctx *ctx = vo->priv; + ctx->osd_objects_drawn = 0; osd_draw_text(osd, ctx->image_width - ctx->image_width * vo->panscan_x / (vo->dwidth + vo->panscan_x), ctx->image_height, ctx->draw_alpha_fnc, vo); + if (ctx->osd_objects_drawn) + ctx->unchanged_next_image = false; } 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) + if (ctx->have_visible_image_copy) + copy_backup_image(vo, ctx->visible_buf, ctx->num_buffers); + else if (ctx->unchanged_visible_image) { + copy_backup_image(vo, ctx->num_buffers, ctx->visible_buf); + ctx->have_visible_image_copy = true; + } + else 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); @@ -479,6 +491,8 @@ static void flip_page(struct vo *vo) ctx->have_visible_image_copy = ctx->have_next_image_copy; ctx->have_next_image_copy = false; + ctx->unchanged_visible_image = ctx->unchanged_next_image; + ctx->unchanged_next_image = false; if (ctx->num_buffers > 1) { ctx->current_buf = vo_directrendering ? 0 : ((ctx->current_buf + 1) % @@ -553,6 +567,7 @@ static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) copy_backup_image(vo, ctx->num_buffers, ctx->current_buf); ctx->have_next_image_copy = true; } + ctx->unchanged_next_image = true; return true; } From 321c93ee998266cff4ce5b5eff2aaba4e2311dd0 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Mon, 8 Dec 2008 20:04:08 +0200 Subject: [PATCH 6/9] core: Rewrite some of the A/V sync related code Notable functionality changes: * Timing change between any two frames is now accurately limited to 1/10 of their nominal distance. Previous code did not always use the correct duration. * The status line now keeps showing the same A-V sync value from one video frame change to the next. Previously it kept recalculating the value using a new audio position but the same video position when the status line was updated between video frames. This incorrectly showed the video losing sync with audio. * The status line now displays actual measured A-V difference in autosync mode too. The previous code displayed values that completely ignored real timing in autosync mode, showing 0 A-V difference even when video was significantly behind audio due to inadequate decoding speed. The new behavior can make the shown A-V values appear more unstable if the audio out has unreliable delay measurements (the most likely reason to use autosync), but this is a display change rather than a timing quality change. * Autosync mode now tries to adjust timing by the amount of time vo_flip() calls take, so the calls start earlier and finish at the time the frame should be shown. Previously non-autosync mode adjusted for this but autosync did not. * The warning about the system being too slow to decode the video in realtime is now displayed in autosync mode too. --- mp_core.h | 20 ++++++++ mplayer.c | 149 +++++++++++++++++++++++++----------------------------- 2 files changed, 88 insertions(+), 81 deletions(-) diff --git a/mp_core.h b/mp_core.h index a346c75dce..c9a843a78e 100644 --- a/mp_core.h +++ b/mp_core.h @@ -1,6 +1,8 @@ #ifndef MPLAYER_MP_CORE_H #define MPLAYER_MP_CORE_H +#include + #include "options.h" #include "mixer.h" #include "subreader.h" @@ -76,6 +78,9 @@ typedef struct MPContext { // struct. int num_buffered_frames; + // Show a video frame as quickly as possible without trying to adjust + // for AV sync. Used when starting a file or after seeking. + bool update_video_immediately; // AV sync: the next frame should be shown when the audio out has this // much (in seconds) buffered data left. Increased when more data is // written to the ao, decreased when moving to the next frame. @@ -84,6 +89,17 @@ typedef struct MPContext { double delay; // AV sync: time until next frame should be shown float time_frame; + // How long the last vo flip() call took. Used to adjust timing with + // the goal of making flip() calls finish (rather than start) at the + // specified time. + float last_vo_flip_duration; + // How much video timing has been changed to make it match the audio + // timeline. Used for status line information only. + double total_avsync_change; + // A-V sync difference when last frame was displayed. Kept to display + // the same value if the status line is updated at a time where no new + // video frame is shown. + double last_av_difference; // Timestamp from the last time some timing functions read the // current time, in (occasionally wrapping) microseconds. Used @@ -118,6 +134,10 @@ typedef struct MPContext { // step this many frames, then pause int step_frames; + // Set after showing warning about decoding being too slow for realtime + // playback rate. Used to avoid showing it multiple times. + bool drop_message_shown; + #ifdef CONFIG_DVDNAV struct mp_image *nav_smpi; ///< last decoded dvdnav video image unsigned char *nav_buffer; ///< last read dvdnav video frame diff --git a/mplayer.c b/mplayer.c index 36e6c5d5f8..cc83c9e83c 100644 --- a/mplayer.c +++ b/mplayer.c @@ -4,6 +4,7 @@ #include #include +#include #include "config.h" #include "talloc.h" @@ -259,8 +260,6 @@ static char *stream_dump_name="stream.dump"; // A-V sync: static float default_max_pts_correction=-1;//0.01f; -static float max_pts_correction=0;//default_max_pts_correction; -static float c_total=0; float audio_delay=0; static int ignore_start=0; @@ -1160,16 +1159,25 @@ static void sadd_hhmmssf(char *buf, unsigned *pos, int len, float time) { saddf(buf, pos, len, "%02d.%1d", ss, f1); } -/** - * \brief print the status line - * \param a_pos audio position - * \param a_v A-V desynchronization - * \param corr amount out A-V synchronization - */ -static void print_status(struct MPContext *mpctx, float a_pos, float a_v, float corr) +static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame) { struct MPOpts *opts = &mpctx->opts; sh_video_t * const sh_video = mpctx->sh_video; + + if (mpctx->sh_audio && a_pos == MP_NOPTS_VALUE) + a_pos = playing_audio_pts(mpctx); + if (mpctx->sh_audio && sh_video && at_frame) { + mpctx->last_av_difference = a_pos - sh_video->pts - audio_delay; + if (mpctx->last_av_difference > 0.5 && drop_frame_cnt > 50 + && !mpctx->drop_message_shown) { + mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow); + mpctx->drop_message_shown = true; + } + } + if (quiet) + return; + + int width; char *line; unsigned pos = 0; @@ -1204,7 +1212,8 @@ static void print_status(struct MPContext *mpctx, float a_pos, float a_v, float // A-V sync if (mpctx->sh_audio && sh_video) - saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ", a_v, corr); + saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ", + mpctx->last_av_difference, mpctx->total_avsync_change); // Video stats if (sh_video) @@ -1696,7 +1705,8 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time) { ++total_frame_cnt; // we should avoid dropping too many frames in sequence unless we // are too late. and we allow 100ms A-V delay here: - if (d < -dropped_frames*frame_time-0.100 && !mpctx->paused) { + if (d < -dropped_frames*frame_time-0.100 && !mpctx->paused + && !mpctx->update_video_immediately) { ++drop_frame_cnt; ++dropped_frames; return frame_dropping; @@ -1921,71 +1931,39 @@ static void mp_dvdnav_save_smpi(struct MPContext *mpctx, int in_size, } #endif /* CONFIG_DVDNAV */ -static void adjust_sync_and_print_status(struct MPContext *mpctx, - int between_frames, - float timing_error) +/* Modify video timing to match the audio timeline. There are two main + * reasons this is needed. First, video and audio can start from different + * positions at beginning of file or after a seek (MPlayer starts both + * immediately even if they have different pts). Second, the file can have + * audio timestamps that are inconsistent with the duration of the audio + * packets, for example two consecutive timestamp values differing by + * one second but only a packet with enough samples for half a second + * of playback between them. + */ +static void adjust_sync(struct MPContext *mpctx, double frame_time) { struct MPOpts *opts = &mpctx->opts; - current_module="av_sync"; + current_module = "av_sync"; - if(mpctx->sh_audio){ - double a_pts, v_pts; + if (!mpctx->sh_audio) + return; - if (autosync) - /* - * If autosync is enabled, the value for delay must be calculated - * a bit differently. It is set only to the difference between - * the audio and video timers. Any attempt to include the real - * or corrected delay causes the pts_correction code below to - * try to correct for the changes in delay which autosync is - * trying to measure. This keeps the two from competing, but still - * allows the code to correct for PTS drift *only*. (Using a delay - * value here, even a "corrected" one, would be incompatible with - * autosync mode.) - */ - a_pts = written_audio_pts(mpctx) - mpctx->delay; - else - a_pts = playing_audio_pts(mpctx); + double a_pts = written_audio_pts(mpctx) - mpctx->delay; + double v_pts = mpctx->sh_video->pts; + double av_delay = a_pts - v_pts; + // Try to sync vo_flip() so it will *finish* at given time + av_delay += mpctx->last_vo_flip_duration; + av_delay -= audio_delay; // This much pts difference is desired - v_pts = mpctx->sh_video->pts; - - { - static int drop_message=0; - double AV_delay = a_pts - audio_delay - v_pts; - double x; - if (AV_delay>0.5 && drop_frame_cnt>50 && drop_message==0){ - ++drop_message; - mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow); - } - if (autosync) - x = AV_delay*0.1f; - else - /* Do not correct target time for the next frame if this frame - * was late not because of wrong target time but because the - * target time could not be met */ - x = (AV_delay + timing_error * opts->playback_speed) * 0.1f; - if (x < -max_pts_correction) - x = -max_pts_correction; - else if (x> max_pts_correction) - x = max_pts_correction; - if (default_max_pts_correction >= 0) - max_pts_correction = default_max_pts_correction; - else - max_pts_correction = mpctx->sh_video->frametime*0.10; // +-10% of time - if (!between_frames) { - mpctx->delay+=x; - c_total+=x; - } - if(!quiet) - print_status(mpctx, a_pts - audio_delay, AV_delay, c_total); - } - - } else { - // No audio: - - if (!quiet) - print_status(mpctx, 0, 0, 0); - } + double change = av_delay * 0.1; + double max_change = default_max_pts_correction >= 0 ? + default_max_pts_correction : frame_time * 0.1; + if (change < -max_change) + change = -max_change; + else if (change > max_change) + change = max_change; + mpctx->delay += change; + mpctx->total_avsync_change += change; } static int fill_audio_out_buffers(struct MPContext *mpctx) @@ -2522,6 +2500,7 @@ static int seek(MPContext *mpctx, double amount, int style) mpctx->num_buffered_frames = 0; mpctx->delay = 0; mpctx->time_frame = 0; + mpctx->update_video_immediately = true; // Not all demuxers set d_video->pts during seek, so this value // (which is used by at least vobsub and edl code below) may // be completely wrong (probably 0). @@ -2544,8 +2523,7 @@ static int seek(MPContext *mpctx, double amount, int style) edl_seek_reset(mpctx); - c_total = 0; - max_pts_correction = 0.1; + mpctx->total_avsync_change = 0; audio_time_usage = 0; video_time_usage = 0; vout_time_usage = 0; drop_frame_cnt = 0; @@ -3733,6 +3711,9 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) { get_relative_time(mpctx); // reset current delta mpctx->time_frame = 0; + mpctx->drop_message_shown = 0; + mpctx->update_video_immediately = true; + mpctx->total_avsync_change = 0; while(!mpctx->stop_play){ float aq_sleep_time=0; @@ -3763,11 +3744,10 @@ if(!mpctx->sh_video) { double a_pos=0; // sh_audio can be NULL due to video stream switching // TODO: handle this better - if(!quiet || end_at.type == END_AT_TIME && mpctx->sh_audio) + if (mpctx->sh_audio) a_pos = playing_audio_pts(mpctx); - if(!quiet) - print_status(mpctx, a_pos, 0, 0); + print_status(mpctx, a_pos, false); if(end_at.type == END_AT_TIME && end_at.pos < a_pos) mpctx->stop_play = PT_NEXT_ENTRY; @@ -3795,7 +3775,13 @@ if(!mpctx->sh_video) { else { // might return with !eof && !blit_frame if !correct_pts mpctx->num_buffered_frames += blit_frame; - mpctx->time_frame += frame_time / opts->playback_speed; // for nosound + if (mpctx->update_video_immediately) { + // Show this frame immediately, rest normally + mpctx->update_video_immediately = false; + } else { + mpctx->time_frame += frame_time / opts->playback_speed; + adjust_sync(mpctx, frame_time); + } } } @@ -3837,11 +3823,12 @@ if(!mpctx->sh_video) { vo_flip_page(mpctx->video_out); mpctx->num_buffered_frames--; - vout_time_usage += (GetTimer() - t2) * 0.000001; + mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001; + vout_time_usage += mpctx->last_vo_flip_duration; + print_status(mpctx, MP_NOPTS_VALUE, true); } -//====================== A-V TIMESTAMP CORRECTION: ========================= - - adjust_sync_and_print_status(mpctx, frame_time_remaining, mpctx->time_frame); + else + print_status(mpctx, MP_NOPTS_VALUE, false); //============================ Auto QUALITY ============================ From 8ed6d269779d8917492614ce8b204a712e311195 Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Tue, 9 Dec 2008 17:31:01 +0200 Subject: [PATCH 7/9] vo_gl: Support changing OSD over existing frame --- libvo/vo_gl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index a9a2690756..5e79014ded 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -1107,6 +1107,12 @@ static int control(uint32_t request, void *data) case VOCTRL_UPDATE_SCREENINFO: update_xinerama_info(); return VO_TRUE; + case VOCTRL_REDRAW_OSD: + if (vo_doublebuffering) + do_render(); + draw_osd(); + flip_page(); + return VO_TRUE; } return VO_NOTIMPL; } From 1f782eb802e9774bc53103e935eb673c283cf0aa Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Tue, 9 Dec 2008 18:39:38 +0200 Subject: [PATCH 8/9] core: Set OSD contents better while paused Handle timing out of OSD messages and set the OSD function symbol to pause instead of play. The implementation is hackish and should be cleaned up later with other pause loop changes. --- mplayer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mplayer.c b/mplayer.c index cc83c9e83c..ac53ed4abb 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1421,8 +1421,7 @@ static mp_osd_msg_t* get_osd_msg(struct MPContext *mpctx) osd_visible = 0; vo_osd_progbar_type = -1; // disable vo_osd_changed(OSDTYPE_PROGBAR); - if (mpctx->osd_function != OSD_PAUSE) - mpctx->osd_function = OSD_PLAY; + mpctx->osd_function = mpctx->paused ? OSD_PAUSE : OSD_PLAY; } } @@ -2377,6 +2376,11 @@ static void pause_loop(struct MPContext *mpctx) vf_menu_pause_update(vf_menu); #endif usec_sleep(20000); + update_osd_msg(mpctx); + int hack = vo_osd_changed(0); + vo_osd_changed(hack); + if (hack) + break; } #ifdef CONFIG_GUI if (use_gui) { @@ -3913,6 +3917,8 @@ if(auto_quality>0){ add_step_frame(mpctx); break; } + else + vo_osd_changed(0); } pause_loop(mpctx); } From 38a76f7fdf5c03bc49072b693d7c53b343f2994a Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Wed, 14 Jan 2009 02:51:24 +0200 Subject: [PATCH 9/9] core: Better -nocorrect-pts pause and filter-added frames handling Rewrite the -nocorrect-pts frame creation code. The new version always updates the visible frame when seeking while pausing, and supports filter-added frames. It can not time those properly though. Now the handling of filter-added frames in MPlayer always uses the new method independently of the value of correct-pts but MEncoder still expects the old behavior. Add a global variable that is set under MEncoder only and change the filters to choose behavior based on that instead of the correct_pts option. --- libmpcodecs/vf_tfields.c | 9 +-- libmpcodecs/vf_yadif.c | 7 ++- mencoder.c | 1 + mplayer.c | 126 ++++++++++++++++++++++----------------- 4 files changed, 82 insertions(+), 61 deletions(-) diff --git a/libmpcodecs/vf_tfields.c b/libmpcodecs/vf_tfields.c index 0d88119371..347cd4bb9e 100644 --- a/libmpcodecs/vf_tfields.c +++ b/libmpcodecs/vf_tfields.c @@ -310,9 +310,10 @@ static int put_image(struct vf_instance* vf, mp_image_t *mpi, double pts) return continue_buffered_image(vf); } +extern const int under_mencoder; + static int continue_buffered_image(struct vf_instance *vf) { - struct MPOpts *opts = vf->opts; int i=vf->priv->buffered_i; double pts = vf->priv->buffered_pts; mp_image_t *mpi = vf->priv->buffered_mpi; @@ -363,7 +364,7 @@ static int continue_buffered_image(struct vf_instance *vf) dmpi->stride[2] = 2*mpi->stride[2]; } ret |= vf_next_put_image(vf, dmpi, pts); - if (opts->correct_pts) + if (!under_mencoder) break; else if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); @@ -393,7 +394,7 @@ static int continue_buffered_image(struct vf_instance *vf) mpi->chroma_width, mpi->chroma_height, (i^!tff)); } ret |= vf_next_put_image(vf, dmpi, pts); - if (opts->correct_pts) + if (!under_mencoder) break; else if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); @@ -419,7 +420,7 @@ static int continue_buffered_image(struct vf_instance *vf) dmpi->stride[2], mpi->stride[2]*2, (i^!tff)); } ret |= vf_next_put_image(vf, dmpi, pts); - if (opts->correct_pts) + if (!under_mencoder) break; else if (!i) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); diff --git a/libmpcodecs/vf_yadif.c b/libmpcodecs/vf_yadif.c index fd46f241cd..2c80a2ec5b 100644 --- a/libmpcodecs/vf_yadif.c +++ b/libmpcodecs/vf_yadif.c @@ -416,9 +416,10 @@ static int put_image(struct vf_instance* vf, mp_image_t *mpi, double pts){ return continue_buffered_image(vf); } +extern const int under_mencoder; + static int continue_buffered_image(struct vf_instance *vf) { - struct MPOpts *opts = vf->opts; mp_image_t *mpi = vf->priv->buffered_mpi; int tff = vf->priv->buffered_tff; double pts = vf->priv->buffered_pts; @@ -435,10 +436,10 @@ static int continue_buffered_image(struct vf_instance *vf) mpi->width,mpi->height); vf_clone_mpi_attributes(dmpi, mpi); filter(vf->priv, dmpi->planes, dmpi->stride, mpi->w, mpi->h, i ^ tff ^ 1, tff); - if (opts->correct_pts && i < (vf->priv->mode & 1)) + if (i < (vf->priv->mode & 1) && !under_mencoder) vf_queue_frame(vf, continue_buffered_image); ret |= vf_next_put_image(vf, dmpi, pts /*FIXME*/); - if (opts->correct_pts) + if (!under_mencoder) break; if(i<(vf->priv->mode&1)) vf_next_control(vf, VFCTRL_FLIP_PAGE, NULL); diff --git a/mencoder.c b/mencoder.c index 052cfdbcde..52edeeac88 100644 --- a/mencoder.c +++ b/mencoder.c @@ -96,6 +96,7 @@ MPOpts opts; struct osd_state *osd; +const int under_mencoder = 1; int vo_doublebuffering=0; int vo_directrendering=0; int forced_subs_only=0; diff --git a/mplayer.c b/mplayer.c index ac53ed4abb..2ece0607ef 100644 --- a/mplayer.c +++ b/mplayer.c @@ -87,6 +87,7 @@ #include "input/input.h" +const int under_mencoder = 0; int slave_mode=0; int player_idle_mode=0; int quiet=0; @@ -2209,65 +2210,82 @@ err_out: return 0; } +static double update_video_nocorrect_pts(struct MPContext *mpctx, + int *blit_frame) +{ + struct sh_video *sh_video = mpctx->sh_video; + *blit_frame = 0; + double frame_time = 0; + while (1) { + current_module = "filter_video"; + // In nocorrect-pts mode there is no way to properly time these frames + if (vf_output_queued_frame(sh_video->vfilter)) + break; + unsigned char *packet = NULL; + frame_time = sh_video->next_frame_time; + if (mpctx->update_video_immediately) + frame_time = 0; + int in_size = video_read_frame(sh_video, &sh_video->next_frame_time, + &packet, force_fps); + if (in_size < 0) { +#ifdef CONFIG_DVDNAV + if (mpctx->stream->type == STREAMTYPE_DVDNAV) { + if (mp_dvdnav_is_eof(mpctx->stream)) + return -1; + if (mpctx->d_video) + mpctx->d_video->eof = 0; + if (mpctx->d_audio) + mpctx->d_audio->eof = 0; + mpctx->stream->eof = 0; + } else +#endif + return -1; + } + if (in_size > max_framesize) + max_framesize = in_size; + sh_video->timer += frame_time; + if (mpctx->sh_audio) + mpctx->delay -= frame_time; + // video_read_frame can change fps (e.g. for ASF video) + vo_fps = sh_video->fps; + int framedrop_type = check_framedrop(mpctx, frame_time); + current_module = "decode video"; + + void *decoded_frame; +#ifdef CONFIG_DVDNAV + decoded_frame = mp_dvdnav_restore_smpi(mpctx, &in_size, &packet, NULL); + if (in_size >= 0 && !decoded_frame) +#endif + decoded_frame = decode_video(sh_video, packet, in_size, framedrop_type, + sh_video->pts); +#ifdef CONFIG_DVDNAV + // Save last still frame for future display + mp_dvdnav_restore_smpi(mpctx, in_size, packet, decoded_frame); +#endif + if (decoded_frame) { + // These updates are done here for vf_expand OSD/subtitles + update_subtitles(sh_video, mpctx->d_sub, 0); + update_teletext(sh_video, mpctx->demuxer, 0); + update_osd_msg(mpctx); + current_module = "filter video"; + if (filter_video(sh_video, decoded_frame, sh_video->pts, + mpctx->osd)) + break; + } + } + *blit_frame = 1; + return frame_time; +} + static double update_video(struct MPContext *mpctx, int *blit_frame) { - struct MPOpts *opts = &mpctx->opts; - sh_video_t * const sh_video = mpctx->sh_video; - //-------------------- Decode a frame: ----------------------- + struct sh_video *sh_video = mpctx->sh_video; double frame_time; - *blit_frame = 0; // Don't blit if we hit EOF + *blit_frame = 0; sh_video->vfilter->control(sh_video->vfilter, VFCTRL_SET_OSD_OBJ, mpctx->osd); // hack for vf_expand - if (!opts->correct_pts) { - unsigned char* start=NULL; - void *decoded_frame = NULL; - int drop_frame=0; - int in_size; - - current_module = "video_read_frame"; - frame_time = sh_video->next_frame_time; - in_size = video_read_frame(sh_video, &sh_video->next_frame_time, - &start, force_fps); -#ifdef CONFIG_DVDNAV - /// wait, still frame or EOF - if (mpctx->stream->type == STREAMTYPE_DVDNAV && in_size < 0) { - if (mp_dvdnav_is_eof(mpctx->stream)) return -1; - if (mpctx->d_video) mpctx->d_video->eof = 0; - if (mpctx->d_audio) mpctx->d_audio->eof = 0; - mpctx->stream->eof = 0; - } else -#endif - if (in_size < 0) - return -1; - if (in_size > max_framesize) - max_framesize = in_size; // stats - sh_video->timer += frame_time; - if (mpctx->sh_audio) - mpctx->delay -= frame_time; - // video_read_frame can change fps (e.g. for ASF video) - vo_fps = sh_video->fps; - drop_frame = check_framedrop(mpctx, frame_time); - update_subtitles(sh_video, mpctx->d_sub, 0); - update_teletext(sh_video, mpctx->demuxer, 0); - update_osd_msg(mpctx); - current_module = "decode_video"; -#ifdef CONFIG_DVDNAV - decoded_frame = mp_dvdnav_restore_smpi(mpctx, &in_size,&start, - decoded_frame); - /// still frame has been reached, no need to decode - if (in_size > 0 && !decoded_frame) -#endif - decoded_frame = decode_video(sh_video, start, in_size, drop_frame, - sh_video->pts); -#ifdef CONFIG_DVDNAV - /// save back last still frame for future display - mp_dvdnav_save_smpi(mpctx, in_size, start, decoded_frame); -#endif - current_module = "filter_video"; - *blit_frame = (decoded_frame && filter_video(sh_video, decoded_frame, - sh_video->pts, - mpctx->osd)); - } + if (!mpctx->opts.correct_pts) + return update_video_nocorrect_pts(mpctx, blit_frame); else { int res = generate_video_frame(mpctx); if (!res)