From 23f598e0ee2151923a44077f510cd484f239480b Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sat, 18 Dec 2010 10:13:45 +0200 Subject: core: add struct for queued seek info To prepare for the addition of exact seek support, add a struct for queued seek state and a helper function to update its state. It would have been cumbersome to update additional state (showing whether the seek is forced to be exact or non-exact) manually at every point that handles seeks. --- command.c | 32 +++++++---------- mp_core.h | 13 +++++-- mplayer.c | 122 ++++++++++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 106 insertions(+), 61 deletions(-) diff --git a/command.c b/command.c index 247af1b9d1..394bf566c4 100644 --- a/command.c +++ b/command.c @@ -454,8 +454,7 @@ static int mp_property_percent_pos(m_option_t *prop, int action, return m_property_int_ro(prop, action, arg, get_percent_pos(mpctx)); } - mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR; - mpctx->rel_seek_secs = pos / 100.0; + queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0); return M_PROPERTY_OK; } @@ -469,13 +468,12 @@ static int mp_property_time_pos(m_option_t *prop, int action, case M_PROPERTY_SET: if(!arg) return M_PROPERTY_ERROR; M_PROPERTY_CLAMP(prop, *(double*)arg); - mpctx->abs_seek_pos = SEEK_ABSOLUTE; - mpctx->rel_seek_secs = *(double*)arg; + queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double*)arg, 0); return M_PROPERTY_OK; case M_PROPERTY_STEP_UP: case M_PROPERTY_STEP_DOWN: - mpctx->rel_seek_secs += (arg ? *(double*)arg : 10.0) * - (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); + queue_seek(mpctx, MPSEEK_RELATIVE, (arg ? *(double*)arg : 10.0) * + (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0), 0); return M_PROPERTY_OK; } return m_property_time_ro(prop, action, arg, get_current_time(mpctx)); @@ -531,20 +529,16 @@ static int mp_property_chapter(m_option_t *prop, int action, void *arg, } double next_pts = 0; + queue_seek(mpctx, MPSEEK_NONE, 0, 0); chapter = seek_chapter(mpctx, chapter, &next_pts, &chapter_name); - mpctx->rel_seek_secs = 0; - mpctx->abs_seek_pos = 0; if (chapter >= 0) { - if (next_pts > -1.0) { - mpctx->abs_seek_pos = SEEK_ABSOLUTE; - mpctx->rel_seek_secs = next_pts; - } + if (next_pts > -1.0) + queue_seek(mpctx, MPSEEK_ABSOLUTE, next_pts, 0); if (chapter_name) set_osd_tmsg(OSD_MSG_TEXT, 1, opts->osd_duration, "Chapter: (%d) %s", chapter + 1, chapter_name); - } - else if (step_all > 0) - mpctx->rel_seek_secs = 1000000000.; + } else if (step_all > 0) + queue_seek(mpctx, MPSEEK_RELATIVE, 1000000000, 0); else set_osd_tmsg(OSD_MSG_TEXT, 1, opts->osd_duration, "Chapter: (%d) %s", 0, mp_gtext("unknown")); @@ -2725,16 +2719,14 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) v = cmd->args[0].v.f; abs = (cmd->nargs > 1) ? cmd->args[1].v.i : 0; if (abs == 2) { /* Absolute seek to a specific timestamp in seconds */ - mpctx->abs_seek_pos = SEEK_ABSOLUTE; + queue_seek(mpctx, MPSEEK_ABSOLUTE, v, 0); mpctx->osd_function = v > get_current_time(mpctx) ? OSD_FFW : OSD_REW; - mpctx->rel_seek_secs = v; } else if (abs) { /* Absolute seek by percentage */ - mpctx->abs_seek_pos = SEEK_ABSOLUTE | SEEK_FACTOR; + queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, 0); mpctx->osd_function = OSD_FFW; // Direction isn't set correctly - mpctx->rel_seek_secs = v / 100.0; } else { - mpctx->rel_seek_secs += v; + queue_seek(mpctx, MPSEEK_RELATIVE, v, 0); mpctx->osd_function = (v > 0) ? OSD_FFW : OSD_REW; } } diff --git a/mp_core.h b/mp_core.h index c02edd4155..c64de2cdbe 100644 --- a/mp_core.h +++ b/mp_core.h @@ -161,8 +161,15 @@ typedef struct MPContext { unsigned int last_time; // Used to communicate the parameters of a seek between parts - double rel_seek_secs; - int abs_seek_pos; + struct seek_params { + enum seek_type { + MPSEEK_NONE, MPSEEK_RELATIVE, MPSEEK_ABSOLUTE, MPSEEK_FACTOR + } type; + double amount; + int exact; // -1 = disable, 0 = default, 1 = enable + // currently not set by commands, only used internally by seek() + int direction; // -1 = backward, 0 = default, 1 = forward + } seek; /* Heuristic for relative chapter seeks: keep track which chapter * the user wanted to go to, even if we aren't exactly within the @@ -225,6 +232,8 @@ 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); +void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount, + int exact); int seek_chapter(struct MPContext *mpctx, int chapter, double *seek_pts, char **chapter_name); double get_time_length(struct MPContext *mpctx); diff --git a/mplayer.c b/mplayer.c index 25d0baac90..7eb2d138b5 100644 --- a/mplayer.c +++ b/mplayer.c @@ -2743,8 +2743,7 @@ static void edl_update(MPContext *mpctx) if (get_current_time(mpctx) >= next_edl_record->start_sec) { if (next_edl_record->action == EDL_SKIP) { mpctx->osd_function = OSD_FFW; - mpctx->abs_seek_pos = 0; - mpctx->rel_seek_secs = next_edl_record->length_sec; + queue_seek(mpctx, MPSEEK_RELATIVE, next_edl_record->length_sec, 0); mp_msg(MSGT_CPLAYER, MSGL_DBG4, "EDL_SKIP: start [%f], stop " "[%f], length [%f]\n", next_edl_record->start_sec, next_edl_record->stop_sec, next_edl_record->length_sec); @@ -2852,39 +2851,36 @@ static double timeline_set_from_time(struct MPContext *mpctx, double pts, } -// style & SEEK_ABSOLUTE == 0 means seek relative to current position, == 1 means absolute -// style & SEEK_FACTOR == 0 means amount in seconds, == 2 means fraction of file length // return -1 if seek failed (non-seekable stream?), 0 otherwise -static int seek(MPContext *mpctx, double amount, int style) +static int seek(MPContext *mpctx, struct seek_params seek) { current_module = "seek"; if (mpctx->stop_play == AT_END_OF_FILE) mpctx->stop_play = KEEP_PLAYING; - if (style & SEEK_FACTOR - || style & SEEK_ABSOLUTE && amount < mpctx->last_chapter_pts - || amount < 0) + if (seek.type == MPSEEK_FACTOR + || seek.type == MPSEEK_ABSOLUTE + && seek.amount < mpctx->last_chapter_pts + || seek.amount < 0) mpctx->last_chapter_seek = -1; - if (mpctx->timeline && style & SEEK_FACTOR) { - amount *= mpctx->timeline[mpctx->num_timeline_parts].start; - style &= ~SEEK_FACTOR; + if (mpctx->timeline && seek.type == MPSEEK_FACTOR) { + seek.amount *= mpctx->timeline[mpctx->num_timeline_parts].start; + seek.type = MPSEEK_ABSOLUTE; } if ((mpctx->demuxer->accurate_seek || mpctx->timeline) - && !(style & (SEEK_ABSOLUTE | SEEK_FACTOR))) { - style |= SEEK_ABSOLUTE; - if (amount > 0) - style |= SEEK_FORWARD; - else - style |= SEEK_BACKWARD; - amount += get_current_time(mpctx); + && seek.type == MPSEEK_RELATIVE) { + seek.type = MPSEEK_ABSOLUTE; + seek.direction = seek.amount > 0 ? 1 : -1; + seek.amount += get_current_time(mpctx); } /* At least the liba52 decoder wants to read from the input stream * during initialization, so reinit must be done after the demux_seek() * call that clears possible stream EOF. */ bool need_reset = false; - double demuxer_amount = amount; + double demuxer_amount = seek.amount; if (mpctx->timeline) { - demuxer_amount = timeline_set_from_time(mpctx, amount, &need_reset); + demuxer_amount = timeline_set_from_time(mpctx, seek.amount, + &need_reset); if (demuxer_amount == -1) { mpctx->stop_play = AT_END_OF_FILE; // Clear audio from current position @@ -2896,8 +2892,20 @@ static int seek(MPContext *mpctx, double amount, int style) return -1; } } + int demuxer_style = 0; + switch (seek.type) { + case MPSEEK_FACTOR: + demuxer_style |= SEEK_FACTOR; // fallthrough + case MPSEEK_ABSOLUTE: + demuxer_style |= SEEK_ABSOLUTE; + } + if (seek.direction < 0) + demuxer_style |= SEEK_BACKWARD; + else if (seek.direction > 0) + demuxer_style |= SEEK_FORWARD; + int seekresult = demux_seek(mpctx->demuxer, demuxer_amount, audio_delay, - style); + demuxer_style); if (need_reset) reinit_decoders(mpctx); if (seekresult == 0) @@ -2907,14 +2915,49 @@ static int seek(MPContext *mpctx, double amount, int style) /* Use the target time as "current position" for further relative * seeks etc until a new video frame has been decoded */ - if ((style & (SEEK_ABSOLUTE | SEEK_FACTOR)) == SEEK_ABSOLUTE) - mpctx->video_pts = amount; + if (seek.type == MPSEEK_ABSOLUTE) + mpctx->video_pts = seek.amount; mpctx->start_timestamp = GetTimerMS(); return 0; } +void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount, + int exact) +{ + struct seek_params *seek = &mpctx->seek; + switch (type) { + case MPSEEK_RELATIVE: + if (seek->type == MPSEEK_FACTOR) + return; // Well... not common enough to bother doing better + seek->amount += amount; + seek->exact = FFMAX(seek->exact, exact); + if (seek->type == MPSEEK_NONE) + seek->exact = exact; + if (seek->type == MPSEEK_ABSOLUTE) + return; + if (seek->amount == 0) { + *seek = (struct seek_params){0}; + return; + } + seek->type = MPSEEK_RELATIVE; + return; + case MPSEEK_ABSOLUTE: + case MPSEEK_FACTOR: + *seek = (struct seek_params) { + .type = type, + .amount = amount, + .exact = exact, + }; + return; + case MPSEEK_NONE: + *seek = (struct seek_params){0}; + return; + } + abort(); +} + double get_time_length(struct MPContext *mpctx) { @@ -3110,7 +3153,8 @@ static void run_playloop(struct MPContext *mpctx) if (mpctx->sh_video->pts >= next->start || mpctx->stop_play == AT_END_OF_FILE && mpctx->timeline_part + 1 < mpctx->num_timeline_parts) { - seek(mpctx, next->start, SEEK_ABSOLUTE); + seek(mpctx, (struct seek_params){ .type = MPSEEK_ABSOLUTE, + .amount = next->start }); return; } } @@ -3272,8 +3316,7 @@ static void run_playloop(struct MPContext *mpctx) * If the user seeks continuously (keeps arrow key down) * try to finish showing a frame from one location before doing * another seek (which could lead to unchanging display). */ - if ((mpctx->rel_seek_secs || mpctx->abs_seek_pos) - && cmd->id != MP_CMD_SEEK + if (mpctx->seek.type && cmd->id != MP_CMD_SEEK || mpctx->restart_playback && cmd->id == MP_CMD_SEEK && GetTimerMS() - mpctx->start_timestamp < 300) break; @@ -3283,8 +3326,8 @@ static void run_playloop(struct MPContext *mpctx) if (mpctx->stop_play) break; } - if (!mpctx->paused || mpctx->stop_play || mpctx->rel_seek_secs - || mpctx->abs_seek_pos || mpctx->restart_playback) + if (!mpctx->paused || mpctx->stop_play || mpctx->seek.type + || mpctx->restart_playback) break; if (mpctx->sh_video) { update_osd_msg(mpctx); @@ -3304,7 +3347,7 @@ static void run_playloop(struct MPContext *mpctx) // handle -sstep if (step_sec > 0 && !mpctx->paused) { mpctx->osd_function = OSD_FFW; - mpctx->rel_seek_secs += step_sec; + queue_seek(mpctx, MPSEEK_RELATIVE, step_sec, 0); } edl_update(mpctx); @@ -3319,15 +3362,12 @@ static void run_playloop(struct MPContext *mpctx) opts->loop_times = -1; play_n_frames = play_n_frames_mf; mpctx->stop_play = 0; - mpctx->abs_seek_pos = SEEK_ABSOLUTE; - mpctx->rel_seek_secs = seek_to_sec; + queue_seek(mpctx, MPSEEK_ABSOLUTE, 0, 0); } - if (mpctx->rel_seek_secs || mpctx->abs_seek_pos) { - seek(mpctx, mpctx->rel_seek_secs, mpctx->abs_seek_pos); - - mpctx->rel_seek_secs = 0; - mpctx->abs_seek_pos = 0; + if (mpctx->seek.type) { + seek(mpctx, mpctx->seek); + mpctx->seek = (struct seek_params){0}; } } @@ -4509,14 +4549,17 @@ if(play_n_frames==0){ // If there's a timeline force an absolute seek to initialize state if (seek_to_sec || mpctx->timeline) { - seek(mpctx, seek_to_sec, SEEK_ABSOLUTE); + queue_seek(mpctx, MPSEEK_ABSOLUTE, seek_to_sec, 0); + seek(mpctx, mpctx->seek); end_at.pos += seek_to_sec; } if (opts->chapterrange[0] > 0) { double pts; if (seek_chapter(mpctx, opts->chapterrange[0]-1, &pts, NULL) >= 0 - && pts > -1.0) - seek(mpctx, pts, SEEK_ABSOLUTE); + && pts > -1.0) { + queue_seek(mpctx, MPSEEK_ABSOLUTE, pts, 0); + seek(mpctx, mpctx->seek); + } } if (end_at.type == END_AT_SIZE) { @@ -4532,6 +4575,7 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) { } #endif + mpctx->seek = (struct seek_params){0}; get_relative_time(mpctx); // reset current delta mpctx->time_frame = 0; mpctx->drop_message_shown = 0; -- cgit v1.2.3