Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • videolan/vlc
  • chouquette/vlc
  • bakiewicz.marek122/vlc
  • devnexen/vlc
  • rohanrajpal/vlc
  • blurrrb/vlc
  • gsoc/gsoc2019/darkapex/vlc
  • b1ue/vlc
  • fkuehne/vlc
  • magsoft/vlc
  • chub/vlc
  • cramiro9/vlc
  • robUx4/vlc
  • rom1v/vlc
  • akshayaky/vlc
  • tmk907/vlc
  • akymaster/vlc
  • govind.sharma/vlc
  • psilokos/vlc
  • xjbeta/vlc
  • jahan/vlc
  • 1480c1/vlc
  • amanchande/vlc
  • aaqib/vlc
  • rist/vlc
  • apol/vlc
  • mindfreeze/vlc
  • alexandre-janniaux/vlc
  • sandsmark/vlc
  • jagannatharjun/vlc
  • gsoc/gsoc2020/matiaslgonzalez/vlc
  • gsoc/gsoc2020/jagannatharjun/vlc
  • mstorsjo/vlc
  • gsoc/gsoc2020/vedenta/vlc
  • gsoc/gsoc2020/arnav-ishaan/vlc
  • gsoc/gsoc2020/andreduong/vlc
  • fuzun/vlc
  • gsoc/gsoc2020/vatsin/vlc
  • gsoc/gsoc2020/sagid/vlc
  • yaron/vlc
  • Phoenix/vlc
  • Garf/vlc
  • ePiratWorkarounds/vlc
  • tguillem/vlc
  • jnqnfe/vlc
  • mdc/vlc
  • Vedaa/vlc
  • rasa/vlc
  • quink/vlc
  • yealo/vlc
  • aleksey_ak/vlc
  • ePirat/vlc
  • ilya.yanok/vlc
  • asenat/vlc
  • m/vlc
  • bunjee/vlc
  • BLumia/vlc
  • sagudev/vlc
  • hamedmonji30/vlc
  • nullgemm/vlc
  • DivyamAhuja/vlc
  • thesamesam/vlc
  • dag7/vlc
  • snehil101/vlc
  • haasn/vlc
  • jbk/vlc
  • ValZapod/vlc
  • mfkl/vlc
  • WangChuan/vlc
  • core1024/vlc
  • GhostVaibhav/vlc
  • dfuhrmann/vlc
  • davide.prade/vlc
  • tmatth/vlc
  • Courmisch/vlc
  • zouya/vlc
  • hpi/vlc
  • EwoutH/vlc
  • aleung27/vlc
  • hengwu0/vlc
  • saladin/vlc
  • ashuio/vlc
  • richselwood/vlc
  • verma16Ayush/vlc
  • chemicalflash/vlc
  • PoignardAzur/vlc
  • huangjieNT/vlc
  • Blake-Haydon/vlc
  • AnuthaDev/vlc
  • gsoc/gsoc2021/mpd/vlc
  • nicolas_lequec/vlc
  • sambassaly/vlc
  • thresh/vlc
  • bonniegong/vlc
  • myaashish/vlc
  • stavros.vagionitis/vlc
  • ileoo/vlc
  • louis-santucci/vlc
  • cchristiansen/vlc
  • sabyasachi07/vlc
  • AbduAmeen/vlc
  • ashishb0410/vlc
  • urbanhusky/vlc
  • davidepietrasanta/vlc
  • riksleutelstad/vlc
  • jeremyVignelles/vlc
  • komh/vlc
  • iamjithinjohn/vlc
  • JohannesKauffmann/vlc2
  • kunglao/vlc
  • natzberg/vlc
  • jill/vlc
  • cwendling/vlc
  • adufou/vlc
  • ErwanAirone/vlc
  • HasinduDilshan10/vlc
  • vagrantc/vlc
  • rafiv/macos-bigsur-icon
  • Aymeriic/vlc
  • saranshg20/vlc
  • metzlove24/vlc
  • linkfanel/vlc
  • Ds886/vlc
  • metehan-arslan/vlc
  • Skantes/vlc
  • kgsandundananjaya96/vlc
  • mitchcapper/vlc
  • advaitgupta/vlc
  • StefanBruens/vlc
  • ratajs/vlc
  • T.M.F.B.3761/vlc
  • m222059/vlc
  • casemerrick/vlc
  • joshuaword2alt/vlc
  • sjwaddy/vlc
  • dima/vlc
  • Ybalrid/vlc
  • umxprime/vlc
  • eschmidt/vlc
  • vannieuwenhuysenmichelle/vlc
  • badcf00d/vlc
  • wesinator/vlc
  • louis/vlc
  • xqq/vlc
  • EmperorYP7/vlc
  • NicoLiam/vlc
  • loveleen/vlc
  • rofferom/vlc
  • rbultje/vlc
  • TheUnamed/vlc
  • pratiksharma341/vlc
  • Saurab17/vlc
  • purist.coder/vlc
  • Shuicheng/vlc
  • mdrrubel292/vlc
  • silverbleu00/vlc
  • metif12/vlc
  • asher-m/vlc
  • jeffk/vlc
  • Brandonbr1/vlc
  • beautyyuyanli/vlc
  • rego21/vlc
  • muyangren907/vlc
  • collectionbylawrencejason/vlc
  • evelez/vlc
  • GSMgeeth/vlc
  • Oneric/vlc
  • TJ5/vlc
  • XuanTung95/vlc
  • darrenjenny21/vlc
  • Trenly/vlc
  • RockyTDR/vlc
  • mjakubowski/vlc
  • caprica/vlc
  • ForteFrankie/vlc
  • seannamiller19/vlc
  • junlon2006/vlc
  • kiwiren6666/vlc
  • iuseiphonexs/vlc
  • fenngtun/vlc
  • Rajdutt999/vlc
  • typx/vlc
  • leon.vitanos/vlc
  • robertogarci0938/vlc
  • gsoc/gsoc2022/luc65r/vlc-mpd
  • skeller/vlc
  • MCJack123/vlc
  • luc65r/vlc-mpd
  • popov895/vlc
  • claucambra/vlc
  • brad/vlc
  • matthewmurua88/vlc
  • Tomas8874/vlc
  • philenotfound/vlc
  • makita-do3/vlc
  • LZXCorp/vlc
  • mar0x/vlc
  • senojetkennedy0102/vlc
  • shaneb243/vlc
  • ahmadbader/vlc
  • rajduttcse26/vlc-audio-filters
  • Juniorzito8415/vlc
  • achernyakov/vlc
  • lucasjetgroup/vlc
  • pupdoggy666/vlc
  • gmde9363/vlc
  • alexnwayne/vlc
  • bahareebrahimi781/vlc
  • hamad633666/vlc
  • umghof3112/vlc
  • joe0199771874/vlc
  • Octocats66666666/vlc
  • jjm_223/vlc
  • btech10110.19/vlc
  • sunnykfc028/vlc-audio-filters
  • loic/vlc
  • nguyenminhducmx1/vlc
  • JanekKrueger/vlc
  • bstubbington2/vlc
  • rcombs/vlc
  • Ordissimo/vlc
  • king7532/vlc
  • noobsauce101/vlc
  • schong0525/vlc
  • myQwil/vlc
  • apisbg91/vlc
  • geeboy0101017/vlc
  • kim.faughey/vlc
  • nurupo/vlc
  • yyusea/vlc
  • 0711235879.khco/vlc
  • ialo/vlc
  • iloveyeye2/vlc
  • gdtdftdqtd/vlc
  • leandroconsiglio/vlc
  • AndyHTML2012/vlc
  • ncz/vlc
  • lucenticus/vlc
  • knr1931/vlc
  • kjoonlee/vlc
  • chandrakant100/vlc-qt
  • johge42/vlc
  • polter/vlc
  • hexchain/vlc
  • Tushwrld/vlc
  • mztea928/vlc
  • jbelloncastro/vlc
  • alvinhochun/vlc
  • ghostpiratecrow/vlc
  • ujjwaltwitx/vlc
  • alexsonarin06/vlc
  • adrianbon76/vlc
  • altsod/vlc
  • damien.lucas44/vlc
  • dmytrivtaisa/vlc
  • utk202/vlc
  • aaxhrj/vlc
  • thomas.hermes/vlc
  • structurenewworldorder/vlc
  • slomo/vlc
  • wantlamy/vlc
  • musc.o3cminc/vlc
  • thebarshablog/vlc
  • kerrick/vlc
  • kratos142518/vlc
  • leogps/vlc
  • vacantron/vlc
  • luna_koly/vlc
  • Ratio2/vlc
  • anuoshemohammad/vlc
  • apsun/vlc
  • aaa1115910/vlc
  • alimotmoyo/vlc
  • Ambossmann/vlc
  • Sam-LearnsToCode/vlc
  • Chilledheart/vlc
  • Labnann/vlc
  • ktcoooot1/vlc
  • mohit-marathe/vlc
  • johnddx/vlc
  • manstabuk/vlc
  • Omar-ahmed314/vlc
  • vineethkm/vlc
  • 9Enemi86/vlc
  • radoslav.m.panteleev/vlc
  • ashishami2002/vlc
  • Corbax/vlc
  • firnasahmed/vlc
  • pelayarmalam4/vlc
  • c0ff330k/vlc
  • shikhindahikar/vlc
  • l342723951/vlc
  • christianschwandner/vlc
  • douniwan5788/vlc
  • 7damian7/vlc
  • ferdnyc/vlc
  • f.ales1/vlc
  • pandagby/vlc
  • BaaBaa/vlc
  • jewe37/vlc
  • w00drow/vlc
  • russelltg/vlc
  • ironicallygod/vlc
  • soumyaDghosh/vlc
  • linzihao1999/vlc
  • deyayush6/vlc
  • mibi88/vlc
  • newabdallah10/vlc
  • jhorbincolombia/vlc
  • rimvihaqueshupto/vlc
  • andrewkhon98/vlc
  • fab78/vlc
  • lapaz17/vlc
  • amanna13/vlc
  • mdakram28/vlc
  • 07jw1980/vlc
  • sohamgupta/vlc
  • Eson-Jia1/vlc
  • Sumou/vlc
  • vikram-kangotra/vlc
  • chalice191/vlc
  • olivercalder/vlc
  • aaasg4001/vlc
  • zipdox/vlc
  • kwizart/vlc
  • Dragon-S/vlc
  • jdemeule/vlc
  • gabriel_lt/vlc
  • locutusofborg/vlc
  • sammirata/vlc-librist
  • another/vlc
  • Benjamin_Loison/vlc
  • ahmedmoselhi/vlc
  • petergaal/vlc
  • huynhsontung/vlc
  • dariusmihut/vlc
  • tvermaashutosh/vlc
  • buti/vlc
  • Niram7777/vlc
  • rohan-here/vlc
  • balaji-sivasakthi/vlc
  • rlindner81/vlc
  • Kakadus/vlc
  • djain/vlc
  • ABBurmeister/vlc
  • craighuggins/vlc
  • orbea/vlc
  • maxos/vlc
  • aakarshmj/vlc
  • kblaschke/vlc
  • ankitm/vlc
  • advait-0/vlc
  • mohak2003/vlc
  • yselkowitz/vlc
  • AZM999/vlc-azm
  • andrey.turkin/vlc
  • Disha-Baghel/vlc
  • nowrep/vlc
  • Apeng/vlc
  • Choucroute_melba/vlc
  • autra/vlc
  • eclipseo/vlc
  • fhuber/vlc
  • olafhering/vlc
  • sdasda7777/vlc
  • 1div0/vlc
  • skosnits/vlc-extended-playlist-support
  • dnicolson/vlc
  • Timshel/vlc
  • octopols/vlc
  • MangalK/vlc
  • nima64/vlc
  • misawai/vlc
  • Alexander-Wilms/vlc
  • Maxime2/vlc-fork-for-visualizer
  • ww/vlc
  • jeske/vlc
  • sgross-emlix/vlc
  • morenonatural/vlc
  • freakingLovesVLC/vlc
  • borisgolovnev/vlc
  • mpromonet/vlc
  • diogo.simao-marques/vlc
  • masstock/vlc
  • pratikpatel8982/vlc
  • hugok79/vlc
  • longervision/vlc
  • abhiudaysurya/vlc
  • rishabhgarg/vlc
  • tumic/vlc
  • cart/vlc
  • shubham442/vlc
  • Aditya692005/vlc
  • sammirata/vlc4
  • syrykh/vlc
  • Vvorcun/macos-new-icon
  • AyaanshC/vlc
  • nasso/vlc
  • Quark/vlc
  • sebastinas/vlc
  • rhstone/vlc
  • talregev/vlc
  • Managor/vlc
403 results
Show changes
Commits on Source (22)
......@@ -39,6 +39,8 @@
#include "clock/clock.h"
#include "libvlc.h"
#define BLOCK_FLAG_CORE_PRIVATE_FILTERED (1 << BLOCK_FLAG_CORE_PRIVATE_SHIFT)
struct vlc_aout_stream
{
aout_instance_t *instance;
......@@ -59,6 +61,7 @@ struct vlc_aout_stream
struct
{
struct vlc_clock_t *clock;
uint32_t clock_id;
float rate; /**< Play-out speed rate */
vlc_tick_t resamp_start_drift; /**< Resampler drift absolute value */
int resamp_type; /**< Resampler mode (FIXME: redundant / resampling) */
......@@ -367,6 +370,7 @@ vlc_aout_stream * vlc_aout_stream_New(audio_output_t *p_aout,
stream->filter_format = stream->mixer_format = stream->input_format = *p_format;
stream->sync.clock = cfg->clock;
stream->sync.clock_id = 0;
stream->str_id = cfg->str_id;
stream->timing.rate_audio_ts = VLC_TICK_INVALID;
......@@ -570,7 +574,7 @@ static void stream_Silence (vlc_aout_stream *stream, vlc_tick_t length, vlc_tick
vlc_clock_Lock(stream->sync.clock);
const vlc_tick_t system_pts =
vlc_clock_ConvertToSystem(stream->sync.clock, system_now, pts,
stream->sync.rate);
stream->sync.rate, NULL);
vlc_clock_Unlock(stream->sync.clock);
stream->timing.played_samples += block->i_nb_samples;
aout->play(aout, block, system_pts);
......@@ -844,7 +848,7 @@ int vlc_aout_stream_Play(vlc_aout_stream *stream, block_t *block)
if (unlikely(ret == AOUT_DEC_FAILED))
goto drop; /* Pipeline is unrecoverably broken :-( */
if (stream->filters)
if (stream->filters && (block->i_flags & BLOCK_FLAG_CORE_PRIVATE_FILTERED) == 0)
{
if (atomic_load_explicit(&owner->vp.update, memory_order_relaxed))
{
......@@ -879,11 +883,20 @@ int vlc_aout_stream_Play(vlc_aout_stream *stream, block_t *block)
/* Drift correction */
vlc_tick_t system_now = vlc_tick_now();
uint32_t clock_id;
vlc_clock_Lock(stream->sync.clock);
vlc_tick_t play_date =
vlc_clock_ConvertToSystem(stream->sync.clock, system_now, block->i_pts,
stream->sync.rate);
stream->sync.rate, &clock_id);
vlc_clock_Unlock(stream->sync.clock);
if (clock_id != stream->sync.clock_id)
{
stream->sync.clock_id = clock_id;
block->i_flags |= BLOCK_FLAG_CORE_PRIVATE_FILTERED;
return stream_StartDiscontinuity(stream, block);
}
stream_Synchronize(stream, system_now, play_date, block->i_pts);
vlc_audio_meter_Process(&owner->meter, block, play_date);
......@@ -952,7 +965,7 @@ void vlc_aout_stream_ChangePause(vlc_aout_stream *stream, bool paused, vlc_tick_
vlc_tick_t play_date =
vlc_clock_ConvertToSystem(stream->sync.clock, date,
stream->timing.rate_audio_ts,
stream->sync.rate);
stream->sync.rate, NULL);
vlc_clock_Unlock(stream->sync.clock);
stream->timing.rate_system_ts = play_date;
}
......
......@@ -45,6 +45,20 @@ struct vlc_clock_listener_id
void *data;
};
struct vlc_clock_context
{
double rate;
double coeff;
vlc_tick_t offset;
uint32_t clock_id;
clock_point_t last;
clock_point_t wait_sync_ref;
struct vlc_list node;
struct vlc_list using_clocks;
};
struct vlc_clock_main_t
{
struct vlc_logger *logger;
......@@ -61,33 +75,30 @@ struct vlc_clock_main_t
* Linear function
* system = ts * coeff / rate + offset
*/
clock_point_t last;
average_t coeff_avg; /* Moving average to smooth out the instant coeff */
double rate;
double coeff;
vlc_tick_t offset;
vlc_tick_t delay;
struct vlc_clock_context *context;
vlc_tick_t pause_date;
unsigned wait_sync_ref_priority;
clock_point_t wait_sync_ref; /* When the master */
clock_point_t first_pcr;
vlc_tick_t output_dejitter; /* Delay used to absorb the output clock jitter */
vlc_tick_t input_dejitter; /* Delay used to absorb the input jitter */
struct VLC_VECTOR(vlc_clock_listener_id *) listeners;
struct vlc_list prev_contexts;
};
struct vlc_clock_ops
{
vlc_tick_t (*update)(vlc_clock_t *clock, vlc_tick_t system_now,
vlc_tick_t ts, double rate,
vlc_tick_t (*update)(vlc_clock_t *clock, struct vlc_clock_context *ctx,
vlc_tick_t system_now, vlc_tick_t ts, double rate,
unsigned frame_rate, unsigned frame_rate_base);
void (*reset)(vlc_clock_t *clock);
vlc_tick_t (*set_delay)(vlc_clock_t *clock, vlc_tick_t delay);
vlc_tick_t (*to_system)(vlc_clock_t *clock, vlc_tick_t system_now,
vlc_tick_t ts, double rate);
vlc_tick_t (*to_system)(vlc_clock_t *clock, struct vlc_clock_context *ctx,
vlc_tick_t system_now, vlc_tick_t ts, double rate);
};
struct vlc_clock_t
......@@ -100,6 +111,12 @@ struct vlc_clock_t
const struct vlc_clock_cbs *cbs;
void *cbs_data;
struct vlc_list node;
struct vlc_clock_context *context;
vlc_tick_t last_conversion;
};
vlc_clock_listener_id *
......@@ -181,25 +198,156 @@ static inline void TraceRender(struct vlc_tracer *tracer, const char *type,
VLC_TRACE_END);
}
static vlc_tick_t main_stream_to_system(vlc_clock_main_t *main_clock,
vlc_tick_t ts)
static void context_reset(struct vlc_clock_context *ctx)
{
ctx->coeff = 1.0f;
ctx->rate = 1.0f;
ctx->offset = VLC_TICK_INVALID;
ctx->wait_sync_ref = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
ctx->last = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
}
static void context_init(struct vlc_clock_context *ctx)
{
vlc_list_init(&ctx->using_clocks);
context_reset(ctx);
ctx->clock_id = 0;
}
static struct vlc_clock_context *context_new(void)
{
if (main_clock->last.system == VLC_TICK_INVALID)
struct vlc_clock_context *ctx = malloc(sizeof(*ctx));
if (unlikely(ctx == NULL))
return NULL;
context_init(ctx);
return ctx;
}
static vlc_tick_t context_stream_to_system(const struct vlc_clock_context *ctx,
vlc_tick_t ts)
{
if (ctx->last.system == VLC_TICK_INVALID)
return VLC_TICK_INVALID;
return ((vlc_tick_t) (ts * main_clock->coeff / main_clock->rate))
+ main_clock->offset;
return ((vlc_tick_t) (ts * ctx->coeff / ctx->rate)) + ctx->offset;
}
static void
vlc_clock_remove_current_context(vlc_clock_t *clock)
{
vlc_clock_main_t *main_clock = clock->owner;
struct vlc_clock_context *ctx = clock->context;
assert(ctx != NULL);
/* Remove the clock from the context using_clocks */
vlc_list_remove(&clock->node);
uint32_t clock_id = ctx->clock_id;
bool removed = false;
/* Free the context if it is not used anymore. Don't free the main context
* that should stay alive even when no clocks are referencing it. */
if (vlc_list_is_empty(&ctx->using_clocks) && ctx != main_clock->context)
{
/* Remove the context from the list of previous contexts */
vlc_list_remove(&ctx->node);
free(ctx);
removed = true;
}
clock->context = NULL;
if (main_clock->logger != NULL && clock->track_str_id != NULL
&& ctx != main_clock->context)
vlc_warning(main_clock->logger, "clock(%s): unused clock context(%u)%s",
clock->track_str_id, clock_id, removed ? " (removed)" : "");
}
static void
vlc_clock_attach_context(vlc_clock_t *clock, struct vlc_clock_context *ctx)
{
vlc_list_append(&clock->node, &ctx->using_clocks);
clock->context = ctx;
}
static void
vlc_clock_switch_context(vlc_clock_t *clock, struct vlc_clock_context *ctx)
{
vlc_clock_main_t *main_clock = clock->owner;
vlc_clock_remove_current_context(clock);
vlc_clock_attach_context(clock, ctx);
if (main_clock->logger != NULL && clock->track_str_id != NULL)
vlc_warning(main_clock->logger, "clock(%s): using clock context(%u)",
clock->track_str_id, ctx->clock_id);
}
static void
context_get_closest(vlc_clock_t *clock, struct vlc_clock_context *ctx,
vlc_tick_t system_now, vlc_tick_t ts,
struct vlc_clock_context **closest_ctx,
vlc_tick_t *closest_diff)
{
/* Find the context which has the smallest gap with the last conversion. */
vlc_tick_t converted =
clock->ops->to_system(clock, ctx, system_now, ts, 1.0);
vlc_tick_t diff = converted - clock->last_conversion;
if (diff < 0)
diff = -diff;
if (diff < *closest_diff)
{
*closest_diff = diff;
*closest_ctx = ctx;
}
}
static struct vlc_clock_context *
vlc_clock_get_context(vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t ts,
bool update)
{
vlc_clock_main_t *main_clock = clock->owner;
/* The input clock is always using the last context */
if (clock->context == NULL)
return main_clock->context;
if (vlc_list_is_empty(&main_clock->prev_contexts)
|| clock->context == main_clock->context)
return main_clock->context;
vlc_tick_t closest_diff = VLC_TICK_MAX;
struct vlc_clock_context *ctx = NULL;
/* Iterate through newer contexts, and not past ones */
for (struct vlc_clock_context *ctx_it = clock->context; ctx_it != NULL;
ctx_it = vlc_list_next_entry_or_null(&main_clock->prev_contexts, ctx_it,
struct vlc_clock_context, node))
context_get_closest(clock, ctx_it, system_now, ts, &ctx, &closest_diff);
context_get_closest(clock, main_clock->context, system_now, ts, &ctx,
&closest_diff);
if (clock->context != ctx && update)
{
/* Switch the clock context to the newer one. This means that contexts
* past the new one will never be selected again by this current clock.
* Switch context only when updating, since outputs will hold frames
* until there are displayed. */
vlc_clock_switch_context(clock, ctx);
}
return ctx;
}
static void vlc_clock_main_reset(vlc_clock_main_t *main_clock)
{
main_clock->coeff = 1.0f;
main_clock->rate = 1.0f;
AvgResetAndFill(&main_clock->coeff_avg, main_clock->coeff);
main_clock->offset = VLC_TICK_INVALID;
struct vlc_clock_context *ctx = main_clock->context;
context_reset(ctx);
AvgResetAndFill(&main_clock->coeff_avg, ctx->coeff);
main_clock->wait_sync_ref_priority = UINT_MAX;
main_clock->wait_sync_ref =
main_clock->last = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
vlc_cond_broadcast(&main_clock->cond);
}
......@@ -224,19 +372,20 @@ static inline void vlc_clock_on_update(vlc_clock_t *clock,
static void vlc_clock_master_update_coeff(
vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t ts, double rate)
vlc_clock_t *clock, struct vlc_clock_context *ctx,
vlc_tick_t system_now, vlc_tick_t ts, double rate)
{
vlc_clock_main_t *main_clock = clock->owner;
vlc_mutex_assert(&main_clock->lock);
if (main_clock->last.system != VLC_TICK_INVALID
&& ts != main_clock->last.stream)
if (ctx->last.system != VLC_TICK_INVALID
&& ts != ctx->last.stream)
{
if (rate == main_clock->rate)
if (rate == ctx->rate)
{
/* We have a reference so we can update coeff */
vlc_tick_t system_diff = system_now - main_clock->last.system;
vlc_tick_t stream_diff = ts - main_clock->last.stream;
vlc_tick_t system_diff = system_now - ctx->last.system;
vlc_tick_t stream_diff = ts - ctx->last.stream;
double instant_coeff = system_diff / (double) stream_diff * rate;
......@@ -273,35 +422,35 @@ static void vlc_clock_master_update_coeff(
else
{
AvgUpdate(&main_clock->coeff_avg, instant_coeff);
main_clock->coeff = AvgGet(&main_clock->coeff_avg);
ctx->coeff = AvgGet(&main_clock->coeff_avg);
}
}
}
else
{
main_clock->wait_sync_ref_priority = UINT_MAX;
main_clock->wait_sync_ref =
ctx->wait_sync_ref =
clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
vlc_clock_SendEvent(main_clock, discontinuity);
}
main_clock->offset =
system_now - ((vlc_tick_t) (ts * main_clock->coeff / rate));
ctx->offset = system_now - ((vlc_tick_t) (ts * ctx->coeff / rate));
if (main_clock->tracer != NULL && clock->track_str_id != NULL)
vlc_tracer_Trace(main_clock->tracer,
VLC_TRACE("type", "RENDER"),
VLC_TRACE("id", clock->track_str_id),
VLC_TRACE_TICK_NS("offset", main_clock->offset),
VLC_TRACE("coeff", main_clock->coeff),
VLC_TRACE_TICK_NS("offset", ctx->offset),
VLC_TRACE("coeff", ctx->coeff),
VLC_TRACE_END);
main_clock->rate = rate;
ctx->rate = rate;
vlc_cond_broadcast(&main_clock->cond);
}
static vlc_tick_t vlc_clock_master_update(vlc_clock_t *clock,
struct vlc_clock_context *ctx,
vlc_tick_t system_now,
vlc_tick_t ts, double rate,
unsigned frame_rate,
......@@ -312,12 +461,15 @@ static vlc_tick_t vlc_clock_master_update(vlc_clock_t *clock,
if (unlikely(ts == VLC_TICK_INVALID || system_now == VLC_TICK_INVALID))
return VLC_TICK_INVALID;
if (ctx != main_clock->context)
return VLC_TICK_INVALID; /* Don't update previous contexts */
/* If system_now is VLC_TICK_MAX, the update is forced, don't modify
* anything but only notify the new clock point. */
if (system_now != VLC_TICK_MAX)
{
vlc_clock_master_update_coeff(clock, system_now, ts, rate);
main_clock->last = clock_point_Create(system_now, ts);
vlc_clock_master_update_coeff(clock, ctx, system_now, ts, rate);
ctx->last = clock_point_Create(system_now, ts);
}
/* Fix the reported ts if both master and slaves source are delayed. This
......@@ -338,6 +490,12 @@ static void vlc_clock_master_reset(vlc_clock_t *clock)
if (main_clock->tracer != NULL && clock->track_str_id != NULL)
vlc_tracer_TraceEvent(main_clock->tracer, "RENDER", clock->track_str_id,
"reset_user");
/* Attach to the last and main context in case of reset */
struct vlc_clock_context *ctx = main_clock->context;
if (clock->context != NULL && clock->context != ctx)
vlc_clock_switch_context(clock, ctx);
vlc_clock_main_reset(main_clock);
assert(main_clock->delay <= 0);
......@@ -387,12 +545,13 @@ static vlc_tick_t vlc_clock_master_set_delay(vlc_clock_t *clock, vlc_tick_t dela
}
static vlc_tick_t
vlc_clock_monotonic_to_system(vlc_clock_t *clock, vlc_tick_t now,
vlc_tick_t ts, double rate)
vlc_clock_monotonic_to_system(vlc_clock_t *clock, struct vlc_clock_context *ctx,
vlc_tick_t now, vlc_tick_t ts, double rate)
{
vlc_clock_main_t *main_clock = clock->owner;
if (clock->priority < main_clock->wait_sync_ref_priority)
if (clock->priority < main_clock->wait_sync_ref_priority
&& ctx == main_clock->context)
{
/* XXX: This input_delay calculation is needed until we (finally) get
* ride of the input clock. This code is adapted from input_clock.c and
......@@ -416,46 +575,50 @@ vlc_clock_monotonic_to_system(vlc_clock_t *clock, vlc_tick_t now,
__MAX(input_delay, main_clock->output_dejitter);
main_clock->wait_sync_ref_priority = clock->priority;
main_clock->wait_sync_ref = clock_point_Create(now + delay, ts);
ctx->wait_sync_ref = clock_point_Create(now + delay, ts);
}
return (ts - main_clock->wait_sync_ref.stream) / rate
+ main_clock->wait_sync_ref.system;
assert(ctx->wait_sync_ref.stream != VLC_TICK_INVALID);
return (ts - ctx->wait_sync_ref.stream) / rate + ctx->wait_sync_ref.system;
}
static vlc_tick_t vlc_clock_slave_to_system(vlc_clock_t *clock,
struct vlc_clock_context *ctx,
vlc_tick_t now, vlc_tick_t ts,
double rate)
{
vlc_clock_main_t *main_clock = clock->owner;
vlc_tick_t system = main_stream_to_system(main_clock, ts);
vlc_tick_t system = context_stream_to_system(ctx, ts);
if (system == VLC_TICK_INVALID)
{
/* We don't have a master sync point, let's fallback to a monotonic ref
* point */
system = vlc_clock_monotonic_to_system(clock, now, ts, rate);
system = vlc_clock_monotonic_to_system(clock, ctx, now, ts, rate);
}
return system + (clock->delay - main_clock->delay) * rate;
}
static vlc_tick_t vlc_clock_master_to_system(vlc_clock_t *clock,
struct vlc_clock_context *ctx,
vlc_tick_t now, vlc_tick_t ts,
double rate)
{
vlc_clock_main_t *main_clock = clock->owner;
vlc_tick_t system = main_stream_to_system(main_clock, ts);
vlc_tick_t system = context_stream_to_system(ctx, ts);
if (system == VLC_TICK_INVALID)
{
/* We don't have a master sync point, let's fallback to a monotonic ref
* point */
system = vlc_clock_monotonic_to_system(clock, now, ts, rate);
system = vlc_clock_monotonic_to_system(clock, ctx, now, ts, rate);
}
return system;
}
static vlc_tick_t vlc_clock_slave_update(vlc_clock_t *clock,
struct vlc_clock_context *ctx,
vlc_tick_t system_now,
vlc_tick_t ts, double rate,
unsigned frame_rate,
......@@ -470,7 +633,7 @@ static vlc_tick_t vlc_clock_slave_update(vlc_clock_t *clock,
return VLC_TICK_MAX;
}
vlc_tick_t computed = clock->ops->to_system(clock, system_now, ts, rate);
vlc_tick_t computed = clock->ops->to_system(clock, ctx, system_now, ts, rate);
vlc_tick_t drift = computed - system_now;
vlc_clock_on_update(clock, computed, ts, drift, rate,
......@@ -481,9 +644,14 @@ static vlc_tick_t vlc_clock_slave_update(vlc_clock_t *clock,
static void vlc_clock_slave_reset(vlc_clock_t *clock)
{
vlc_clock_main_t *main_clock = clock->owner;
/* Attach to the last and main context in case of reset */
struct vlc_clock_context *ctx = main_clock->context;
if (clock->context != NULL && clock->context != ctx)
vlc_clock_switch_context(clock, ctx);
main_clock->wait_sync_ref_priority = UINT_MAX;
main_clock->wait_sync_ref =
clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
ctx->wait_sync_ref = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
vlc_clock_on_update(clock, VLC_TICK_INVALID, VLC_TICK_INVALID,
VLC_TICK_INVALID, 1.0f, 0, 0);
......@@ -548,6 +716,13 @@ vlc_clock_main_t *vlc_clock_main_New(struct vlc_logger *parent_logger, struct vl
if (main_clock == NULL)
return NULL;
struct vlc_clock_context *ctx = main_clock->context = context_new();
if (unlikely(ctx == NULL))
{
free(main_clock);
return NULL;
}
main_clock->logger = vlc_LogHeaderCreate(parent_logger, "clock");
main_clock->tracer = parent_tracer;
......@@ -556,25 +731,21 @@ vlc_clock_main_t *vlc_clock_main_New(struct vlc_logger *parent_logger, struct vl
main_clock->input_master = main_clock->master = NULL;
main_clock->rc = 1;
main_clock->coeff = 1.0f;
main_clock->rate = 1.0f;
main_clock->offset = VLC_TICK_INVALID;
main_clock->delay = 0;
main_clock->first_pcr =
clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
main_clock->wait_sync_ref_priority = UINT_MAX;
main_clock->wait_sync_ref = main_clock->last =
clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
main_clock->pause_date = VLC_TICK_INVALID;
main_clock->input_dejitter = DEFAULT_PTS_DELAY;
main_clock->output_dejitter = AOUT_MAX_PTS_ADVANCE * 2;
AvgInit(&main_clock->coeff_avg, 10);
AvgResetAndFill(&main_clock->coeff_avg, main_clock->coeff);
AvgResetAndFill(&main_clock->coeff_avg, ctx->coeff);
vlc_vector_init(&main_clock->listeners);
vlc_list_init(&main_clock->prev_contexts);
return main_clock;
}
......@@ -584,6 +755,7 @@ void vlc_clock_main_Reset(vlc_clock_main_t *main_clock)
vlc_mutex_assert(&main_clock->lock);
vlc_clock_main_reset(main_clock);
main_clock->first_pcr =
clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
}
......@@ -592,14 +764,30 @@ void vlc_clock_main_SetFirstPcr(vlc_clock_main_t *main_clock,
vlc_tick_t system_now, vlc_tick_t ts)
{
vlc_mutex_assert(&main_clock->lock);
struct vlc_clock_context *ctx = main_clock->context;
if (main_clock->first_pcr.system == VLC_TICK_INVALID)
/* Keep the old context if it allows to convert via master or monotonic */
if (main_clock->first_pcr.system != VLC_TICK_INVALID
&& (ctx->last.system != VLC_TICK_INVALID ||
ctx->wait_sync_ref.stream != VLC_TICK_INVALID)
&& !vlc_list_is_empty(&ctx->using_clocks))
{
main_clock->first_pcr = clock_point_Create(system_now, ts);
main_clock->wait_sync_ref_priority = UINT_MAX;
main_clock->wait_sync_ref =
clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
struct vlc_clock_context *newctx = context_new();
if (newctx != NULL)
{
newctx->clock_id = ctx->clock_id + 1;
vlc_list_append(&ctx->node, &main_clock->prev_contexts);
main_clock->context = ctx = newctx;
}
vlc_warning(main_clock->logger, "new clock context(%u) @%"PRId64,
ctx->clock_id, ts);
}
vlc_clock_main_reset(main_clock);
main_clock->first_pcr = clock_point_Create(system_now, ts);
main_clock->wait_sync_ref_priority = UINT_MAX;
ctx->wait_sync_ref =
clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
}
void vlc_clock_main_SetInputDejitter(vlc_clock_main_t *main_clock,
......@@ -631,20 +819,21 @@ void vlc_clock_main_ChangePause(vlc_clock_main_t *main_clock, vlc_tick_t now,
return;
}
struct vlc_clock_context *ctx = main_clock->context;
/**
* Only apply a delay if the clock has a reference point to avoid
* messing up the timings if the stream was paused then seeked
*/
const vlc_tick_t delay = now - main_clock->pause_date;
if (main_clock->last.system != VLC_TICK_INVALID)
if (ctx->last.system != VLC_TICK_INVALID)
{
main_clock->last.system += delay;
main_clock->offset += delay;
ctx->last.system += delay;
ctx->offset += delay;
}
if (main_clock->first_pcr.system != VLC_TICK_INVALID)
main_clock->first_pcr.system += delay;
if (main_clock->wait_sync_ref.system != VLC_TICK_INVALID)
main_clock->wait_sync_ref.system += delay;
if (ctx->wait_sync_ref.system != VLC_TICK_INVALID)
ctx->wait_sync_ref.system += delay;
main_clock->pause_date = VLC_TICK_INVALID;
vlc_cond_broadcast(&main_clock->cond);
}
......@@ -658,6 +847,11 @@ void vlc_clock_main_Delete(vlc_clock_main_t *main_clock)
assert(main_clock->listeners.size == 0);
vlc_vector_destroy(&main_clock->listeners);
assert(vlc_list_is_empty(&main_clock->prev_contexts));
assert(vlc_list_is_empty(&main_clock->context->using_clocks));
free(main_clock->context);
free(main_clock);
}
......@@ -676,7 +870,10 @@ vlc_tick_t vlc_clock_Update(vlc_clock_t *clock, vlc_tick_t system_now,
vlc_tick_t ts, double rate)
{
AssertLocked(clock);
return clock->ops->update(clock, system_now, ts, rate, 0, 0);
struct vlc_clock_context *ctx =
vlc_clock_get_context(clock, system_now, ts, true);
return clock->ops->update(clock, ctx, system_now, ts, rate, 0, 0);
}
vlc_tick_t vlc_clock_UpdateVideo(vlc_clock_t *clock, vlc_tick_t system_now,
......@@ -684,7 +881,11 @@ vlc_tick_t vlc_clock_UpdateVideo(vlc_clock_t *clock, vlc_tick_t system_now,
unsigned frame_rate, unsigned frame_rate_base)
{
AssertLocked(clock);
return clock->ops->update(clock, system_now, ts, rate, frame_rate, frame_rate_base);
struct vlc_clock_context *ctx =
vlc_clock_get_context(clock, system_now, ts, true);
return clock->ops->update(clock, ctx, system_now, ts, rate,
frame_rate, frame_rate_base);
}
void vlc_clock_Reset(vlc_clock_t *clock)
......@@ -701,10 +902,17 @@ vlc_tick_t vlc_clock_SetDelay(vlc_clock_t *clock, vlc_tick_t delay)
vlc_tick_t vlc_clock_ConvertToSystem(vlc_clock_t *clock,
vlc_tick_t system_now, vlc_tick_t ts,
double rate)
double rate, uint32_t *clock_id)
{
AssertLocked(clock);
return clock->ops->to_system(clock, system_now, ts, rate);
struct vlc_clock_context *ctx =
vlc_clock_get_context(clock, system_now, ts, false);
if (clock_id != NULL)
*clock_id = ctx->clock_id;
clock->last_conversion =
clock->ops->to_system(clock, ctx, system_now, ts, rate);
return clock->last_conversion;
}
static const struct vlc_clock_ops master_ops = {
......@@ -723,7 +931,7 @@ static const struct vlc_clock_ops slave_ops = {
static vlc_clock_t *vlc_clock_main_Create(vlc_clock_main_t *main_clock,
const char* track_str_id,
unsigned priority,
bool input, unsigned priority,
const struct vlc_clock_cbs *cbs,
void *cbs_data)
{
......@@ -738,6 +946,20 @@ static vlc_clock_t *vlc_clock_main_Create(vlc_clock_main_t *main_clock,
clock->cbs_data = cbs_data;
clock->priority = priority;
assert(!cbs || cbs->on_update);
clock->last_conversion = 0;
if (input)
clock->context = NULL; /* Always use the main one */
else
{
/* Attach the clock to the first context or the main one */
struct vlc_clock_context *ctx =
vlc_list_first_entry_or_null(&main_clock->prev_contexts,
struct vlc_clock_context, node);
if (likely(ctx == NULL))
ctx = main_clock->context;
vlc_clock_attach_context(clock, ctx);
}
return clock;
}
......@@ -750,7 +972,8 @@ vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock,
vlc_mutex_assert(&main_clock->lock);
/* The master has always the 0 priority */
vlc_clock_t *clock = vlc_clock_main_Create(main_clock, track_str_id, 0, cbs, cbs_data);
vlc_clock_t *clock = vlc_clock_main_Create(main_clock, track_str_id, false,
0, cbs, cbs_data);
if (!clock)
return NULL;
......@@ -770,9 +993,11 @@ vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock,
vlc_clock_t *vlc_clock_main_CreateInputMaster(vlc_clock_main_t *main_clock)
{
vlc_mutex_assert(&main_clock->lock);
struct vlc_clock_context *ctx = main_clock->context;
/* The master has always the 0 priority */
vlc_clock_t *clock = vlc_clock_main_Create(main_clock, "input", 0, NULL, NULL);
vlc_clock_t *clock = vlc_clock_main_Create(main_clock, "input", true,
0, NULL, NULL);
if (!clock)
return NULL;
......@@ -780,7 +1005,7 @@ vlc_clock_t *vlc_clock_main_CreateInputMaster(vlc_clock_main_t *main_clock)
/* Even if the master ES clock has already been created, it should not
* have updated any points */
assert(main_clock->offset == VLC_TICK_INVALID);
assert(ctx->offset == VLC_TICK_INVALID); (void) ctx;
/* Override the master ES clock if it exists */
if (main_clock->master != NULL)
......@@ -793,6 +1018,22 @@ vlc_clock_t *vlc_clock_main_CreateInputMaster(vlc_clock_main_t *main_clock)
return clock;
}
vlc_clock_t *vlc_clock_main_CreateInputSlave(vlc_clock_main_t *main_clock)
{
vlc_mutex_assert(&main_clock->lock);
/* The input has always the 0 priority */
vlc_clock_t *clock = vlc_clock_main_Create(main_clock, "input", true,
0, NULL, NULL);
if (!clock)
return NULL;
clock->ops = &slave_ops;
main_clock->rc++;
return clock;
}
vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock,
const char* track_str_id,
enum es_format_category_e cat,
......@@ -818,8 +1059,8 @@ vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock,
break;
}
vlc_clock_t *clock = vlc_clock_main_Create(main_clock, track_str_id, priority, cbs,
cbs_data);
vlc_clock_t *clock = vlc_clock_main_Create(main_clock, track_str_id, false,
priority, cbs, cbs_data);
if (!clock)
return NULL;
......@@ -839,6 +1080,10 @@ void vlc_clock_Delete(vlc_clock_t *clock)
{
vlc_clock_main_t *main_clock = clock->owner;
vlc_mutex_lock(&main_clock->lock);
if (clock->context != NULL)
vlc_clock_remove_current_context(clock);
if (clock == main_clock->input_master)
{
/* The input master must be the last clock to be deleted */
......
......@@ -170,6 +170,17 @@ vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock,
*/
vlc_clock_t *vlc_clock_main_CreateInputMaster(vlc_clock_main_t *main_clock);
/**
* This function creates a new input slave vlc_clock_t interface
*
* @warning There can be only one input, slave or master, at a given time.
*
* You must use vlc_clock_Delete to free it.
*
* @param main_clock the locked main_clock
*/
vlc_clock_t *vlc_clock_main_CreateInputSlave(vlc_clock_main_t *main_clock);
/**
* This function creates a new slave vlc_clock_t interface
*
......@@ -312,10 +323,11 @@ vlc_clock_RemoveListener(vlc_clock_t *clock, vlc_clock_listener_id *listener_id)
* This function converts a timestamp from stream to system
*
* @param clock the locked clock used by the source
* @param clock_id pointer to the clock id used for conversion. Can be NULL.
* @return the valid system time
*/
vlc_tick_t vlc_clock_ConvertToSystem(vlc_clock_t *clock,
vlc_tick_t system_now, vlc_tick_t ts,
double rate);
double rate, uint32_t *clock_id);
#endif /*CLOCK_H*/
......@@ -144,7 +144,7 @@ static vlc_tick_t ClockSystemToStream( input_clock_t *, vlc_tick_t i_system );
static vlc_tick_t ClockGetTsOffset( input_clock_t * );
static void UpdateListener( input_clock_t *cl )
static void UpdateListener( input_clock_t *cl, bool discontinuity )
{
if (cl->listener.cbs == NULL)
return;
......@@ -156,7 +156,7 @@ static void UpdateListener( input_clock_t *cl )
/* The returned drift value is ignored for now since a different
* value is computed by the input_clock. */
cl->listener.cbs->update(cl->listener.opaque, system_expected,
cl->last.stream, cl->rate);
cl->last.stream, cl->rate, discontinuity);
}
/*****************************************************************************
......@@ -224,6 +224,7 @@ vlc_tick_t input_clock_Update( input_clock_t *cl, vlc_object_t *p_log,
vlc_tick_t i_ck_stream, vlc_tick_t i_ck_system )
{
bool b_reset_reference = false;
bool discontinuity = false;
assert( i_ck_stream != VLC_TICK_INVALID && i_ck_system != VLC_TICK_INVALID );
......@@ -255,6 +256,7 @@ vlc_tick_t input_clock_Update( input_clock_t *cl, vlc_object_t *p_log,
msg_Warn(p_log, "feeding synchro with a new reference point trying"
" to recover from clock gap");
b_reset_reference= true;
discontinuity = true;
}
}
cl->b_origin_changed = false;
......@@ -313,7 +315,7 @@ vlc_tick_t input_clock_Update( input_clock_t *cl, vlc_object_t *p_log,
cl->late.i_index = ( cl->late.i_index + 1 ) % INPUT_CLOCK_LATE_COUNT;
}
UpdateListener( cl );
UpdateListener( cl, discontinuity );
return i_late;
}
......@@ -345,7 +347,7 @@ void input_clock_ChangeRate( input_clock_t *cl, float rate )
}
cl->rate = rate;
UpdateListener( cl );
UpdateListener( cl, false );
}
/*****************************************************************************
......@@ -364,7 +366,7 @@ void input_clock_ChangePause( input_clock_t *cl, bool b_paused, vlc_tick_t i_dat
cl->ref.system += i_duration;
cl->last.system += i_duration;
UpdateListener( cl );
UpdateListener( cl, false );
}
}
cl->i_pause_date = i_date;
......@@ -419,7 +421,7 @@ void input_clock_ChangeSystemOrigin( input_clock_t *cl, vlc_tick_t i_system )
cl->ref.system += i_offset;
cl->last.system += i_offset;
UpdateListener( cl );
UpdateListener( cl, false );
}
#warning "input_clock_SetJitter needs more work"
......
......@@ -49,12 +49,13 @@ struct vlc_input_clock_cbs {
* \param ck_system time reference for the buffering progress
* \param ck_stream progress of the buffering in tick
* \param rate current playback rate for the buffering
* \param discontinuity PCR discontinuity with the previous update
*
* \return how much time the playback has drifted from
* the main clock
*/
vlc_tick_t (*update)(void *opaque, vlc_tick_t ck_system,
vlc_tick_t ck_stream, double rate);
vlc_tick_t ck_stream, double rate, bool discontinuity);
/**
* Notify the listener that the buffering needed a reset.
......@@ -109,6 +110,7 @@ void input_clock_Delete(input_clock_t *);
vlc_tick_t input_clock_Update( input_clock_t *clock, vlc_object_t *p_log,
bool b_can_pace_control, bool b_buffering_allowed,
vlc_tick_t i_clock, vlc_tick_t i_system );
/**
* This function will reset the drift of a input_clock_t.
*
......
......@@ -991,7 +991,7 @@ static vlc_tick_t ModuleThread_GetDisplayDate( decoder_t *p_dec,
vlc_clock_Lock( p_owner->p_clock );
vlc_tick_t conv_ts =
vlc_clock_ConvertToSystem( p_owner->p_clock, system_now, i_ts, rate );
vlc_clock_ConvertToSystem( p_owner->p_clock, system_now, i_ts, rate, NULL );
vlc_clock_Unlock( p_owner->p_clock );
return conv_ts;
}
......
......@@ -1240,10 +1240,17 @@ static void EsOutSendEsEvent(es_out_sys_t *p_sys, es_out_id_t *es, int action,
static vlc_tick_t
ClockListenerUpdate(void *opaque, vlc_tick_t ck_system,
vlc_tick_t ck_stream, double rate)
vlc_tick_t ck_stream, double rate, bool discontinuity)
{
es_out_pgrm_t *pgrm = opaque;
vlc_clock_Lock(pgrm->clocks.input);
if (discontinuity)
{
const vlc_tick_t current_date = vlc_tick_now();
vlc_clock_main_SetFirstPcr(pgrm->clocks.main, current_date, ck_stream);
}
vlc_tick_t drift =
vlc_clock_Update(pgrm->clocks.input, ck_system, ck_stream, rate);
vlc_clock_Unlock(pgrm->clocks.input);
......@@ -1259,7 +1266,6 @@ ClockListenerReset(void *opaque)
vlc_clock_Unlock(pgrm->clocks.input);
}
static void EsOutProgramHandleClockSource(es_out_sys_t *p_sys, es_out_pgrm_t *p_pgrm)
{
input_thread_t *p_input = p_sys->p_input;
......@@ -1327,8 +1333,8 @@ static void EsOutProgramHandleClockSource(es_out_sys_t *p_sys, es_out_pgrm_t *p_
if (p_pgrm->active_clock_source != VLC_CLOCK_MASTER_INPUT)
{
vlc_clock_main_Lock(p_pgrm->clocks.main);
p_pgrm->clocks.input = vlc_clock_main_CreateSlave(
p_pgrm->clocks.main, "pcr", UNKNOWN_ES, NULL, NULL);
p_pgrm->clocks.input =
vlc_clock_main_CreateInputSlave(p_pgrm->clocks.main);
vlc_clock_main_Unlock(p_pgrm->clocks.main);
if (p_pgrm->clocks.input != NULL)
......
......@@ -85,6 +85,7 @@ typedef struct vout_thread_sys_t
vlc_clock_t *clock;
vlc_clock_listener_id *clock_listener_id;
uint32_t clock_id;
float rate;
vlc_tick_t delay;
......@@ -982,25 +983,37 @@ static picture_t *PreparePicture(vout_thread_sys_t *vout, bool reuse_decoded,
decoded = picture_fifo_Pop(sys->decoder_fifo);
if (decoded) {
if (is_late_dropped && !decoded->b_force)
const vlc_tick_t system_now = vlc_tick_now();
uint32_t clock_id;
vlc_clock_Lock(sys->clock);
const vlc_tick_t system_pts =
vlc_clock_ConvertToSystem(sys->clock, system_now,
decoded->date, sys->rate, &clock_id);
vlc_clock_Unlock(sys->clock);
if (clock_id != sys->clock_id)
{
const vlc_tick_t system_now = vlc_tick_now();
vlc_clock_Lock(sys->clock);
const vlc_tick_t system_pts =
vlc_clock_ConvertToSystem(sys->clock, system_now,
decoded->date, sys->rate);
vlc_clock_Unlock(sys->clock);
if (IsPictureLate(vout, decoded, system_now, system_pts))
{
picture_Release(decoded);
vout_statistic_AddLost(&sys->statistic, 1);
sys->clock_id = clock_id;
msg_Dbg(&vout->obj, "Using a new clock context (%u), "
"flusing static filters", clock_id);
/* Most deinterlace modules can't handle a PTS
* discontinuity, so flush them.
*
* FIXME: Pass a discontinuity flag and handle it in
* deinterlace modules. */
filter_chain_VideoFlush(sys->filter.chain_static);
}
/* A picture dropped means discontinuity for the
* filters and we need to notify eg. deinterlacer. */
filter_chain_VideoFlush(sys->filter.chain_static);
continue;
}
if (is_late_dropped && !decoded->b_force
&& IsPictureLate(vout, decoded, system_now, system_pts))
{
picture_Release(decoded);
vout_statistic_AddLost(&sys->statistic, 1);
/* A picture dropped means discontinuity for the
* filters and we need to notify eg. deinterlacer. */
filter_chain_VideoFlush(sys->filter.chain_static);
continue;
}
if (!VideoFormatIsCropArEqual(&decoded->format, &sys->filter.src_fmt))
......@@ -1152,7 +1165,7 @@ static int PrerenderPicture(vout_thread_sys_t *sys, picture_t *filtered,
vlc_clock_Lock(sys->clock);
render_subtitle_date = filtered->date <= VLC_TICK_0 ? system_now :
vlc_clock_ConvertToSystem(sys->clock, system_now, filtered->date,
sys->rate);
sys->rate, NULL);
vlc_clock_Unlock(sys->clock);
}
......@@ -1325,7 +1338,7 @@ static int RenderPicture(vout_thread_sys_t *sys, bool render_now)
const vlc_tick_t pts = todisplay->date;
vlc_clock_Lock(sys->clock);
vlc_tick_t system_pts = render_now ? system_now :
vlc_clock_ConvertToSystem(sys->clock, system_now, pts, sys->rate);
vlc_clock_ConvertToSystem(sys->clock, system_now, pts, sys->rate, NULL);
vlc_clock_Unlock(sys->clock);
const unsigned frame_rate = todisplay->format.i_frame_rate;
......@@ -1371,7 +1384,7 @@ static int RenderPicture(vout_thread_sys_t *sys, bool render_now)
{
deadline = vlc_clock_ConvertToSystem(sys->clock,
vlc_tick_now(), pts,
sys->rate);
sys->rate, NULL);
if (deadline > max_deadline)
deadline = max_deadline;
}
......@@ -1479,7 +1492,7 @@ static bool UpdateCurrentPicture(vout_thread_sys_t *sys)
vlc_clock_Lock(sys->clock);
const vlc_tick_t system_swap_current =
vlc_clock_ConvertToSystem(sys->clock, system_now,
sys->displayed.current->date, sys->rate);
sys->displayed.current->date, sys->rate, NULL);
vlc_clock_Unlock(sys->clock);
const vlc_tick_t render_delay = vout_chrono_GetHigh(&sys->chrono.render) + VOUT_MWAIT_TOLERANCE;
......@@ -1932,6 +1945,7 @@ static void vout_ReleaseDisplay(vout_thread_sys_t *vout)
sys->clock = NULL;
vlc_mutex_unlock(&sys->clock_lock);
sys->str_id = NULL;
sys->clock_id = 0;
}
void vout_StopDisplay(vout_thread_t *vout)
......@@ -2269,6 +2283,7 @@ int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input
sys->delay = 0;
sys->rate = 1.f;
sys->str_id = cfg->str_id;
sys->clock_id = 0;
vlc_mutex_lock(&sys->clock_lock);
sys->clock = cfg->clock;
......
......@@ -776,11 +776,13 @@ static size_t spu_channel_UpdateDates(struct spu_channel *channel,
assert(entry);
entry->start = vlc_clock_ConvertToSystem(channel->clock, system_now,
entry->orgstart, channel->rate);
entry->orgstart, channel->rate,
NULL);
entry->stop =
vlc_clock_ConvertToSystem(channel->clock, system_now,
entry->orgstop, channel->rate);
entry->orgstop, channel->rate,
NULL);
}
vlc_clock_Unlock(channel->clock);
......@@ -2125,10 +2127,10 @@ void spu_PutSubpicture(spu_t *spu, subpicture_t *subpic)
vlc_clock_Lock(channel->clock);
subpic->i_start =
vlc_clock_ConvertToSystem(channel->clock, system_now,
orgstart, channel->rate);
orgstart, channel->rate, NULL);
subpic->i_stop =
vlc_clock_ConvertToSystem(channel->clock, system_now,
orgstop, channel->rate);
orgstop, channel->rate, NULL);
vlc_clock_Unlock(channel->clock);
spu_channel_EarlyRemoveLate(sys, channel, system_now);
......
......@@ -398,7 +398,7 @@ static void play_scenario(libvlc_int_t *vlc, struct vlc_tracer *tracer,
vlc_clock_Lock(ctx.slave);
vlc_tick_t play_date =
vlc_clock_ConvertToSystem(ctx.slave, video_system, video_ts,
1.0f);
1.0f, NULL);
vlc_clock_Update(ctx.slave, play_date, video_ts, 1.0f);
vlc_clock_Unlock(ctx.slave);
video_system += video_increment;
......@@ -561,7 +561,7 @@ static void normal_check(const struct clock_ctx *ctx, size_t update_count,
vlc_clock_Lock(ctx->slave);
vlc_tick_t converted =
vlc_clock_ConvertToSystem(ctx->slave, expected_system_end,
stream_end, 1.0f);
stream_end, 1.0f, NULL);
vlc_clock_Unlock(ctx->slave);
assert(converted == expected_system_end);
}
......@@ -643,7 +643,7 @@ static void drift_check(const struct clock_ctx *ctx, size_t update_count,
vlc_clock_Lock(ctx->slave);
vlc_tick_t converted =
vlc_clock_ConvertToSystem(ctx->slave, expected_system_end,
stream_end, 1.0f);
stream_end, 1.0f, NULL);
vlc_clock_Unlock(ctx->slave);
assert(converted - expected_system_end == scenario->total_drift_duration);
......@@ -683,7 +683,7 @@ static void pause_common(const struct clock_ctx *ctx, vlc_clock_t *updater)
{
vlc_clock_Lock(ctx->slave);
vlc_tick_t converted = vlc_clock_ConvertToSystem(ctx->slave, system, ctx->stream_start, 1.0f);
vlc_tick_t converted = vlc_clock_ConvertToSystem(ctx->slave, system, ctx->stream_start, 1.0f, NULL);
assert(converted == system);
vlc_clock_Unlock(ctx->slave);
}
......@@ -702,7 +702,7 @@ static void pause_common(const struct clock_ctx *ctx, vlc_clock_t *updater)
system += 1;
vlc_clock_Lock(ctx->slave);
vlc_tick_t converted = vlc_clock_ConvertToSystem(ctx->slave, system, ctx->stream_start, 1.0f);
vlc_tick_t converted = vlc_clock_ConvertToSystem(ctx->slave, system, ctx->stream_start, 1.0f, NULL);
vlc_clock_Unlock(ctx->slave);
assert(converted == system_start + pause_duration);
}
......@@ -734,7 +734,7 @@ static void convert_paused_common(const struct clock_ctx *ctx, vlc_clock_t *upda
system += 1;
vlc_clock_Lock(ctx->slave);
vlc_tick_t converted = vlc_clock_ConvertToSystem(ctx->slave, system, ctx->stream_start, 1.0f);
vlc_tick_t converted = vlc_clock_ConvertToSystem(ctx->slave, system, ctx->stream_start, 1.0f, NULL);
vlc_clock_Unlock(ctx->slave);
assert(converted == system_start);
}
......@@ -749,6 +749,72 @@ static void monotonic_convert_paused_run(const struct clock_ctx *ctx)
convert_paused_common(ctx, ctx->slave);
}
static void contexts_run(const struct clock_ctx *ctx)
{
vlc_tick_t converted;
vlc_tick_t system = ctx->system_start;
vlc_tick_t stream_context0 = 1;
uint32_t clock_id;
vlc_clock_main_Lock(ctx->mainclk);
/* Initial SetFirstPcr, that will initialise the default and main context */
vlc_clock_main_SetFirstPcr(ctx->mainclk, system, stream_context0);
/* Check that the converted point is valid */
converted = vlc_clock_ConvertToSystem(ctx->slave, system, stream_context0,
1.0f, &clock_id);
assert(clock_id == 0);
assert(converted == system);
vlc_clock_Update(ctx->slave, system, stream_context0, 1.0f);
/* Discontinuity from 1us to 30 sec */
vlc_tick_t system_context0 = system;
vlc_tick_t stream_context1 = VLC_TICK_FROM_SEC(30);
system += VLC_TICK_FROM_MS(100);
vlc_clock_main_SetFirstPcr(ctx->mainclk, system, stream_context1);
/* Check that we can use the new context (or new origin) */
converted = vlc_clock_ConvertToSystem(ctx->slave, system, stream_context1,
1.0f, &clock_id);
assert(clock_id == 1);
assert(converted == system);
/* Check that we can still use the old context when converting a point
* closer to the original context */
converted = vlc_clock_ConvertToSystem(ctx->slave, system,
VLC_TICK_FROM_MS(10) + stream_context0,
1.0f, &clock_id);
assert(clock_id == 0);
assert(converted == system_context0 + VLC_TICK_FROM_MS(10));
/* Update on the newest context will cause previous contexts to be removed */
vlc_clock_Update(ctx->slave, system, stream_context1, 1.0f);
/* Discontinuity back to 1us */
system += VLC_TICK_FROM_MS(100);
vlc_tick_t stream_context2 = 1;
vlc_clock_main_SetFirstPcr(ctx->mainclk, system, stream_context2);
/* Check that we can use the new context (or new origin) */
converted = vlc_clock_ConvertToSystem(ctx->slave, system, stream_context2,
1.0f, &clock_id);
assert(clock_id == 2);
assert(converted == system);
/* Update on the newest context will cause previous contexts to be removed */
vlc_clock_Update(ctx->slave, system, stream_context2, 1.0f);
/* Check that the same conversion will output a different result now that
* the old contexts are removed */
system += VLC_TICK_FROM_MS(100);
converted = vlc_clock_ConvertToSystem(ctx->slave, system, stream_context1, 1.0f,
&clock_id);
assert(clock_id == 2);
assert(converted != system_context0);
vlc_clock_main_Unlock(ctx->mainclk);
}
#define VLC_TICK_12H VLC_TICK_FROM_SEC(12 * 60 * 60)
#define VLC_TICK_2H VLC_TICK_FROM_SEC(2 * 60 * 60)
#define DEFAULT_STREAM_INCREMENT VLC_TICK_FROM_MS(100)
......@@ -849,6 +915,13 @@ static struct clock_scenario clock_scenarios[] = {
.run = monotonic_convert_paused_run,
.disable_jitter = true,
},
{
.name = "contexts",
.desc = "switching contexts is handled",
.type = CLOCK_SCENARIO_RUN,
.run = contexts_run,
.disable_jitter = true,
},
};
int main(int argc, const char *argv[])
......
......@@ -124,7 +124,7 @@ struct report_media_attachments
size_t count;
};
#define REPORT_LIST \
#define PLAYER_REPORT_LIST \
X(input_item_t *, on_current_media_changed) \
X(enum vlc_player_state, on_state_changed) \
X(enum vlc_player_error, on_error_changed) \
......@@ -154,6 +154,14 @@ struct report_media_attachments
X(struct report_media_subitems, on_media_subitems_changed) \
X(struct report_media_attachments, on_media_attachments_added) \
struct report_aout_first_pts
{
vlc_tick_t first_pts;
};
#define REPORT_LIST \
X(vlc_tick_t, on_aout_first_pts) \
struct report_timer
{
enum
......@@ -179,12 +187,14 @@ struct timer_state
};
#define X(type, name) typedef struct VLC_VECTOR(type) vec_##name;
PLAYER_REPORT_LIST
REPORT_LIST
#undef X
#define X(type, name) vec_##name name;
struct reports
{
PLAYER_REPORT_LIST
REPORT_LIST
};
#undef X
......@@ -193,6 +203,7 @@ static inline void
reports_init(struct reports *report)
{
#define X(type, name) vlc_vector_init(&report->name);
PLAYER_REPORT_LIST
REPORT_LIST
#undef X
}
......@@ -220,6 +231,7 @@ struct media_params
vlc_tick_t pts_delay;
const char *config;
const char *discontinuities;
};
#define DEFAULT_MEDIA_PARAMS(param_length) { \
......@@ -243,10 +255,19 @@ struct media_params
.null_names = false, \
.pts_delay = DEFAULT_PTS_DELAY, \
.config = NULL, \
.discontinuities = NULL, \
}
#define DISABLE_VIDEO_OUTPUT (1 << 0)
#define DISABLE_AUDIO_OUTPUT (1 << 1)
#define DISABLE_VIDEO (1 << 2)
#define DISABLE_AUDIO (1 << 3)
#define AUDIO_INSTANT_DRAIN (1 << 4)
struct ctx
{
int flags;
libvlc_instance_t *vlc;
vlc_player_t *player;
vlc_player_listener_id *listener;
......@@ -748,6 +769,7 @@ ctx_reset(struct ctx *ctx)
#undef FOREACH_VEC
#define X(type, name) vlc_vector_clear(&ctx->report.name);
PLAYER_REPORT_LIST
REPORT_LIST
#undef X
......@@ -786,7 +808,7 @@ create_mock_media(const char *name, const struct media_params *params)
"video_frame_rate=%u;video_frame_rate_base=%u;"
"title_count=%zu;chapter_count=%zu;"
"can_seek=%d;can_pause=%d;error=%d;null_names=%d;pts_delay=%"PRId64";"
"config=%s;attachment_count=%zu",
"config=%s;discontinuities=%s;attachment_count=%zu",
params->track_count[VIDEO_ES], params->track_count[AUDIO_ES],
params->track_count[SPU_ES], params->program_count,
params->video_packetized, params->audio_packetized,
......@@ -795,7 +817,9 @@ create_mock_media(const char *name, const struct media_params *params)
params->title_count, params->chapter_count,
params->can_seek, params->can_pause, params->error, params->null_names,
params->pts_delay,
params->config ? params->config : "", params->attachment_count);
params->config ? params->config : "",
params->discontinuities ? params->discontinuities : "",
params->attachment_count);
assert(ret != -1);
input_item_t *item = input_item_New(url, name);
assert(item);
......@@ -2234,6 +2258,7 @@ static void
ctx_destroy(struct ctx *ctx)
{
#define X(type, name) vlc_vector_destroy(&ctx->report.name);
PLAYER_REPORT_LIST
REPORT_LIST
#undef X
vlc_player_RemoveListener(ctx->player, ctx->listener);
......@@ -2243,16 +2268,8 @@ REPORT_LIST
libvlc_release(ctx->vlc);
}
enum ctx_flags
{
DISABLE_VIDEO_OUTPUT = 1 << 0,
DISABLE_AUDIO_OUTPUT = 1 << 1,
DISABLE_VIDEO = 1 << 2,
DISABLE_AUDIO = 1 << 3,
};
static void
ctx_init(struct ctx *ctx, enum ctx_flags flags)
ctx_init(struct ctx *ctx, int flags)
{
const char * argv[] = {
"-v",
......@@ -2277,11 +2294,12 @@ ctx_init(struct ctx *ctx, enum ctx_flags flags)
#define X(type, name) .name = player_##name,
static const struct vlc_player_cbs cbs = {
REPORT_LIST
PLAYER_REPORT_LIST
};
#undef X
*ctx = (struct ctx) {
.flags = flags,
.vlc = vlc,
.next_medias = VLC_VECTOR_INITIALIZER,
.added_medias = VLC_VECTOR_INITIALIZER,
......@@ -2297,6 +2315,11 @@ REPORT_LIST
int ret = var_SetString(vlc->p_libvlc_int, "window", "wdummy");
assert(ret == VLC_SUCCESS);
ret = var_Create(vlc->p_libvlc_int, "test-ctx", VLC_VAR_ADDRESS);
assert(ret == VLC_SUCCESS);
ret = var_SetAddress(vlc->p_libvlc_int, "test-ctx", ctx);
assert(ret == VLC_SUCCESS);
ctx->player = vlc_player_New(VLC_OBJECT(vlc->p_libvlc_int),
VLC_PLAYER_LOCK_NORMAL);
assert(ctx->player);
......@@ -2964,6 +2987,32 @@ test_attachments(struct ctx *ctx)
test_end(ctx);
}
static void
test_clock_discontinuities(struct ctx *ctx)
{
test_log("discontinuities\n");
vlc_player_t *player = ctx->player;
struct media_params params = DEFAULT_MEDIA_PARAMS(VLC_TICK_FROM_SEC(20));
params.pts_delay = VLC_TICK_FROM_MS(50);
params.discontinuities = "(400000,2)(400000,2500000)(3000000,10000000)";
player_set_next_mock_media(ctx, "media1", &params);
player_start(ctx);
vec_on_aout_first_pts *vec = &ctx->report.on_aout_first_pts;
while (vec->size != 4)
vlc_player_CondWait(player, &ctx->wait);
assert(vec->data[0] == VLC_TICK_0); /* Initial PTS */
assert(vec->data[1] == 2); /* 1st discontinuity */
assert(vec->data[2] == 2500000); /* 2nd discontinuity */
assert(vec->data[3] == 10000000); /* 3rd discontinuity */
test_end(ctx);
}
static void
test_audio_loudness_meter_cb(vlc_tick_t date, double momentary_loudness,
void *data)
......@@ -3122,6 +3171,12 @@ main(void)
test_delete_while_playback(VLC_OBJECT(ctx.vlc->p_libvlc_int), false);
ctx_destroy(&ctx);
/* Test with instantaneous audio drain */
ctx_init(&ctx, AUDIO_INSTANT_DRAIN);
test_clock_discontinuities(&ctx);
ctx_destroy(&ctx);
/* Test with --no-video */
ctx_init(&ctx, DISABLE_VIDEO);
test_es_selection_override(&ctx);
......@@ -3144,6 +3199,8 @@ struct aout_sys
vlc_tick_t first_pts;
vlc_tick_t first_play_date;
vlc_tick_t pos;
struct ctx *ctx;
};
static void aout_Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
......@@ -3155,6 +3212,9 @@ static void aout_Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
assert(sys->first_pts == VLC_TICK_INVALID);
sys->first_play_date = date;
sys->first_pts = block->i_pts;
struct ctx *ctx = sys->ctx;
VEC_PUSH(on_aout_first_pts, sys->first_pts);
}
aout_TimingReport(aout, sys->first_play_date + sys->pos - VLC_TICK_0,
......@@ -3170,6 +3230,11 @@ static void aout_Flush(audio_output_t *aout)
sys->first_pts = sys->first_play_date = VLC_TICK_INVALID;
}
static void aout_InstantDrain(audio_output_t *aout)
{
aout_DrainedReport(aout);
}
static int aout_Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
{
(void) aout;
......@@ -3197,6 +3262,13 @@ static int aout_Open(vlc_object_t *obj)
struct aout_sys *sys = aout->sys = malloc(sizeof(*sys));
assert(sys != NULL);
sys->ctx = var_InheritAddress(aout, "test-ctx");
assert(sys->ctx != NULL);
if (sys->ctx->flags & AUDIO_INSTANT_DRAIN)
aout->drain = aout_InstantDrain;
aout_Flush(aout);
return VLC_SUCCESS;
......