player: handle seek delays differently

The code removed from handle_input_and_seek_coalesce() did two things:

1. If there's a queued seek, stop accepting non-seek commands, and delay
   them to the next playloop iteration.
2. If a seek is executing (i.e. the seek was unqueued, and now it's
   trying to decode and display the first video frame), stop accepting
   seek commands (and in fact all commands that were queued after the
   first seek command). This logic is disabled if seeking started longer
   than 300ms ago. (To avoid starvation.)

I'm not sure why 1. would be needed. It's still possible that a command
immediately executed after a seek command sees a "seeking in progress"
state, because it affects queued seeks only, and not seeks in progress.
Drop this code, since it can easily lead to input starvation, and I'm
not aware of any disadvantages.

The logic in 2. is good to make seeking behave much better, as it
guarantees that the video display is updated frequently. Keep the core
idea, but implement it differently. Now this logic is applied to seeks
only. Commands after the seek can execute freely, and like with 1., I
don't see a reason why they couldn't. However, in some cases, seeks are
supposed to be executed instantly, so queue_seek() needs an additional
parameter to signal the need for immediate update.

One nice thing is that commands like sub_seek automatically profit from
the seek delay logic. On the other hand, hitting chapter seek multiple
times still does not update the video on chapter boundaries (as it
should be).

Note that the main goal of this commit is actually simplification of the
input processing logic and to allow all commands to be executed
immediately.
This commit is contained in:
wm4 2014-02-07 22:29:50 +01:00
parent 67769db1a4
commit 17ec073a15
5 changed files with 27 additions and 25 deletions

View File

@ -358,7 +358,7 @@ static int mp_property_percent_pos(m_option_t *prop, int action,
switch (action) {
case M_PROPERTY_SET: {
double pos = *(double *)arg;
queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0);
queue_seek(mpctx, MPSEEK_FACTOR, pos / 100.0, 0, true);
return M_PROPERTY_OK;
}
case M_PROPERTY_GET: {
@ -383,7 +383,7 @@ static int mp_property_time_pos(m_option_t *prop, int action,
return M_PROPERTY_UNAVAILABLE;
if (action == M_PROPERTY_SET) {
queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double *)arg, 0);
queue_seek(mpctx, MPSEEK_ABSOLUTE, *(double *)arg, 0, true);
return M_PROPERTY_OK;
}
return property_time(prop, action, arg, get_current_time(mpctx));
@ -2562,14 +2562,14 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
int exact = cmd->args[2].v.i;
mark_seek(mpctx);
if (abs == 2) { // Absolute seek to a timestamp in seconds
queue_seek(mpctx, MPSEEK_ABSOLUTE, v, exact);
queue_seek(mpctx, MPSEEK_ABSOLUTE, v, exact, false);
set_osd_function(mpctx,
v > get_current_time(mpctx) ? OSD_FFW : OSD_REW);
} else if (abs) { /* Absolute seek by percentage */
queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, exact);
queue_seek(mpctx, MPSEEK_FACTOR, v / 100.0, exact, false);
set_osd_function(mpctx, OSD_FFW); // Direction isn't set correctly
} else {
queue_seek(mpctx, MPSEEK_RELATIVE, v, exact);
queue_seek(mpctx, MPSEEK_RELATIVE, v, exact, false);
set_osd_function(mpctx, (v > 0) ? OSD_FFW : OSD_REW);
}
if (bar_osd)
@ -2583,7 +2583,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
double oldpts = cmdctx->last_seek_pts;
if (oldpts != MP_NOPTS_VALUE) {
cmdctx->last_seek_pts = get_current_time(mpctx);
queue_seek(mpctx, MPSEEK_ABSOLUTE, oldpts, 1);
queue_seek(mpctx, MPSEEK_ABSOLUTE, oldpts, 1, false);
set_osd_function(mpctx, OSD_REW);
if (bar_osd)
mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;
@ -2761,7 +2761,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
// rounding for the mess of it.
a[0] += 0.01 * (a[1] > 0 ? 1 : -1);
mark_seek(mpctx);
queue_seek(mpctx, MPSEEK_RELATIVE, a[0], 1);
queue_seek(mpctx, MPSEEK_RELATIVE, a[0], 1, false);
set_osd_function(mpctx, (a[0] > 0) ? OSD_FFW : OSD_REW);
if (bar_osd)
mpctx->add_osd_seek_info |= OSD_SEEK_INFO_BAR;

View File

@ -298,6 +298,7 @@ typedef struct MPContext {
enum seek_type type;
double amount;
int exact; // -1 = disable, 0 = default, 1 = enable
bool immediate; // disable seek delay logic
// currently not set by commands, only used internally by seek()
int direction; // -1 = backward, 0 = default, 1 = forward
} seek;
@ -413,7 +414,7 @@ void pause_player(struct MPContext *mpctx);
void unpause_player(struct MPContext *mpctx);
void add_step_frame(struct MPContext *mpctx, int dir);
void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
int exact);
int exact, bool immediate);
bool mp_seek_chapter(struct MPContext *mpctx, int chapter);
double get_time_length(struct MPContext *mpctx);
double get_current_time(struct MPContext *mpctx);

View File

@ -1325,13 +1325,14 @@ goto_reopen_demuxer: ;
// If there's a timeline force an absolute seek to initialize state
double startpos = rel_time_to_abs(mpctx, opts->play_start, -1);
if (startpos != -1 || mpctx->timeline) {
queue_seek(mpctx, MPSEEK_ABSOLUTE, startpos, 0);
queue_seek(mpctx, MPSEEK_ABSOLUTE, startpos, 0, true);
execute_queued_seek(mpctx);
}
if (startpos == -1 && mpctx->resolve_result &&
mpctx->resolve_result->start_time > 0)
{
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->resolve_result->start_time, 0);
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->resolve_result->start_time,
0, true);
execute_queued_seek(mpctx);
}
if (opts->chapterrange[0] > 0) {

View File

@ -351,12 +351,14 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek,
return 0;
}
// This combines consecutive seek requests.
void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
int exact)
int exact, bool immediate)
{
struct seek_params *seek = &mpctx->seek;
switch (type) {
case MPSEEK_RELATIVE:
seek->immediate |= immediate;
if (seek->type == MPSEEK_FACTOR)
return; // Well... not common enough to bother doing better
seek->amount += amount;
@ -377,6 +379,7 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
.type = type,
.amount = amount,
.exact = exact,
.immediate = immediate,
};
return;
case MPSEEK_NONE:
@ -389,6 +392,12 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount,
void execute_queued_seek(struct MPContext *mpctx)
{
if (mpctx->seek.type) {
/* 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->seek.immediate && mpctx->restart_playback &&
mp_time_sec() - mpctx->start_timestamp < 0.3)
return;
mp_seek(mpctx, mpctx->seek, false);
mpctx->seek = (struct seek_params){0};
}
@ -582,7 +591,7 @@ bool mp_seek_chapter(struct MPContext *mpctx, int chapter)
return false;
do_seek:
queue_seek(mpctx, MPSEEK_ABSOLUTE, pts, 0);
queue_seek(mpctx, MPSEEK_ABSOLUTE, pts, 0, true);
mpctx->last_chapter_seek = chapter;
mpctx->last_chapter_pts = pts;
return true;
@ -740,15 +749,6 @@ static void handle_input_and_seek_coalesce(struct MPContext *mpctx)
mp_cmd_t *cmd;
while ((cmd = mp_input_get_cmd(mpctx->input, 0, 1)) != NULL) {
/* Allow running consecutive seek commands to combine them,
* but execute the seek before running other commands.
* 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->seek.type && cmd->id != MP_CMD_SEEK) ||
(mpctx->restart_playback && cmd->id == MP_CMD_SEEK &&
mp_time_sec() - mpctx->start_timestamp < 0.3))
break;
cmd = mp_input_get_cmd(mpctx->input, 0, 0);
run_command(mpctx, cmd);
mp_cmd_free(cmd);
@ -802,14 +802,14 @@ static void handle_backstep(struct MPContext *mpctx)
if (demuxer_ok && mpctx->d_video && current_pts != MP_NOPTS_VALUE) {
double seek_pts = find_previous_pts(mpctx, current_pts);
if (seek_pts != MP_NOPTS_VALUE) {
queue_seek(mpctx, MPSEEK_ABSOLUTE, seek_pts, 2);
queue_seek(mpctx, MPSEEK_ABSOLUTE, seek_pts, 2, true);
} else {
double last = get_last_frame_pts(mpctx);
if (last != MP_NOPTS_VALUE && last >= current_pts &&
mpctx->backstep_start_seek_ts != mpctx->vo_pts_history_seek_ts)
{
MP_ERR(mpctx, "Backstep failed.\n");
queue_seek(mpctx, MPSEEK_ABSOLUTE, current_pts, 2);
queue_seek(mpctx, MPSEEK_ABSOLUTE, current_pts, 2, true);
} else if (!mpctx->hrseek_active) {
MP_VERBOSE(mpctx, "Start backstep indexing.\n");
// Force it to index the video up until current_pts.
@ -845,7 +845,7 @@ static void handle_sstep(struct MPContext *mpctx)
!mpctx->restart_playback)
{
set_osd_function(mpctx, OSD_FFW);
queue_seek(mpctx, MPSEEK_RELATIVE, opts->step_sec, 0);
queue_seek(mpctx, MPSEEK_RELATIVE, opts->step_sec, 0, true);
}
}

View File

@ -245,7 +245,7 @@ void mp_force_video_refresh(struct MPContext *mpctx)
// If not paused, the next frame should come soon enough.
if (opts->pause && mpctx->last_vo_pts != MP_NOPTS_VALUE)
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->last_vo_pts, 1);
queue_seek(mpctx, MPSEEK_ABSOLUTE, mpctx->last_vo_pts, 1, true);
}
static bool filter_output_queued_frame(struct MPContext *mpctx)