Browse Source

player: timer: handle seek state

Keep the last requested seek position/time, that will be used for
successive jumps. It will be more precise than using the demux
GET_TIME/GET_POSITION.

Send 'on_seek' callback with a valid point when starting a new seek.
This callback will be called with a NULL point once all seek requests
are processed.

UI have now the choice to update their time/position to the seeked
value. This will fix the UI not updated when the seek is long to
process.

Refs #27383
Refs #28482
pull/162/head
Thomas Guillem 4 years ago
committed by Steve Lhomme
parent
commit
1ecb283c87
  1. 9
      include/vlc_player.h
  2. 4
      src/player/input.c
  3. 12
      src/player/player.h
  4. 124
      src/player/timer.c

9
include/vlc_player.h

@ -3399,6 +3399,15 @@ struct vlc_player_timer_cbs
* @param data opaque pointer set by vlc_player_AddTimer()
*/
void (*on_discontinuity)(vlc_tick_t system_date, void *data);
/**
* Called when the player is seeking or finished seeking
*
* @param value point of the seek request or NULL when seeking is finished
* value.system_date = VLC_TICK_MAX in that case
* @param data opaque pointer set by vlc_player_AddTimer()
*/
void (*on_seek)(const struct vlc_player_timer_point *value, void *data);
};
/**

4
src/player/input.c

@ -65,7 +65,7 @@ vlc_player_input_GetTime(struct vlc_player_input *input, vlc_tick_t system_now)
vlc_tick_t ts;
if (input == player->input
&& vlc_player_GetTimerPoint(player, system_now, &ts, NULL) == 0)
&& vlc_player_GetTimerPoint(player, false, system_now, &ts, NULL) == 0)
return ts;
return input->time;
}
@ -77,7 +77,7 @@ vlc_player_input_GetPos(struct vlc_player_input *input, vlc_tick_t system_now)
double pos;
if (input == player->input
&& vlc_player_GetTimerPoint(player, system_now, NULL, &pos) == 0)
&& vlc_player_GetTimerPoint(player, false, system_now, NULL, &pos) == 0)
return pos;
return input->position;
}

12
src/player/player.h

@ -215,13 +215,16 @@ struct vlc_player_timer
vlc_mutex_t lock;
enum vlc_player_timer_state state;
bool seeking;
vlc_tick_t input_length;
vlc_tick_t input_normal_time;
vlc_tick_t last_ts;
double input_position;
vlc_tick_t seek_ts;
double seek_position;
bool seeking;
struct vlc_player_timer_source sources[VLC_PLAYER_TIMER_TYPE_COUNT];
#define best_source sources[VLC_PLAYER_TIMER_TYPE_BEST]
#define smpte_source sources[VLC_PLAYER_TIMER_TYPE_SMPTE]
@ -482,6 +485,10 @@ vlc_player_UpdateTimerState(vlc_player_t *player, vlc_es_id_t *es_source,
enum vlc_player_timer_state state,
vlc_tick_t system_date);
void
vlc_player_UpdateTimerSeekState(vlc_player_t *player, vlc_tick_t time,
double position);
void
vlc_player_UpdateTimer(vlc_player_t *player, vlc_es_id_t *es_source,
bool es_source_is_master,
@ -493,7 +500,8 @@ void
vlc_player_RemoveTimerSource(vlc_player_t *player, vlc_es_id_t *es_source);
int
vlc_player_GetTimerPoint(vlc_player_t *player, vlc_tick_t system_now,
vlc_player_GetTimerPoint(vlc_player_t *player, bool seeking,
vlc_tick_t system_now,
vlc_tick_t *out_ts, double *out_pos);
/*

124
src/player/timer.c

@ -37,10 +37,28 @@ vlc_player_ResetTimer(vlc_player_t *player)
player->timer.last_ts = VLC_TICK_INVALID;
player->timer.input_position = 0;
player->timer.smpte_source.smpte.last_framenum = ULONG_MAX;
player->timer.seek_ts = VLC_TICK_INVALID;
player->timer.seek_position = -1;
player->timer.seeking = false;
vlc_mutex_unlock(&player->timer.lock);
}
static void
vlc_player_SendTimerSeek(vlc_player_t *player,
struct vlc_player_timer_source *source,
const struct vlc_player_timer_point *point)
{
(void) player;
vlc_player_timer_id *timer;
vlc_list_foreach(timer, &source->listeners, node)
{
if (timer->cbs->on_seek != NULL)
timer->cbs->on_seek(point, timer->data);
}
}
static void
vlc_player_SendTimerSourceUpdates(vlc_player_t *player,
struct vlc_player_timer_source *source,
@ -194,8 +212,22 @@ vlc_player_UpdateTimerState(vlc_player_t *player, vlc_es_id_t *es_source,
if (source->es != es_source)
continue;
/* signal discontinuity only on best source */
if (source->point.system_date != VLC_TICK_INVALID)
notify = bestsource->es == es_source;
if (bestsource->es == es_source)
{
/* And only once */
if (source->point.system_date != VLC_TICK_INVALID)
notify = true;
/* There can be several discontinuities on the same source
* for one seek request, hence the need of the
* 'timer.seeking' variable to notify only once the end of
* the seek request. */
if (player->timer.seeking)
{
player->timer.seeking = false;
vlc_player_SendTimerSeek(player, bestsource, NULL);
}
}
source->point.system_date = VLC_TICK_INVALID;
}
break;
@ -228,6 +260,47 @@ vlc_player_UpdateTimerState(vlc_player_t *player, vlc_es_id_t *es_source,
vlc_mutex_unlock(&player->timer.lock);
}
void
vlc_player_UpdateTimerSeekState(vlc_player_t *player, vlc_tick_t time,
double position)
{
vlc_mutex_lock(&player->timer.lock);
struct vlc_player_timer_source *source = &player->timer.best_source;
if (time == VLC_TICK_INVALID)
{
assert(position >= 0);
if (source->point.length != VLC_TICK_INVALID)
player->timer.seek_ts = position * source->point.length;
else
player->timer.seek_ts = VLC_TICK_INVALID;
}
else
player->timer.seek_ts = time;
if (position < 0)
{
assert(time != VLC_TICK_INVALID);
if (source->point.length != VLC_TICK_INVALID)
player->timer.seek_position = time / (double) source->point.length;
}
else
player->timer.seek_position = position;
const struct vlc_player_timer_point point =
{
.position = player->timer.seek_position,
.rate = source->point.rate,
.ts = player->timer.seek_ts,
.length = source->point.length,
.system_date = VLC_TICK_MAX,
};
player->timer.seeking = true;
vlc_player_SendTimerSeek(player, source, &point);
vlc_mutex_unlock(&player->timer.lock);
}
static void
vlc_player_UpdateTimerSource(vlc_player_t *player,
struct vlc_player_timer_source *source,
@ -340,6 +413,17 @@ vlc_player_UpdateTimer(vlc_player_t *player, vlc_es_id_t *es_source,
vlc_player_UpdateTimerSource(player, source, point->rate, point->ts,
system_date);
/* It is possible to receive valid points while seeking. These
* points could be updated when the input thread didn't yet process
* the seek request. */
if (!player->timer.seeking)
{
/* Reset seek time/position now that we receive a valid point
* and seek was processed */
player->timer.seek_ts = VLC_TICK_INVALID;
player->timer.seek_position = -1;
}
if (!vlc_list_is_empty(&source->listeners))
vlc_player_SendTimerSourceUpdates(player, source, force_update,
&source->point);
@ -384,6 +468,14 @@ void
vlc_player_RemoveTimerSource(vlc_player_t *player, vlc_es_id_t *es_source)
{
vlc_mutex_lock(&player->timer.lock);
/* Unlikely case where the source ES is deleted while seeking */
if (player->timer.best_source.es == es_source && player->timer.seeking)
{
player->timer.seeking = false;
vlc_player_SendTimerSeek(player, &player->timer.best_source, NULL);
}
for (size_t i = 0; i < VLC_PLAYER_TIMER_TYPE_COUNT; ++i)
{
struct vlc_player_timer_source *source = &player->timer.sources[i];
@ -398,23 +490,41 @@ vlc_player_RemoveTimerSource(vlc_player_t *player, vlc_es_id_t *es_source)
}
int
vlc_player_GetTimerPoint(vlc_player_t *player, vlc_tick_t system_now,
vlc_player_GetTimerPoint(vlc_player_t *player, bool seeking,
vlc_tick_t system_now,
vlc_tick_t *out_ts, double *out_pos)
{
int ret;
int ret = VLC_EGENERIC;
vlc_mutex_lock(&player->timer.lock);
if (player->timer.best_source.point.system_date == VLC_TICK_INVALID)
if (seeking
&& (player->timer.seek_ts != VLC_TICK_INVALID || player->timer.seek_position >= 0.0f))
{
vlc_mutex_unlock(&player->timer.lock);
return VLC_EGENERIC;
if (out_ts != NULL)
{
if (player->timer.seek_ts == VLC_TICK_INVALID)
goto end;
*out_ts = player->timer.seek_ts;
}
if (out_pos != NULL)
{
if (player->timer.seek_position < 0)
goto end;
*out_pos = player->timer.seek_position;
}
ret = VLC_SUCCESS;
goto end;
}
if (player->timer.best_source.point.system_date == VLC_TICK_INVALID)
goto end;
if (system_now != VLC_TICK_INVALID)
ret = vlc_player_timer_point_Interpolate(&player->timer.best_source.point,
system_now, out_ts, out_pos);
else
ret = VLC_SUCCESS;
end:
vlc_mutex_unlock(&player->timer.lock);
return ret;
}

Loading…
Cancel
Save