[vlc-devel] [RFC PATCH 09/13] FIXUP: implement audio/video/spu delay
Thomas Guillem
thomas at gllm.fr
Wed Jun 27 14:41:31 CEST 2018
Each ESses will set the delay to their specific clocks.
Setting a delay on the master clock has an effect on all others slaves clocks.
Setting a delay on a slave clock has only an effect for the current clock.
For the audio master case (most common case), the aout need to wait (play
silence) when adding a positive delay to the master clock.
---
src/audio_output/aout_internal.h | 3 ++
src/audio_output/dec.c | 24 +++++++++++++
src/clock/clock.c | 42 ++++++++++++++++++++++
src/clock/clock.h | 7 ++++
src/input/decoder.c | 56 +++++++++++++++++++++++------
src/video_output/control.h | 13 ++++++-
src/video_output/video_output.c | 53 ++++++++++++++++++++++++---
src/video_output/vout_internal.h | 15 ++++++++
src/video_output/vout_subpictures.c | 6 ++++
9 files changed, 203 insertions(+), 16 deletions(-)
diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h
index 9437b13cfb..b1f658b9eb 100644
--- a/src/audio_output/aout_internal.h
+++ b/src/audio_output/aout_internal.h
@@ -78,6 +78,8 @@ typedef struct
vlc_tick_t resamp_start_drift; /**< Resampler drift absolute value */
int resamp_type; /**< Resampler mode (FIXME: redundant / resampling) */
bool discontinuity;
+ vlc_tick_t request_delay;
+ vlc_tick_t delay;
} sync;
int requested_stereo_mode; /**< Requested stereo mode set by the user */
@@ -149,6 +151,7 @@ int aout_DecPlay(audio_output_t *aout, block_t *block);
void aout_DecGetResetStats(audio_output_t *, unsigned *, unsigned *);
void aout_DecChangePause(audio_output_t *, bool b_paused, vlc_tick_t i_date);
void aout_DecChangeRate(audio_output_t *aout, float rate);
+void aout_DecChangeDelay(audio_output_t *aout, vlc_tick_t delay);
void aout_DecFlush(audio_output_t *, bool wait);
void aout_RequestRestart (audio_output_t *, unsigned);
void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t audio_ts,
diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c
index 3f3a6da702..59a1c065c3 100644
--- a/src/audio_output/dec.c
+++ b/src/audio_output/dec.c
@@ -106,6 +106,7 @@ error:
owner->sync.end = VLC_TS_INVALID;
owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
owner->sync.discontinuity = true;
+ owner->sync.delay = owner->sync.request_delay = 0;
atomic_init (&owner->buffers_lost, 0);
atomic_init (&owner->buffers_played, 0);
@@ -230,6 +231,16 @@ static void aout_DecSilence (audio_output_t *aout, vlc_tick_t length, vlc_tick_t
static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t dec_pts)
{
+ aout_owner_t *owner = aout_owner (aout);
+
+ if (owner->sync.request_delay != owner->sync.delay)
+ {
+ owner->sync.delay = owner->sync.request_delay;
+ vlc_tick_t delta = vlc_clock_SetDelay(owner->sync.clock, owner->sync.delay);
+ if (delta > 0)
+ aout_DecSilence (aout, delta, dec_pts);
+ }
+
vlc_tick_t now = vlc_tick_now();
vlc_tick_t delay;
@@ -390,6 +401,12 @@ int aout_DecPlay(audio_output_t *aout, block_t *block)
/* Drift correction */
aout_DecSynchronize(aout, block->i_pts);
+ if (owner->sync.delay != 0)
+ {
+ block->i_pts += owner->sync.delay;
+ block->i_dts += owner->sync.delay;
+ }
+
/* Output */
owner->sync.end = block->i_pts + block->i_length + 1;
owner->sync.discontinuity = false;
@@ -446,6 +463,13 @@ void aout_DecChangeRate(audio_output_t *aout, float rate)
owner->sync.rate = rate;
}
+void aout_DecChangeDelay(audio_output_t *aout, vlc_tick_t delay)
+{
+ aout_owner_t *owner = aout_owner(aout);
+
+ owner->sync.request_delay = delay;
+}
+
void aout_DecFlush (audio_output_t *aout, bool wait)
{
aout_owner_t *owner = aout_owner (aout);
diff --git a/src/clock/clock.c b/src/clock/clock.c
index ecf5e9db56..cbba4bca09 100644
--- a/src/clock/clock.c
+++ b/src/clock/clock.c
@@ -62,6 +62,7 @@ struct vlc_clock_t
vlc_tick_t system_now, float rate);
void (*reset)(vlc_clock_t * clock);
void (*pause)(vlc_clock_t * clock, bool paused, vlc_tick_t now);
+ vlc_tick_t (*set_delay)(vlc_clock_t * clock, vlc_tick_t delay);
void (*set_dejitter)(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg);
vlc_tick_t (*to_system_locked)(vlc_clock_t * clock, vlc_tick_t now, vlc_tick_t pts);
@@ -183,6 +184,28 @@ static void vlc_clock_master_pause(vlc_clock_t * clock, bool paused, vlc_tick_t
vlc_mutex_unlock(&main_clock->lock);
}
+static vlc_tick_t vlc_clock_master_set_delay(vlc_clock_t * clock, vlc_tick_t delay)
+{
+ vlc_clock_main_t * main_clock = clock->owner;
+ vlc_mutex_lock(&main_clock->lock);
+
+ vlc_tick_t delta = delay - main_clock->delay;
+ main_clock->delay = delay;
+ if (delta > 0)
+ {
+ if (main_clock->reset_date == VLC_TS_INVALID)
+ main_clock->reset_date = vlc_tick_now() + delta;
+ else
+ main_clock->reset_date += delta;
+ }
+ else
+ delta = 0;
+
+ vlc_cond_broadcast(&main_clock->cond);
+ vlc_mutex_unlock(&main_clock->lock);
+ return delta;
+}
+
static float vlc_clock_get_rate(vlc_clock_t * clock)
{
float rate;
@@ -295,6 +318,18 @@ static void vlc_clock_slave_pause(vlc_clock_t * clock, bool paused, vlc_tick_t n
VLC_UNUSED(now);
}
+static vlc_tick_t vlc_clock_slave_set_delay(vlc_clock_t * clock, vlc_tick_t delay)
+{
+ vlc_clock_main_t * main_clock = clock->owner;
+ vlc_mutex_lock(&main_clock->lock);
+
+ clock->delay = delay;
+
+ vlc_cond_broadcast(&main_clock->cond);
+ vlc_mutex_unlock(&main_clock->lock);
+ return 0;
+}
+
int vlc_clock_Wait(vlc_clock_t * clock, vlc_tick_t pts, vlc_tick_t max_duration)
{
vlc_clock_main_t * main_clock = clock->owner;
@@ -404,6 +439,11 @@ void vlc_clock_ChangePause(vlc_clock_t * clock, bool paused, vlc_tick_t system_n
clock->pause(clock, paused, system_now);
}
+vlc_tick_t vlc_clock_SetDelay(vlc_clock_t * clock, vlc_tick_t delay)
+{
+ return clock->set_delay(clock, delay);
+}
+
float vlc_clock_GetRate(vlc_clock_t * clock)
{
return vlc_clock_get_rate(clock);
@@ -449,6 +489,7 @@ static void vlc_clock_set_master_cbk(vlc_clock_t * clk)
clk->update = vlc_clock_master_update;
clk->reset = vlc_clock_master_reset;
clk->pause = vlc_clock_master_pause;
+ clk->set_delay = vlc_clock_master_set_delay;
clk->set_dejitter = vlc_clock_master_set_dejitter;
clk->to_system_locked = vlc_clock_master_to_system_locked;
}
@@ -458,6 +499,7 @@ static void vlc_clock_set_slave_cbk(vlc_clock_t * clk)
clk->update = vlc_clock_slave_update;
clk->reset = vlc_clock_slave_reset;
clk->pause = vlc_clock_slave_pause;
+ clk->set_delay = vlc_clock_slave_set_delay;
clk->set_dejitter = vlc_clock_slave_set_dejitter;
clk->to_system_locked = vlc_clock_slave_to_system_locked;
}
diff --git a/src/clock/clock.h b/src/clock/clock.h
index 51e34f34e1..41469a9274 100644
--- a/src/clock/clock.h
+++ b/src/clock/clock.h
@@ -91,6 +91,13 @@ void vlc_clock_Reset(vlc_clock_t * clock);
void vlc_clock_ChangePause(vlc_clock_t * clock, bool paused,
vlc_tick_t sysem_now);
+/**
+ * This functions change the clock delay.
+ * It returns the amount of time the clock owner need to wait in order to reach
+ * the time introduced by the new positive delay.
+ */
+vlc_tick_t vlc_clock_SetDelay(vlc_clock_t * clock, vlc_tick_t pts_delay);
+
/**
* This function returns the current rate.
*/
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 4650850e17..2597431997 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -111,6 +111,7 @@ struct decoder_owner
vlc_tick_t i_preroll_end;
/* Pause & Rate */
vlc_tick_t pause_date;
+ vlc_tick_t delay;
float rate;
unsigned frames_countdown;
bool paused;
@@ -136,9 +137,6 @@ struct decoder_owner
decoder_cc_desc_t desc;
decoder_t *pp_decoder[MAX_CC_DECODERS];
} cc;
-
- /* Delay */
- vlc_tick_t i_ts_delay;
};
/* Pictures which are DECODER_BOGUS_VIDEO_DELAY or more in advance probably have
@@ -1433,6 +1431,31 @@ static void OutputChangeRate( decoder_t *p_dec, float rate )
}
}
+static void OutputChangeDelay( decoder_t *p_dec, vlc_tick_t delay )
+{
+ struct decoder_owner *p_owner = dec_get_owner( p_dec );
+
+ msg_Dbg( p_dec, "changing delay: %"PRId64, delay );
+ switch( p_dec->fmt_out.i_cat )
+ {
+ case VIDEO_ES:
+ if( p_owner->p_vout != NULL )
+ vout_ChangeDelay( p_owner->p_vout, delay );
+ break;
+ case AUDIO_ES:
+ if( p_owner->p_aout != NULL )
+ aout_DecChangeDelay( p_owner->p_aout, delay );
+ break;
+ case SPU_ES:
+ if( p_owner->p_vout != NULL )
+ vout_ChangeSpuDelay( p_owner->p_vout, p_owner->i_spu_channel,
+ delay );
+ break;
+ default:
+ vlc_assert_unreachable();
+ }
+}
+
/**
* The decoding main loop
*
@@ -1443,6 +1466,7 @@ static void *DecoderThread( void *p_data )
decoder_t *p_dec = (decoder_t *)p_data;
struct decoder_owner *p_owner = dec_get_owner( p_dec );
float rate = 1.f;
+ vlc_tick_t delay = 0;
bool paused = false;
/* The decoder's main loop */
@@ -1500,6 +1524,19 @@ static void *DecoderThread( void *p_data )
vlc_fifo_Lock( p_owner->p_fifo );
}
+ if( delay != p_owner->delay )
+ {
+ int canc = vlc_savecancel();
+
+ delay = p_owner->delay;
+ vlc_fifo_Unlock( p_owner->p_fifo );
+
+ OutputChangeDelay( p_dec, delay );
+
+ vlc_restorecancel( canc );
+ vlc_fifo_Lock( p_owner->p_fifo );
+ }
+
if( p_owner->paused && p_owner->frames_countdown == 0 )
{ /* Wait for resumption from pause */
p_owner->b_idle = true;
@@ -1620,6 +1657,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
p_owner->b_fmt_description = false;
p_owner->p_description = NULL;
+ p_owner->delay = 0;
p_owner->rate = 1.f;
p_owner->paused = false;
p_owner->pause_date = VLC_TS_INVALID;
@@ -1722,7 +1760,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
p_owner->cc.desc.i_708_channels = 0;
for( unsigned i = 0; i < MAX_CC_DECODERS; i++ )
p_owner->cc.pp_decoder[i] = NULL;
- p_owner->i_ts_delay = 0;
return p_dec;
}
@@ -2215,17 +2252,16 @@ void input_DecoderChangeRate( decoder_t *dec, float rate )
vlc_fifo_Lock( owner->p_fifo );
owner->rate = rate;
- vlc_fifo_Signal( owner->p_fifo );
vlc_fifo_Unlock( owner->p_fifo );
}
-void input_DecoderChangeDelay( decoder_t *p_dec, vlc_tick_t i_delay )
+void input_DecoderChangeDelay( decoder_t *dec, vlc_tick_t delay )
{
- struct decoder_owner *p_owner = dec_get_owner( p_dec );
+ struct decoder_owner *owner = dec_get_owner( dec );
- vlc_mutex_lock( &p_owner->lock );
- p_owner->i_ts_delay = i_delay;
- vlc_mutex_unlock( &p_owner->lock );
+ vlc_fifo_Lock( owner->p_fifo );
+ owner->delay = delay;
+ vlc_fifo_Unlock( owner->p_fifo );
}
void input_DecoderStartWait( decoder_t *p_dec )
diff --git a/src/video_output/control.h b/src/video_output/control.h
index ad04dff963..70117c7507 100644
--- a/src/video_output/control.h
+++ b/src/video_output/control.h
@@ -48,7 +48,9 @@ enum {
VOUT_CONTROL_CHANGE_SUB_MARGIN, /* integer */
VOUT_CONTROL_PAUSE,
- VOUT_CONTROL_CHANGE_RATE, /* float */
+ VOUT_CONTROL_CHANGE_RATE, /* rate */
+ VOUT_CONTROL_CHANGE_DELAY, /* delay */
+ VOUT_CONTROL_CHANGE_SPU_DELAY, /* spu_delay */
VOUT_CONTROL_FLUSH, /* time */
VOUT_CONTROL_STEP, /* time_ptr */
@@ -85,6 +87,7 @@ typedef struct {
vlc_tick_t date;
} pause;
float rate;
+ vlc_tick_t delay;
struct {
int channel;
char *string;
@@ -101,6 +104,14 @@ typedef struct {
unsigned width;
unsigned height;
} window;
+ struct {
+ int channel;
+ float value;
+ } spu_rate;
+ struct {
+ int channel;
+ vlc_tick_t value;
+ } spu_delay;
vlc_mouse_t mouse;
const vout_configuration_t *cfg;
subpicture_t *subpicture;
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 67858b1a91..adc3240eb2 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -133,7 +133,7 @@ static vout_thread_t *VoutCreate(vlc_object_t *object,
/* */
vout->p = (vout_thread_sys_t*)&vout[1];
- vout->p->rate = 1;
+ vout->p->rate = 1.f;
vout->p->clock = cfg->clock;
vout->p->original = original;
vout->p->dpb_size = cfg->dpb_size;
@@ -338,6 +338,27 @@ void vout_ChangeRate(vout_thread_t *vout, float rate)
vout_control_WaitEmpty(&vout->p->control);
}
+void vout_ChangeDelay(vout_thread_t *vout, vlc_tick_t delay)
+{
+ vout_control_cmd_t cmd;
+ vout_control_cmd_Init(&cmd, VOUT_CONTROL_CHANGE_DELAY);
+ cmd.delay = delay;
+ vout_control_Push(&vout->p->control, &cmd);
+
+ vout_control_WaitEmpty(&vout->p->control);
+}
+
+void vout_ChangeSpuDelay(vout_thread_t *vout, int channel, vlc_tick_t delay)
+{
+ vout_control_cmd_t cmd;
+ vout_control_cmd_Init(&cmd, VOUT_CONTROL_CHANGE_SPU_DELAY);
+ cmd.spu_delay.channel = channel;
+ cmd.spu_delay.value = delay;
+ vout_control_Push(&vout->p->control, &cmd);
+
+ vout_control_WaitEmpty(&vout->p->control);
+}
+
void vout_GetResetStatistic(vout_thread_t *vout, unsigned *restrict displayed,
unsigned *restrict lost)
{
@@ -1000,8 +1021,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
if (vout->p->pause.is_on)
render_subtitle_date = vout->p->pause.date;
else
- render_subtitle_date = filtered->date > 1 ? filtered->date : vlc_tick_now();
- vlc_tick_t render_osd_date = vlc_tick_now(); /* FIXME wrong */
+ render_subtitle_date =
+ vlc_clock_ConvertToSystem(vout->p->clock, system_now, filtered->date);
/*
* Get the subpicture to be displayed
@@ -1330,9 +1351,18 @@ static void ThreadChangePause(vout_thread_t *vout, bool is_paused, vlc_tick_t da
vlc_clock_ChangePause(vout->p->clock, is_paused, date);
}
-static void ThreadChangeRate(vout_thread_t *vout, float rate)
+static void ThreadChangeDelay(vout_thread_t *vout, vlc_tick_t delay)
{
- vout->p->rate = rate;
+ if (vout->p->clock)
+ vlc_clock_SetDelay(vout->p->clock, delay);
+}
+
+static void ThreadChangeSpuDelay(vout_thread_t *vout, int channel, vlc_tick_t delay)
+{
+ vlc_mutex_lock(&vout->p->spu_lock);
+ if (vout->p->spu)
+ spu_SetClockDelay(vout->p->spu, delay);
+ vlc_mutex_unlock(&vout->p->spu_lock);
}
static void ThreadFlush(vout_thread_t *vout, bool below, vlc_tick_t date)
@@ -1360,6 +1390,13 @@ static void ThreadFlush(vout_thread_t *vout, bool below, vlc_tick_t date)
vlc_clock_Reset(vout->p->clock);
}
+static void ThreadChangeRate(vout_thread_t *vout, float rate)
+{
+ if (rate != vout->p->rate)
+ ThreadFlush(vout, false, 0);
+ vout->p->rate = rate;
+}
+
static void ThreadStep(vout_thread_t *vout, vlc_tick_t *duration)
{
*duration = 0;
@@ -1754,6 +1791,12 @@ static int ThreadControl(vout_thread_t *vout, vout_control_cmd_t cmd)
case VOUT_CONTROL_CHANGE_RATE:
ThreadChangeRate(vout, cmd.rate);
break;
+ case VOUT_CONTROL_CHANGE_DELAY:
+ ThreadChangeDelay(vout, cmd.delay);
+ break;
+ case VOUT_CONTROL_CHANGE_SPU_DELAY:
+ ThreadChangeSpuDelay(vout, cmd.spu_delay.channel, cmd.spu_delay.value);
+ break;
case VOUT_CONTROL_FLUSH:
ThreadFlush(vout, false, cmd.time);
break;
diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h
index 2f0d52c44e..4e57dad406 100644
--- a/src/video_output/vout_internal.h
+++ b/src/video_output/vout_internal.h
@@ -63,6 +63,7 @@ struct vout_thread_sys_t
vlc_clock_t *clock;
float rate;
+ vlc_tick_t delay;
/* Input thread for dvd menu interactions */
vlc_object_t *input;
@@ -225,6 +226,7 @@ int spu_ProcessMouse(spu_t *, const vlc_mouse_t *, const video_format_t *);
void spu_Attach( spu_t *, vlc_object_t *input, bool );
void vout_SetSubpictureClock( vout_thread_t *vout, vlc_clock_t *clock ); /* FIXME */
void spu_SetClock( spu_t *, vlc_clock_t * );
+void spu_SetClockDelay(spu_t *spu, vlc_tick_t delay);
void spu_ChangeMargin(spu_t *, int);
/**
@@ -239,6 +241,19 @@ void vout_ChangePause( vout_thread_t *, bool b_paused, vlc_tick_t i_date );
*/
void vout_ChangeRate( vout_thread_t *, float rate );
+/**
+ * This function will change the delay of the vout
+ * It is thread safe
+ */
+void vout_ChangeDelay( vout_thread_t *, vlc_tick_t delay );
+
+/**
+ * This function will change the delay of the spu channel
+ * It is thread safe
+ */
+void vout_ChangeSpuDelay( vout_thread_t *, int spu_channel, vlc_tick_t delay );
+
+
/**
* Updates the pointing device state.
*/
diff --git a/src/video_output/vout_subpictures.c b/src/video_output/vout_subpictures.c
index dc3e83ede3..066f615603 100644
--- a/src/video_output/vout_subpictures.c
+++ b/src/video_output/vout_subpictures.c
@@ -1485,6 +1485,12 @@ void spu_SetClock(spu_t *spu, vlc_clock_t *clock)
spu->p->clock = clock;
}
+void spu_SetClockDelay(spu_t *spu, vlc_tick_t delay)
+{
+ if (spu->p->clock)
+ vlc_clock_SetDelay(spu->p->clock, delay);
+}
+
/**
* Inform the SPU filters of mouse event
*/
--
2.18.0
More information about the vlc-devel
mailing list