[vlc-devel] [PATCH 13/17] input: send input clock points to the player
Thomas Guillem
thomas at gllm.fr
Mon Feb 15 10:15:08 UTC 2021
player/timer: there is now always a common master source (when es_source
== NULL), and there is no need to handle ES source priorities anymore.
vlc_player_UpdateTimer() still need a bool clock_source to identify the
source. There are 4 possible sources:
- The input source (from demux GET_TIME/POSITION/LENGTH) (clock_source
== false, es_source == NULL). It is only used at startup or if
the demux doesn't have any programs or ES.
- The input PCR points from the demux (clock_source == false, es_source
== NULL)
- The output points from the master, override the input PCR point.
There can be only one source between input and master. (clock_source
== false, es_source == NULL)
- The Output points from the video (for SMPTE timer (clock_source ==
false, es_source == video_es)
One test from test/player was removed: the assertions for the regular
timer check. Indeed, we can't ensure that we only receive outputs points
anymore.
---
src/input/es_out.c | 45 ++++++++---
src/input/event.h | 4 +-
src/input/input_internal.h | 1 -
src/player/input.c | 7 +-
src/player/player.h | 5 +-
src/player/timer.c | 157 ++++++++++++++++++++-----------------
test/src/player/player.c | 26 ------
7 files changed, 126 insertions(+), 119 deletions(-)
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 0d95e0f8c8a..259a4a52a11 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -1349,6 +1349,20 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
}
}
+static void MasterClockUpdate(vlc_tick_t system_ts, vlc_tick_t ts, double rate,
+ unsigned frame_rate, unsigned frame_rate_base,
+ void *data)
+{
+ es_out_sys_t *p_sys = data;
+
+ input_SendEventOutputClock(p_sys->p_input, NULL, system_ts,
+ ts, rate, frame_rate, frame_rate_base);
+}
+
+static const struct vlc_clock_cbs master_clock_cbs = {
+ .on_update = MasterClockUpdate
+};
+
/* EsOutAddProgram:
* Add a program
*/
@@ -1384,7 +1398,7 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, input_source_t *source, in
}
vlc_clock_t *clock_listener =
- vlc_clock_main_CreateInput( p_pgrm->p_main_clock, NULL, NULL );
+ vlc_clock_main_CreateInput( p_pgrm->p_main_clock, &master_clock_cbs, p_sys );
if( clock_listener == NULL )
{
vlc_clock_main_Delete( p_pgrm->p_main_clock );
@@ -2149,14 +2163,14 @@ static bool EsIsSelected( es_out_id_t *es )
}
}
-static void ClockUpdate(vlc_tick_t system_ts, vlc_tick_t ts, double rate,
- unsigned frame_rate, unsigned frame_rate_base,
- void *data)
+static void VideoClockUpdate(vlc_tick_t system_ts, vlc_tick_t ts, double rate,
+ unsigned frame_rate, unsigned frame_rate_base,
+ void *data)
{
es_out_id_t *es = data;
es_out_sys_t *p_sys = container_of(es->out, es_out_sys_t, out);
- input_SendEventOutputClock(p_sys->p_input, &es->id, es->master, system_ts,
+ input_SendEventOutputClock(p_sys->p_input, &es->id, system_ts,
ts, rate, frame_rate, frame_rate_base);
}
@@ -2166,10 +2180,6 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
input_thread_t *p_input = p_sys->p_input;
vlc_input_decoder_t *dec;
- static const struct vlc_clock_cbs clock_cbs = {
- .on_update = ClockUpdate
- };
-
assert( p_es->p_pgrm );
if( p_es->fmt.i_cat != UNKNOWN_ES
@@ -2179,14 +2189,27 @@ static void EsOutCreateDecoder( es_out_t *out, es_out_id_t *p_es )
p_es->master = true;
p_es->p_pgrm->p_master_clock = p_es->p_clock =
vlc_clock_main_CreateMaster( p_es->p_pgrm->p_main_clock,
- &clock_cbs, p_es );
+ &master_clock_cbs, p_sys );
}
else
{
+ const struct vlc_clock_cbs *clock_cbs = NULL;
+ void *clock_cbs_data = NULL;
+
+ if( p_es->fmt.i_cat == VIDEO_ES )
+ {
+ /* Register callbacks for the SMPTE Timer */
+ static const struct vlc_clock_cbs video_clock_cbs = {
+ .on_update = VideoClockUpdate
+ };
+ clock_cbs = &video_clock_cbs;
+ clock_cbs_data = p_es;
+ }
+
p_es->master = false;
p_es->p_clock = vlc_clock_main_CreateSlave( p_es->p_pgrm->p_main_clock,
p_es->fmt.i_cat,
- &clock_cbs, p_es );
+ clock_cbs, clock_cbs_data );
}
if( !p_es->p_clock )
diff --git a/src/input/event.h b/src/input/event.h
index dd9aec4a871..3ecd38866a3 100644
--- a/src/input/event.h
+++ b/src/input/event.h
@@ -66,7 +66,7 @@ static inline void input_SendEventTimes(input_thread_t *p_input,
}
static inline void input_SendEventOutputClock(input_thread_t *p_input,
- vlc_es_id_t *id, bool master,
+ vlc_es_id_t *id,
vlc_tick_t system_ts,
vlc_tick_t ts, double rate,
unsigned frame_rate,
@@ -74,7 +74,7 @@ static inline void input_SendEventOutputClock(input_thread_t *p_input,
{
input_SendEvent(p_input, &(struct vlc_input_event) {
.type = INPUT_EVENT_OUTPUT_CLOCK,
- .output_clock = { id, master, system_ts, ts, rate,
+ .output_clock = { id, system_ts, ts, rate,
frame_rate, frame_rate_base }
});
}
diff --git a/src/input/input_internal.h b/src/input/input_internal.h
index 7279fb0becc..3e26d95e681 100644
--- a/src/input/input_internal.h
+++ b/src/input/input_internal.h
@@ -169,7 +169,6 @@ struct vlc_input_event_times
struct vlc_input_event_output_clock
{
vlc_es_id_t *id;
- bool master;
vlc_tick_t system_ts;
vlc_tick_t ts;
double rate;
diff --git a/src/player/input.c b/src/player/input.c
index 535df00e6c4..aa340601cf8 100644
--- a/src/player/input.c
+++ b/src/player/input.c
@@ -709,15 +709,14 @@ input_thread_Events(input_thread_t *input_thread,
if (event->output_clock.system_ts != VLC_TICK_INVALID)
{
const struct vlc_player_timer_point point = {
- .position = 0,
+ .position = -1,
.rate = event->output_clock.rate,
.ts = event->output_clock.ts,
.length = VLC_TICK_INVALID,
.system_date = event->output_clock.system_ts,
};
- vlc_player_UpdateTimer(player, event->output_clock.id,
- event->output_clock.master, &point,
- VLC_TICK_INVALID,
+ vlc_player_UpdateTimer(player, event->output_clock.id, true,
+ &point, VLC_TICK_INVALID,
event->output_clock.frame_rate,
event->output_clock.frame_rate_base);
}
diff --git a/src/player/player.h b/src/player/player.h
index ae5a2770d6b..9be85378922 100644
--- a/src/player/player.h
+++ b/src/player/player.h
@@ -170,6 +170,7 @@ struct vlc_player_timer_id
{
vlc_tick_t period;
vlc_tick_t last_update_date;
+ vlc_tick_t last_ts;
union
{
@@ -214,6 +215,8 @@ struct vlc_player_timer
enum vlc_player_timer_state state;
bool seeking;
+ bool has_clock_source;
+ vlc_tick_t input_time;
vlc_tick_t input_length;
vlc_tick_t input_normal_time;
vlc_tick_t last_ts;
@@ -462,7 +465,7 @@ vlc_player_UpdateTimerState(vlc_player_t *player, vlc_es_id_t *es_source,
void
vlc_player_UpdateTimer(vlc_player_t *player, vlc_es_id_t *es_source,
- bool es_source_is_master,
+ bool clock_source,
const struct vlc_player_timer_point *point,
vlc_tick_t normal_time,
unsigned frame_rate, unsigned frame_rate_base);
diff --git a/src/player/timer.c b/src/player/timer.c
index 48005571494..d76126a383c 100644
--- a/src/player/timer.c
+++ b/src/player/timer.c
@@ -32,6 +32,7 @@ vlc_player_ResetTimer(vlc_player_t *player)
vlc_mutex_lock(&player->timer.lock);
player->timer.state = VLC_PLAYER_TIMER_STATE_DISCONTINUITY;
+ player->timer.has_clock_source = false;
player->timer.input_length = VLC_TICK_INVALID;
player->timer.input_normal_time = VLC_TICK_0;
player->timer.last_ts = VLC_TICK_INVALID;
@@ -52,13 +53,17 @@ vlc_player_SendTimerSourceUpdates(vlc_player_t *player,
vlc_list_foreach(timer, &source->listeners, node)
{
- /* Respect refresh delay of the timer */
- if (force_update || timer->period == VLC_TICK_INVALID
- || timer->last_update_date == VLC_TICK_INVALID
- || point->system_date == INT64_MAX /* always update when paused */
- || point->system_date - timer->last_update_date >= timer->period)
+ /* Respect refresh delay of the timer. Don't update when the ts point
+ * decrease. It can happen for a very short time when switching clock
+ * sources (from input to master ES). */
+ if (point->ts > timer->last_ts
+ && (force_update || timer->period == VLC_TICK_INVALID
+ || timer->last_update_date == VLC_TICK_INVALID
+ || point->system_date == INT64_MAX /* always update when paused */
+ || point->system_date - timer->last_update_date >= timer->period))
{
timer->cbs->on_update(point, timer->data);
+ timer->last_ts = point->ts;
timer->last_update_date = point->system_date == INT64_MAX ?
VLC_TICK_INVALID : point->system_date;
}
@@ -198,6 +203,7 @@ vlc_player_UpdateTimerState(vlc_player_t *player, vlc_es_id_t *es_source,
notify = bestsource->es == es_source;
source->point.system_date = VLC_TICK_INVALID;
}
+ player->timer.has_clock_source = false;
break;
case VLC_PLAYER_TIMER_STATE_PAUSED:
@@ -221,7 +227,7 @@ vlc_player_UpdateTimerState(vlc_player_t *player, vlc_es_id_t *es_source,
vlc_player_timer_id *timer;
vlc_list_foreach(timer, &bestsource->listeners, node)
{
- timer->last_update_date = VLC_TICK_INVALID;
+ timer->last_ts = timer->last_update_date = VLC_TICK_INVALID;
timer->cbs->on_discontinuity(system_date, timer->data);
}
@@ -257,86 +263,84 @@ vlc_player_UpdateTimerSource(vlc_player_t *player,
void
vlc_player_UpdateTimer(vlc_player_t *player, vlc_es_id_t *es_source,
- bool es_source_is_master,
+ bool clock_source,
const struct vlc_player_timer_point *point,
vlc_tick_t normal_time,
unsigned frame_rate, unsigned frame_rate_base)
{
struct vlc_player_timer_source *source;
assert(point);
- /* A null source can't be the master */
- assert(es_source == NULL ? !es_source_is_master : true);
vlc_mutex_lock(&player->timer.lock);
+ vlc_tick_t ts = point->ts;
+ vlc_tick_t system_date = point->system_date;
+ if (player->timer.state == VLC_PLAYER_TIMER_STATE_PAUSED)
+ system_date = INT64_MAX;
+
+ if (clock_source)
+ player->timer.has_clock_source = true;
+
bool force_update = false;
- if (!es_source) /* input source */
+ if (es_source == NULL) /* clock source or input source */
{
- /* Only valid for input sources */
- if (player->timer.input_normal_time != normal_time)
- {
- player->timer.input_normal_time = normal_time;
- player->timer.last_ts = VLC_TICK_INVALID;
- force_update = true;
- }
- if (player->timer.input_length != point->length
- && point->length >= VLC_TICK_0)
+ source = &player->timer.best_source;
+
+ if (!clock_source)
{
- player->timer.input_length = point->length;
- player->timer.last_ts = VLC_TICK_INVALID;
- force_update = true;
+ /* input source */
+ if (player->timer.input_normal_time != normal_time
+ && normal_time != VLC_TICK_INVALID)
+ {
+ player->timer.input_normal_time = normal_time;
+ player->timer.last_ts = VLC_TICK_INVALID;
+ force_update = true;
+ }
+ if (player->timer.input_length != point->length
+ && point->length >= VLC_TICK_0)
+ {
+ player->timer.input_length = point->length;
+ player->timer.last_ts = VLC_TICK_INVALID;
+ force_update = true;
+ }
+
+ /* Will likely be overridden by non input source */
+ if (point->position >= 0)
+ player->timer.input_position = point->position;
+
+ if (player->timer.has_clock_source)
+ {
+ if (!force_update)
+ {
+ /* Don't override clock points from the input times */
+ vlc_mutex_unlock(&player->timer.lock);
+ return;
+ }
+
+ /* Update forced, only update the length, so use the last point
+ * from the clock */
+ ts = source->point.ts;
+ system_date = source->point.system_date;
+ }
}
- /* Will likely be overridden by non input source */
- player->timer.input_position = point->position;
- if (point->ts == VLC_TICK_INVALID
- || point->system_date == VLC_TICK_INVALID)
+ if (ts == VLC_TICK_INVALID || system_date == VLC_TICK_INVALID)
{
- /* ts can only be invalid from the input source */
vlc_mutex_unlock(&player->timer.lock);
return;
}
- }
-
- assert(point->ts != VLC_TICK_INVALID);
- vlc_tick_t system_date = point->system_date;
- if (player->timer.state == VLC_PLAYER_TIMER_STATE_PAUSED)
- system_date = INT64_MAX;
+ /* An update after a discontinuity means that the playback is resumed */
+ if (player->timer.state == VLC_PLAYER_TIMER_STATE_DISCONTINUITY)
+ player->timer.state = VLC_PLAYER_TIMER_STATE_PLAYING;
- /* An update after a discontinuity means that the playback is resumed */
- if (player->timer.state == VLC_PLAYER_TIMER_STATE_DISCONTINUITY)
- player->timer.state = VLC_PLAYER_TIMER_STATE_PLAYING;
-
- /* Best source priority:
- * 1/ es_source != NULL when paused (any ES tracks when paused. Indeed,
- * there is likely no audio update (master) when paused but only video
- * ones, via vlc_player_NextVideoFrame() for example)
- * 2/ es_source != NULL + master (from the master ES track)
- * 3/ es_source != NULL (from the first ES track updated)
- * 4/ es_source == NULL (from the input)
- */
- source = &player->timer.best_source;
- if (!source->es || es_source_is_master
- || (es_source && player->timer.state == VLC_PLAYER_TIMER_STATE_PAUSED))
- source->es = es_source;
-
- /* Notify the best source */
- if (source->es == es_source)
- {
if (source->point.rate != point->rate)
- {
- player->timer.last_ts = VLC_TICK_INVALID;
force_update = true;
- }
- /* When paused (INT64_MAX), the same ts can be send more than one time
- * from the video source, only send it if different in that case. */
- if (point->ts != player->timer.last_ts
- || source->point.system_date != system_date
+ if (source->point.system_date != system_date
|| system_date != INT64_MAX)
{
- vlc_player_UpdateTimerSource(player, source, point->rate, point->ts,
+ vlc_player_UpdateTimerSource(player, source, point->rate, ts,
system_date);
if (!vlc_list_is_empty(&source->listeners))
@@ -344,16 +348,23 @@ vlc_player_UpdateTimer(vlc_player_t *player, vlc_es_id_t *es_source,
&source->point);
}
}
+ else
+ {
+ assert(clock_source);
+ source = &player->timer.smpte_source;
- source = &player->timer.smpte_source;
- /* SMPTE source: only the video source */
- if (!source->es && es_source && vlc_es_id_GetCat(es_source) == VIDEO_ES)
- source->es = es_source;
+ /* SMPTE source: only the video source */
+ if (!source->es && vlc_es_id_GetCat(es_source) == VIDEO_ES)
+ source->es = es_source;
- /* Notify the SMPTE source, also notify when the video output was rendered
- * while the clock was paused */
- if (source->es == es_source && source->es)
- {
+ if (source->es != es_source)
+ {
+ vlc_mutex_unlock(&player->timer.lock);
+ return;
+ }
+
+ /* Notify the SMPTE source, also notify when the video output was
+ * rendered while the clock was paused */
if (frame_rate != 0 && (frame_rate != source->smpte.frame_rate
|| frame_rate_base != source->smpte.frame_rate_base))
{
@@ -372,10 +383,8 @@ vlc_player_UpdateTimer(vlc_player_t *player, vlc_es_id_t *es_source,
vlc_player_SendSmpteTimerSourceUpdates(player, source,
&source->point);
}
+ player->timer.last_ts = point->ts;
}
-
- player->timer.last_ts = point->ts;
-
vlc_mutex_unlock(&player->timer.lock);
}
@@ -425,7 +434,7 @@ vlc_player_AddTimer(vlc_player_t *player, vlc_tick_t min_period,
if (!timer)
return NULL;
timer->period = min_period;
- timer->last_update_date = VLC_TICK_INVALID;
+ timer->last_ts = timer->last_update_date = VLC_TICK_INVALID;
timer->cbs = cbs;
timer->data = data;
@@ -447,7 +456,7 @@ vlc_player_AddSmpteTimer(vlc_player_t *player,
if (!timer)
return NULL;
timer->period = VLC_TICK_INVALID;
- timer->last_update_date = VLC_TICK_INVALID;
+ timer->last_ts = timer->last_update_date = VLC_TICK_INVALID;
timer->smpte_cbs = cbs;
timer->data = data;
diff --git a/test/src/player/player.c b/test/src/player/player.c
index 704b3f8b4d0..30f53ee8cd3 100644
--- a/test/src/player/player.c
+++ b/test/src/player/player.c
@@ -2331,32 +2331,6 @@ test_timers_playback(struct ctx *ctx, struct timer_state timers[],
}
}
- /* Assertions for the regular timer that received all update points */
- if (track_count != 0)
- {
- struct timer_state *timer = &timers[REGULAR_TIMER_IDX];
- vec_report_timer *vec = &timer->vec;
-
- /* Check that we didn't miss any update points */
- assert(vec->size > 1);
- size_t point_count = 1;
- for (size_t i = 1; i < vec->size - 1; ++i)
- {
- struct report_timer *prev_report = &vec->data[i - 1];
- struct report_timer *report = &vec->data[i];
-
- /* Don't count forced points */
- if (report->point.ts != prev_report->point.ts)
- {
- assert(report->point.ts == prev_report->point.ts + SAMPLE_LENGTH);
- point_count++;
- }
- }
- assert(vec->data[vec->size - 2].point.ts
- == length - SAMPLE_LENGTH + VLC_TICK_0);
- assert(point_count == MAX_UPDATE_COUNT);
- }
-
/* Assertions for the regular filtered timer */
{
struct timer_state *timer = &timers[REGULAR_DELAY_TIMER_IDX];
--
2.30.0
More information about the vlc-devel
mailing list