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) {