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 (78)
Showing
with 866 additions and 298 deletions
......@@ -551,6 +551,32 @@ static webvtt_dom_node_t * webvtt_domnode_getFirstChild( webvtt_dom_node_t *p_no
}
#define webvtt_domnode_getFirstChild(a) webvtt_domnode_getFirstChild((webvtt_dom_node_t *)a)
static void webvtt_domnode_mergeCues( webvtt_dom_cue_t *p_dst, webvtt_dom_cue_t *p_src )
{
p_dst->i_nzstop = p_src->i_nzstop;
/* needs more work */
webvtt_dom_cue_Delete( p_src );
}
static webvtt_dom_cue_t * webvtt_domnode_getCue( webvtt_dom_node_t *p_node,
vlc_tick_t i_nzstart,
const char *psz_id )
{
for( ; p_node ; p_node = p_node->p_next )
{
if( p_node->type != NODE_CUE )
continue;
webvtt_dom_cue_t *p_cue = (webvtt_dom_cue_t *) p_node;
if( p_cue->i_nzstart != i_nzstart )
continue;
if( !psz_id != !p_cue->psz_id ||
(psz_id && strcmp(psz_id, p_cue->psz_id)) )
continue;
return p_cue;
}
return NULL;
}
#ifdef HAVE_CSS
static vlc_tick_t webvtt_domnode_GetPlaybackTime( const webvtt_dom_node_t *p_node, bool b_end )
{
......@@ -1932,15 +1958,26 @@ static int ProcessISOBMFF( decoder_t *p_dec,
webvtt_region_t *p_region = webvtt_region_GetByID( p_sys,
p_cue->settings.psz_region );
if( p_region )
webvtt_dom_cue_t *p_existingcue = webvtt_domnode_getCue( p_region ? p_region->p_child
: p_sys->p_root->p_child,
p_cue->i_nzstart,
p_cue->psz_id );
if( p_existingcue )
{
webvtt_region_AddCue( p_region, p_cue );
assert( p_region->p_child );
webvtt_domnode_mergeCues( p_existingcue, p_cue );
}
else
{
webvtt_domnode_AppendLast( &p_sys->p_root->p_child, p_cue );
p_cue->p_parent = (webvtt_dom_node_t *) p_sys->p_root;
if( p_region )
{
webvtt_region_AddCue( p_region, p_cue );
assert( p_region->p_child );
}
else
{
webvtt_domnode_AppendLast( &p_sys->p_root->p_child, p_cue );
p_cue->p_parent = (webvtt_dom_node_t *) p_sys->p_root;
}
}
}
}
......
......@@ -512,6 +512,8 @@ adaptive_test_SOURCES = \
demux/adaptive/test/playlist/SegmentTimeline.cpp \
demux/adaptive/test/playlist/TemplatedUri.cpp \
demux/adaptive/test/plumbing/CommandsQueue.cpp \
demux/adaptive/test/plumbing/FakeEsOut.cpp \
demux/adaptive/test/SegmentTracker.cpp \
demux/adaptive/test/test.cpp \
demux/adaptive/test/test.hpp
adaptive_test_LDADD = libvlc_adaptive.la
......
......@@ -73,8 +73,6 @@ PlaylistManager::PlaylistManager( demux_t *p_demux_,
b_canceled = false;
b_preparsing = false;
nextPlaylistupdate = 0;
demux.i_nzpcr = VLC_TICK_INVALID;
demux.i_firstpcr = VLC_TICK_INVALID;
demux.pcr_syncpoint = TimestampSynchronizationPoint::RandomAccess;
vlc_mutex_init(&demux.lock);
vlc_cond_init(&demux.cond);
......@@ -82,6 +80,7 @@ PlaylistManager::PlaylistManager( demux_t *p_demux_,
cached.b_live = false;
cached.f_position = 0.0;
cached.i_time = VLC_TICK_INVALID;
cached.i_normaltime = VLC_TICK_INVALID;
cached.playlistStart = 0;
cached.playlistEnd = 0;
cached.playlistLength = 0;
......@@ -123,12 +122,13 @@ bool PlaylistManager::setupPeriod()
if(set && streamFactory)
{
SegmentTracker *tracker = new SegmentTracker(resources, logic,
bufferingLogic, set);
bufferingLogic, set,
&synchronizationReferences);
if(!tracker)
continue;
AbstractStream *st = streamFactory->create(p_demux, set->getStreamFormat(),
tracker, resources->getConnManager());
tracker);
if(!st)
{
delete tracker;
......@@ -217,7 +217,7 @@ static bool streamCompare(const PrioritizedAbstractStream &a, const Prioritized
return false;
}
AbstractStream::BufferingStatus PlaylistManager::bufferize(vlc_tick_t i_nzdeadline,
AbstractStream::BufferingStatus PlaylistManager::bufferize(Times deadline,
vlc_tick_t i_min_buffering,
vlc_tick_t i_max_buffering,
vlc_tick_t i_target_buffering)
......@@ -231,8 +231,11 @@ AbstractStream::BufferingStatus PlaylistManager::bufferize(vlc_tick_t i_nzdeadli
{
PrioritizedAbstractStream &p = *it;
p.st = stream;
p.status = p.st->getLastBufferStatus();
p.demuxed_amount = p.st->getDemuxedAmount(i_nzdeadline);
p.status = p.st->getBufferAndStatus(deadline, i_min_buffering, i_max_buffering, &p.demuxed_amount);
p.demuxed_amount = p.st->getDemuxedAmount(deadline).continuous;
vlc_tick_t mediaAmount;
if(p.st->getMediaAdvanceAmount(&mediaAmount) && mediaAmount > p.demuxed_amount)
p.demuxed_amount = mediaAmount;
++it;
}
std::sort(prioritized_streams.begin(), prioritized_streams.end(), streamCompare);
......@@ -255,7 +258,7 @@ AbstractStream::BufferingStatus PlaylistManager::bufferize(vlc_tick_t i_nzdeadli
/* initial */
}
AbstractStream::BufferingStatus i_ret = st->bufferize(i_nzdeadline,
AbstractStream::BufferingStatus i_ret = st->bufferize(deadline,
i_min_buffering,
i_max_buffering,
i_target_buffering,
......@@ -272,55 +275,61 @@ AbstractStream::BufferingStatus PlaylistManager::bufferize(vlc_tick_t i_nzdeadli
}
vlc_mutex_lock(&demux.lock);
if(demux.i_nzpcr == VLC_TICK_INVALID &&
if(demux.times.continuous == VLC_TICK_INVALID &&
/* don't wait minbuffer on simple discontinuity or restart */
(demux.pcr_syncpoint == TimestampSynchronizationPoint::Discontinuity ||
/* prevents starting before buffering is reached */
i_return != AbstractStream::BufferingStatus::Lessthanmin ))
{
demux.i_nzpcr = getFirstDTS();
demux.times = getFirstTimes();
}
vlc_mutex_unlock(&demux.lock);
return i_return;
}
AbstractStream::Status PlaylistManager::dequeue(vlc_tick_t i_floor, vlc_tick_t *pi_nzbarrier)
AbstractStream::Status PlaylistManager::dequeue(Times floor, Times *barrier)
{
AbstractStream::Status i_return = AbstractStream::Status::Eof;
const vlc_tick_t i_nzdeadline = *pi_nzbarrier;
const Times deadline = *barrier;
for(AbstractStream *st : streams)
{
vlc_tick_t i_pcr;
AbstractStream::Status i_ret = st->dequeue(i_nzdeadline, &i_pcr);
Times pcr;
AbstractStream::Status i_ret = st->dequeue(deadline, &pcr);
if( i_ret > i_return )
i_return = i_ret;
if( i_pcr > i_floor )
*pi_nzbarrier = std::min( *pi_nzbarrier, i_pcr - VLC_TICK_0 );
if( pcr.continuous > floor.continuous )
{
if( barrier->continuous > pcr.continuous )
*barrier = pcr;
}
}
return i_return;
}
vlc_tick_t PlaylistManager::getResumeTime() const
StreamPosition PlaylistManager::getResumePosition() const
{
vlc_mutex_locker locker(&demux.lock);
return demux.i_nzpcr;
StreamPosition pos;
pos.times = demux.times;
return pos;
}
vlc_tick_t PlaylistManager::getFirstDTS() const
Times PlaylistManager::getFirstTimes() const
{
vlc_tick_t mindts = VLC_TICK_INVALID;
Times mindts;
for(const AbstractStream *stream : streams)
{
const vlc_tick_t dts = stream->getFirstDTS();
if(mindts == VLC_TICK_INVALID)
const Times dts = stream->getFirstTimes();
if(mindts.continuous == VLC_TICK_INVALID)
mindts = dts;
else if(dts.continuous != VLC_TICK_INVALID &&
dts.continuous < mindts.continuous)
mindts = dts;
else if(dts != VLC_TICK_INVALID)
mindts = std::min(mindts, dts);
}
return mindts;
}
......@@ -337,10 +346,17 @@ unsigned PlaylistManager::getActiveStreamsCount() const
return count;
}
bool PlaylistManager::setPosition(vlc_tick_t time)
bool PlaylistManager::setPosition(vlc_tick_t mediatime, double pos, bool accurate)
{
bool ret = true;
bool hasValidStream = false;
StreamPosition streampos;
streampos.times = demux.firsttimes;
if(streampos.times.continuous != VLC_TICK_INVALID)
streampos.times.offsetBy(mediatime - streampos.times.segment.media);
else
streampos.times.segment.media = mediatime;
streampos.pos = pos;
for(int real = 0; real < 2; real++)
{
/* Always probe if we can seek first */
......@@ -349,7 +365,7 @@ bool PlaylistManager::setPosition(vlc_tick_t time)
if(st->isValid() && !st->isDisabled())
{
hasValidStream = true;
ret &= st->setPosition(time, !real);
ret &= st->setPosition(streampos, !real);
}
}
if(!ret)
......@@ -360,6 +376,15 @@ bool PlaylistManager::setPosition(vlc_tick_t time)
msg_Warn(p_demux, "there is no valid streams");
ret = false;
}
if(accurate && ret && streampos.times.continuous >= VLC_TICK_0)
{
es_out_Control(p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
streampos.times.continuous);
SeekDebug(msg_Dbg(p_demux,"ES_OUT_SET_NEXT_DISPLAY_TIME to %" PRId64,
streampos.times.continuous));
}
return ret;
}
......@@ -393,10 +418,10 @@ bool PlaylistManager::updatePlaylist()
return true;
}
vlc_tick_t PlaylistManager::getCurrentDemuxTime() const
Times PlaylistManager::getTimes(bool b_first) const
{
vlc_mutex_locker locker(&demux.lock);
return demux.i_nzpcr;
return b_first ? demux.firsttimes : demux.times;
}
vlc_tick_t PlaylistManager::getMinAheadTime() const
......@@ -416,7 +441,7 @@ vlc_tick_t PlaylistManager::getMinAheadTime() const
bool PlaylistManager::reactivateStream(AbstractStream *stream)
{
return stream->reactivate(getResumeTime());
return stream->reactivate(getResumePosition());
}
#define DEMUX_INCREMENT VLC_TICK_FROM_MS(50)
......@@ -431,7 +456,7 @@ int PlaylistManager::demux_callback(demux_t *p_demux)
int PlaylistManager::doDemux(vlc_tick_t increment)
{
vlc_mutex_lock(&demux.lock);
if(demux.i_nzpcr == VLC_TICK_INVALID)
if(demux.times.continuous == VLC_TICK_INVALID)
{
bool b_dead = true;
bool b_all_disabled = true;
......@@ -447,13 +472,20 @@ int PlaylistManager::doDemux(vlc_tick_t increment)
return (b_dead || b_all_disabled) ? VLC_DEMUXER_EOF : VLC_DEMUXER_SUCCESS;
}
if(demux.i_firstpcr == VLC_TICK_INVALID)
demux.i_firstpcr = demux.i_nzpcr;
Times barrier = demux.times;
barrier.offsetBy(increment);
vlc_tick_t i_nzbarrier = demux.i_nzpcr + increment;
vlc_mutex_unlock(&demux.lock);
AbstractStream::Status status = dequeue(demux.i_nzpcr, &i_nzbarrier);
AbstractStream::Status status = dequeue(demux.times, &barrier);
vlc_mutex_lock(&demux.lock);
if(demux.firsttimes.continuous == VLC_TICK_INVALID && barrier.continuous != VLC_TICK_INVALID)
{
demux.firsttimes = barrier;
assert(barrier.segment.media != VLC_TICK_INVALID);
}
vlc_mutex_unlock(&demux.lock);
updateControlsPosition();
......@@ -473,8 +505,8 @@ int PlaylistManager::doDemux(vlc_tick_t increment)
if (!setupPeriod())
return VLC_DEMUXER_EOF;
demux.i_nzpcr = VLC_TICK_INVALID;
demux.i_firstpcr = VLC_TICK_INVALID;
demux.times = Times();
demux.firsttimes = Times();
es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
setBufferingRunState(true);
......@@ -488,18 +520,18 @@ int PlaylistManager::doDemux(vlc_tick_t increment)
break;
case AbstractStream::Status::Discontinuity:
vlc_mutex_lock(&demux.lock);
demux.i_nzpcr = VLC_TICK_INVALID;
demux.i_firstpcr = VLC_TICK_INVALID;
demux.times = Times();
demux.firsttimes = Times();
demux.pcr_syncpoint = TimestampSynchronizationPoint::Discontinuity;
es_out_Control(p_demux->out, ES_OUT_RESET_PCR);
vlc_mutex_unlock(&demux.lock);
break;
case AbstractStream::Status::Demuxed:
vlc_mutex_lock(&demux.lock);
if( demux.i_nzpcr != VLC_TICK_INVALID && i_nzbarrier != demux.i_nzpcr )
if( demux.times.continuous != VLC_TICK_INVALID && barrier.continuous != demux.times.continuous )
{
demux.i_nzpcr = i_nzbarrier;
vlc_tick_t pcr = VLC_TICK_0 + std::max(INT64_C(0), demux.i_nzpcr - VLC_TICK_FROM_MS(100));
demux.times = barrier;
vlc_tick_t pcr = VLC_TICK_0 + std::max(INT64_C(0), demux.times.continuous - VLC_TICK_FROM_MS(100));
es_out_Control(p_demux->out, ES_OUT_SET_GROUP_PCR, 0, pcr);
}
vlc_mutex_unlock(&demux.lock);
......@@ -540,7 +572,7 @@ int PlaylistManager::doControl(int i_query, va_list args)
if(playlist->isLive())
{
vlc_tick_t now = vlc_tick_now();
demux.i_nzpcr = VLC_TICK_INVALID;
demux.times = Times();
cached.lastupdate = 0;
if(b_pause)
{
......@@ -568,6 +600,15 @@ int PlaylistManager::doControl(int i_query, va_list args)
break;
}
case DEMUX_GET_NORMAL_TIME:
{
vlc_mutex_locker locker(&cached.lock);
if( cached.i_normaltime == VLC_TICK_INVALID )
return VLC_TICK_INVALID;
*(va_arg (args, vlc_tick_t *)) = cached.i_normaltime;
break;
}
case DEMUX_GET_LENGTH:
{
vlc_mutex_locker locker(&cached.lock);
......@@ -598,20 +639,24 @@ int PlaylistManager::doControl(int i_query, va_list args)
}
double pos = va_arg(args, double);
bool accurate = va_arg(args, int);
vlc_tick_t seekTime = cached.playlistStart + cached.playlistLength * pos;
SeekDebug(msg_Dbg(p_demux, "Seek %f to %ld plstart %ld duration %ld",
pos, seekTime, cached.playlistEnd, cached.playlistLength));
if(!setPosition(seekTime))
if(!setPosition(seekTime, pos, accurate))
{
setBufferingRunState(true);
return VLC_EGENERIC;
}
demux.pcr_syncpoint = TimestampSynchronizationPoint::RandomAccess;
demux.i_nzpcr = VLC_TICK_INVALID;
demux.times = Times();
demux.firsttimes = Times();
cached.lastupdate = 0;
cached.i_normaltime = VLC_TICK_INVALID;
cached.i_time = VLC_TICK_INVALID;
setBufferingRunState(true);
break;
}
......@@ -621,7 +666,8 @@ int PlaylistManager::doControl(int i_query, va_list args)
setBufferingRunState(false); /* stop downloader first */
vlc_tick_t time = va_arg(args, vlc_tick_t);
if(!setPosition(time))
bool accurate = va_arg(args, int);
if(!setPosition(time, -1, accurate))
{
setBufferingRunState(true);
return VLC_EGENERIC;
......@@ -629,8 +675,11 @@ int PlaylistManager::doControl(int i_query, va_list args)
vlc_mutex_locker locker(&cached.lock);
demux.pcr_syncpoint = TimestampSynchronizationPoint::RandomAccess;
demux.i_nzpcr = VLC_TICK_INVALID;
demux.times = Times();
demux.firsttimes = Times();
cached.lastupdate = 0;
cached.i_normaltime = VLC_TICK_INVALID;
cached.i_time = VLC_TICK_INVALID;
setBufferingRunState(true);
break;
}
......@@ -674,10 +723,10 @@ void PlaylistManager::Run()
}
vlc_mutex_lock(&demux.lock);
vlc_tick_t i_nzpcr = demux.i_nzpcr;
Times pcr = demux.times;
vlc_mutex_unlock(&demux.lock);
AbstractStream::BufferingStatus i_return = bufferize(i_nzpcr, i_min_buffering,
AbstractStream::BufferingStatus i_return = bufferize(pcr, i_min_buffering,
i_max_buffering, i_target_buffering);
if(i_return != AbstractStream::BufferingStatus::Lessthanmin)
......@@ -721,15 +770,12 @@ void PlaylistManager::updateControlsPosition()
return;
cached.lastupdate = now;
vlc_tick_t rapPlaylistStart = 0;
vlc_tick_t rapDemuxStart = 0;
for(AbstractStream* st : streams)
{
if(st->isValid() && !st->isDisabled() && st->isSelected())
{
if(st->getMediaPlaybackTimes(&cached.playlistStart, &cached.playlistEnd,
&cached.playlistLength,
&rapPlaylistStart, &rapDemuxStart))
&cached.playlistLength))
break;
}
}
......@@ -748,19 +794,20 @@ void PlaylistManager::updateControlsPosition()
* All seeks need to be done in playlist time !
*/
vlc_tick_t currentDemuxTime = getCurrentDemuxTime();
Times currentTimes = getTimes();
Times startTimes = getTimes(true);
cached.b_live = playlist->isLive();
SeekDebug(msg_Dbg(p_demux, "playlist Start/End %ld/%ld len %ld"
"rap pl/demux (%ld/%ld)",
cached.playlistStart, cached.playlistEnd, cached.playlistEnd,
rapPlaylistStart, rapDemuxStart));
startTimes.segment.media, startTimes.segment.demux));
if(cached.b_live)
{
/* Special case for live until we can provide relative start to fully match
the above description */
cached.i_time = currentDemuxTime;
cached.i_time = currentTimes.segment.media;
if(cached.playlistStart != cached.playlistEnd)
{
......@@ -770,11 +817,11 @@ void PlaylistManager::updateControlsPosition()
cached.playlistStart = cached.playlistEnd - cached.playlistLength;
}
}
const vlc_tick_t currentTime = getCurrentDemuxTime();
if(currentTime > cached.playlistStart &&
currentTime <= cached.playlistEnd && cached.playlistLength)
if(cached.i_time > VLC_TICK_0 + cached.playlistStart &&
cached.i_time <= VLC_TICK_0 + cached.playlistEnd && cached.playlistLength)
{
cached.f_position = ((double)(currentTime - cached.playlistStart)) / cached.playlistLength;
cached.f_position = ((double)(cached.i_time - VLC_TICK_0 - cached.playlistStart)) / cached.playlistLength;
}
else
{
......@@ -783,17 +830,16 @@ void PlaylistManager::updateControlsPosition()
}
else
{
cached.i_normaltime = startTimes.continuous;
cached.i_normaltime += VLC_TICK_0 + cached.playlistStart - startTimes.segment.media;
if(playlist->duration.Get() > cached.playlistLength)
cached.playlistLength = playlist->duration.Get();
if(cached.playlistLength && currentDemuxTime)
if(cached.playlistLength && currentTimes.segment.media != VLC_TICK_INVALID)
{
/* convert to playlist time */
vlc_tick_t rapRelOffset = currentDemuxTime - rapDemuxStart; /* offset from start/seek */
vlc_tick_t absPlaylistTime = rapPlaylistStart + rapRelOffset; /* converted as abs playlist time */
vlc_tick_t relMediaTime = absPlaylistTime - cached.playlistStart; /* elapsed, in playlist time */
cached.i_time = absPlaylistTime;
cached.f_position = (double) relMediaTime / cached.playlistLength;
cached.i_time = currentTimes.segment.media;
cached.f_position = (double) (cached.i_time - VLC_TICK_0 - cached.playlistStart) / cached.playlistLength;
}
else
{
......@@ -801,8 +847,9 @@ void PlaylistManager::updateControlsPosition()
}
}
SeekDebug(msg_Dbg(p_demux, "cached.i_time (%ld) cur %ld rap start (pl %ld/dmx %ld)",
cached.i_time, currentDemuxTime, rapPlaylistStart, rapDemuxStart));
SeekDebug(msg_Dbg(p_demux, "cached.i_time (%ld) cur %ld rap start (pl %ld/dmx %ld) pos %f",
cached.i_time, currentTimes.continuous, startTimes.segment.media,
startTimes.segment.demux, cached.f_position));
}
AbstractAdaptationLogic *PlaylistManager::createLogic(AbstractAdaptationLogic::LogicType type, AbstractConnectionManager *conn)
......
......@@ -44,6 +44,8 @@ namespace adaptive
using namespace playlist;
using namespace logic;
using StreamPosition = AbstractStream::StreamPosition;
class PlaylistManager
{
public:
......@@ -59,9 +61,9 @@ namespace adaptive
bool started() const;
void stop();
AbstractStream::BufferingStatus bufferize(vlc_tick_t, vlc_tick_t,
AbstractStream::BufferingStatus bufferize(Times, vlc_tick_t,
vlc_tick_t, vlc_tick_t);
AbstractStream::Status dequeue(vlc_tick_t, vlc_tick_t *);
AbstractStream::Status dequeue(Times, Times *);
virtual bool needsUpdate() const;
virtual bool updatePlaylist();
......@@ -77,12 +79,12 @@ namespace adaptive
virtual int doDemux(vlc_tick_t);
void setLivePause(bool);
virtual bool setPosition(vlc_tick_t);
vlc_tick_t getResumeTime() const;
vlc_tick_t getFirstDTS() const;
virtual bool setPosition(vlc_tick_t, double pos = -1, bool accurate = false);
StreamPosition getResumePosition() const;
Times getFirstTimes() const;
unsigned getActiveStreamsCount() const;
vlc_tick_t getCurrentDemuxTime() const;
Times getTimes(bool = false) const;
vlc_tick_t getMinAheadTime() const;
virtual bool reactivateStream(AbstractStream *);
......@@ -116,8 +118,7 @@ namespace adaptive
struct
{
TimestampSynchronizationPoint pcr_syncpoint;
vlc_tick_t i_nzpcr;
vlc_tick_t i_firstpcr;
Times times, firsttimes;
mutable vlc_mutex_t lock;
vlc_cond_t cond;
} demux;
......@@ -131,6 +132,7 @@ namespace adaptive
{
bool b_live;
vlc_tick_t i_time;
vlc_tick_t i_normaltime;
double f_position;
mutable vlc_mutex_t lock;
vlc_tick_t playlistStart;
......@@ -139,6 +141,8 @@ namespace adaptive
time_t lastupdate;
} cached;
SynchronizationReferences synchronizationReferences;
private:
void setBufferingRunState(bool);
void Run();
......
......@@ -23,6 +23,7 @@
#endif
#include "SegmentTracker.hpp"
#include "SharedResources.hpp"
#include "playlist/BasePlaylist.hpp"
#include "playlist/BaseRepresentation.h"
#include "playlist/BaseAdaptationSet.h"
......@@ -53,9 +54,15 @@ TrackerEvent::Type TrackerEvent::getType() const
return type;
}
DiscontinuityEvent::DiscontinuityEvent()
DiscontinuityEvent::DiscontinuityEvent(uint64_t d)
: TrackerEvent(Type::Discontinuity)
{
discontinuitySequenceNumber = d;
}
SegmentGapEvent::SegmentGapEvent()
: TrackerEvent(Type::SegmentGap)
{
}
......@@ -67,17 +74,30 @@ RepresentationSwitchEvent::RepresentationSwitchEvent(BaseRepresentation *prev,
this->next = next;
}
RepresentationUpdatedEvent::RepresentationUpdatedEvent(BaseRepresentation * rep)
: TrackerEvent(Type::RepresentationUpdated)
{
this->rep = rep;
}
RepresentationUpdateFailedEvent::RepresentationUpdateFailedEvent(BaseRepresentation * rep)
: TrackerEvent(Type::RepresentationUpdateFailed)
{
this->rep = rep;
}
FormatChangedEvent::FormatChangedEvent(const StreamFormat *f)
: TrackerEvent(Type::FormatChange)
{
this->format = f;
}
SegmentChangedEvent::SegmentChangedEvent(const ID &id, vlc_tick_t starttime,
SegmentChangedEvent::SegmentChangedEvent(const ID &id, uint64_t sequence, vlc_tick_t starttime,
vlc_tick_t duration, vlc_tick_t displaytime)
: TrackerEvent(Type::SegmentChange)
{
this->id = &id;
this->sequence = sequence;
this->duration = duration;
this->starttime = starttime;
this->displaytime = displaytime;
......@@ -102,16 +122,17 @@ BufferingLevelChangedEvent::BufferingLevelChangedEvent(const ID &id,
this->target = target;
}
PositionChangedEvent::PositionChangedEvent()
PositionChangedEvent::PositionChangedEvent(vlc_tick_t r)
: TrackerEvent(Type::PositionChange)
{
resumeTime = r;
}
SegmentTracker::SegmentTracker(SharedResources *res,
AbstractAdaptationLogic *logic_,
const AbstractBufferingLogic *bl,
BaseAdaptationSet *adaptSet)
BaseAdaptationSet *adaptSet,
SynchronizationReferences *refs)
{
resources = res;
first = true;
......@@ -119,6 +140,7 @@ SegmentTracker::SegmentTracker(SharedResources *res,
bufferingLogic = bl;
setAdaptationLogic(logic_);
adaptationSet = adaptSet;
synchronizationReferences = refs;
format = StreamFormat::Type::Unknown;
}
......@@ -184,21 +206,6 @@ void SegmentTracker::setAdaptationLogic(AbstractAdaptationLogic *logic_)
registerListener(logic);
}
StreamFormat SegmentTracker::getCurrentFormat() const
{
BaseRepresentation *rep = current.rep;
if(!rep)
rep = logic->getNextRepresentation(adaptationSet, nullptr);
if(rep)
{
/* Ensure ephemere content is updated/loaded */
if(rep->needsUpdate(next.number))
(void) rep->runLocalUpdates(resources);
return rep->getStreamFormat();
}
return StreamFormat();
}
void SegmentTracker::getCodecsDesc(CodecDescriptionList *descs) const
{
BaseRepresentation *rep = current.rep;
......@@ -243,14 +250,11 @@ bool SegmentTracker::ChunkEntry::isValid() const
}
SegmentTracker::ChunkEntry
SegmentTracker::prepareChunk(bool switch_allowed, Position pos,
AbstractConnectionManager *connManager) const
SegmentTracker::prepareChunk(bool switch_allowed, Position pos) const
{
if(!adaptationSet)
return ChunkEntry();
bool b_updated = false;
/* starting */
if(!pos.isValid())
{
......@@ -269,26 +273,33 @@ SegmentTracker::prepareChunk(bool switch_allowed, Position pos,
temp.rep = logic->getNextRepresentation(adaptationSet, pos.rep);
if(temp.rep && temp.rep != pos.rep)
{
/* Convert our segment number if we need to */
temp.number = temp.rep->translateSegmentNumber(pos.number, pos.rep);
/* Ensure ephemere content is updated/loaded */
if(temp.rep->needsUpdate(pos.number))
b_updated = temp.rep->runLocalUpdates(resources);
/* if we need to translate pos */
if(!temp.rep->consistentSegmentNumber())
{
/* Convert our segment number */
if(temp.rep->needsUpdate(temp.number))
temp.rep->scheduleNextUpdate(temp.number, temp.rep->runLocalUpdates(resources));
/* could have been std::numeric_limits<uint64_t>::max() if not found because not avail */
if(!temp.isValid()) /* try again */
temp.number = temp.rep->translateSegmentNumber(pos.number, pos.rep);
}
else temp.number = pos.number;
/* cancel switch that would go past playlist */
if(temp.isValid() && temp.rep->getMinAheadTime(temp.number) == 0)
temp = Position();
}
if(temp.isValid())
pos = temp;
}
}
ISegment *segment = nullptr;
bool b_gap = true;
ISegment *datasegment = pos.rep->getNextMediaSegment(pos.number, &pos.number, &b_gap);
pos.rep->scheduleNextUpdate(pos.number, b_updated);
if(!datasegment)
return ChunkEntry();
ISegment *segment = nullptr;
if(!pos.init_sent)
{
segment = pos.rep->getInitSegment();
......@@ -304,20 +315,24 @@ SegmentTracker::prepareChunk(bool switch_allowed, Position pos,
++pos;
}
bool b_gap = true;
if(!segment)
segment = pos.rep->getNextMediaSegment(pos.number, &pos.number, &b_gap);
if(!segment)
return ChunkEntry();
segment = datasegment;
SegmentChunk *segmentChunk = segment->toChunk(resources, connManager, pos.number, pos.rep);
SegmentChunk *segmentChunk = segment->toChunk(resources, pos.number, pos.rep);
if(!segmentChunk)
return ChunkEntry();
const Timescale timescale = pos.rep->inheritTimescale();
return ChunkEntry(segmentChunk, pos, VLC_TICK_0 + timescale.ToTime(segment->startTime.Get()),
timescale.ToTime(segment->duration.Get()), segment->getDisplayTime());
if(segment != datasegment) /* need to set for init */
segmentChunk->discontinuitySequenceNumber = datasegment->getDiscontinuitySequenceNumber();
vlc_tick_t startTime = VLC_TICK_INVALID;
vlc_tick_t duration = 0;
vlc_tick_t displayTime = datasegment->getDisplayTime();
/* timings belong to timeline and are not set on the segment or need profile timescale */
if(pos.rep->getPlaybackTimeDurationBySegmentNumber(pos.number, &startTime, &duration))
startTime += VLC_TICK_0;
return ChunkEntry(segmentChunk, pos, startTime, duration, displayTime);
}
void SegmentTracker::resetChunksSequence()
......@@ -329,15 +344,14 @@ void SegmentTracker::resetChunksSequence()
}
}
ChunkInterface * SegmentTracker::getNextChunk(bool switch_allowed,
AbstractConnectionManager *connManager)
ChunkInterface * SegmentTracker::getNextChunk(bool switch_allowed)
{
if(!adaptationSet || !next.isValid())
return nullptr;
if(chunkssequence.empty())
{
ChunkEntry chunk = prepareChunk(switch_allowed, next, connManager);
ChunkEntry chunk = prepareChunk(switch_allowed, next);
chunkssequence.push_back(chunk);
}
......@@ -351,12 +365,18 @@ ChunkInterface * SegmentTracker::getNextChunk(bool switch_allowed,
/* here next == wanted chunk pos */
bool b_gap = (next.number != chunk.pos.number);
const bool b_switched = (next.rep != chunk.pos.rep);
const bool b_discontinuity = chunk.chunk->discontinuity;
const bool b_switched = (current.rep != chunk.pos.rep) || !current.rep;
bool b_discontinuity = chunk.chunk->discontinuity && current.isValid();
if(b_discontinuity && current.number == next.number)
{
/* if we are on the same segment and indexes have been sent, then discontinuity was */
b_discontinuity = false;
}
const uint64_t discontinuitySequenceNumber = chunk.chunk->discontinuitySequenceNumber;
if(b_switched)
{
notify(RepresentationSwitchEvent(next.rep, chunk.pos.rep));
notify(RepresentationSwitchEvent(current.rep, chunk.pos.rep));
initializing = true;
}
......@@ -403,13 +423,17 @@ ChunkInterface * SegmentTracker::getNextChunk(bool switch_allowed,
initializing = false;
}
/* Notify new segment length for stats / logic */
if(chunk.pos.init_sent && chunk.pos.index_sent)
notify(SegmentChangedEvent(adaptationSet->getID(), chunk.starttime, chunk.duration, chunk.displaytime));
if(b_gap)
notify(SegmentGapEvent());
/* Handle both implicit and explicit discontinuities */
if(b_gap || b_discontinuity)
notify(DiscontinuityEvent());
if(b_discontinuity)
notify(DiscontinuityEvent(discontinuitySequenceNumber));
/* Notify new segment length for stats / logic */
notify(SegmentChangedEvent(adaptationSet->getID(),
discontinuitySequenceNumber,
chunk.starttime, chunk.duration, chunk.displaytime));
if(!b_gap)
++next;
......@@ -427,12 +451,17 @@ bool SegmentTracker::setPositionByTime(vlc_tick_t time, bool restarted, bool try
return false;
/* Stream might not have been loaded at all (HLS) or expired */
if(pos.rep->needsUpdate(pos.number) && !pos.rep->runLocalUpdates(resources))
if(pos.rep->needsUpdate(pos.number))
{
msg_Err(adaptationSet->getPlaylist()->getVLCObject(),
"Failed to update Representation %s",
pos.rep->getID().str().c_str());
return false;
if(!pos.rep->runLocalUpdates(resources))
{
msg_Err(adaptationSet->getPlaylist()->getVLCObject(),
"Failed to update Representation %s",
pos.rep->getID().str().c_str());
return false;
}
pos.rep->scheduleNextUpdate(pos.number, true);
notify(RepresentationUpdatedEvent(pos.rep));
}
if(pos.rep->getSegmentNumberByTime(time, &pos.number))
......@@ -451,7 +480,7 @@ void SegmentTracker::setPosition(const Position &pos, bool restarted)
current = Position();
next = pos;
resetChunksSequence();
notify(PositionChangedEvent());
notify(PositionChangedEvent(getPlaybackTime(true)));
}
SegmentTracker::Position SegmentTracker::getStartPosition() const
......@@ -461,9 +490,11 @@ SegmentTracker::Position SegmentTracker::getStartPosition() const
if(pos.rep)
{
/* Ensure ephemere content is updated/loaded */
if(pos.rep->needsUpdate(pos.number))
pos.rep->runLocalUpdates(resources);
bool b_updated = pos.rep->needsUpdate(pos.number) && pos.rep->runLocalUpdates(resources);
pos.number = bufferingLogic->getStartSegmentNumber(pos.rep);
pos.rep->scheduleNextUpdate(pos.number, b_updated);
if(b_updated)
notify(RepresentationUpdatedEvent(pos.rep));
}
return pos;
}
......@@ -514,8 +545,12 @@ vlc_tick_t SegmentTracker::getMinAheadTime() const
{
/* Ensure ephemere content is updated/loaded */
if(rep->needsUpdate(next.number))
(void) rep->runLocalUpdates(resources);
{
bool b_updated = rep->runLocalUpdates(resources);
rep->scheduleNextUpdate(next.number, b_updated);
if(b_updated)
notify(RepresentationUpdatedEvent(rep));
}
uint64_t startnumber = current.number;
if(startnumber == std::numeric_limits<uint64_t>::max())
startnumber = bufferingLogic->getStartSegmentNumber(rep);
......@@ -525,6 +560,19 @@ vlc_tick_t SegmentTracker::getMinAheadTime() const
return 0;
}
bool SegmentTracker::getSynchronizationReference(uint64_t discontinuitysequence,
vlc_tick_t time,
SynchronizationReference &r) const
{
return synchronizationReferences->getReference(discontinuitysequence, time, r);
}
void SegmentTracker::updateSynchronizationReference(uint64_t discontinuitysequence,
const Times &t)
{
synchronizationReferences->addReference(discontinuitysequence, t);
}
void SegmentTracker::notifyBufferingState(bool enabled) const
{
notify(BufferingStateUpdatedEvent(adaptationSet->getID(), enabled));
......@@ -554,7 +602,12 @@ void SegmentTracker::updateSelected()
{
bool b_updated = current.rep->runLocalUpdates(resources);
current.rep->scheduleNextUpdate(current.number, b_updated);
if(b_updated)
notify(RepresentationUpdatedEvent(current.rep));
}
if(current.rep && current.rep->canNoLongerUpdate())
notify(RepresentationUpdateFailedEvent(current.rep));
}
void SegmentTracker::notify(const TrackerEvent &event) const
......
......@@ -21,6 +21,7 @@
#define SEGMENTTRACKER_HPP
#include "StreamFormat.hpp"
#include "Time.hpp"
#include "playlist/CodecDescription.hpp"
#include "playlist/Role.hpp"
......@@ -61,7 +62,10 @@ namespace adaptive
enum class Type
{
Discontinuity,
SegmentGap,
RepresentationSwitch,
RepresentationUpdated,
RepresentationUpdateFailed,
FormatChange,
SegmentChange,
BufferingStateUpdate,
......@@ -82,8 +86,17 @@ namespace adaptive
class DiscontinuityEvent : public TrackerEvent
{
public:
DiscontinuityEvent();
DiscontinuityEvent(uint64_t);
virtual ~DiscontinuityEvent() = default;
uint64_t discontinuitySequenceNumber;
};
class SegmentGapEvent : public TrackerEvent
{
public:
SegmentGapEvent();
virtual ~SegmentGapEvent() = default;
};
class RepresentationSwitchEvent : public TrackerEvent
......@@ -97,6 +110,24 @@ namespace adaptive
BaseRepresentation *next;
};
class RepresentationUpdatedEvent : public TrackerEvent
{
public:
RepresentationUpdatedEvent(BaseRepresentation *);
virtual ~RepresentationUpdatedEvent() = default;
BaseRepresentation *rep;
};
class RepresentationUpdateFailedEvent : public TrackerEvent
{
public:
RepresentationUpdateFailedEvent(BaseRepresentation *);
virtual ~RepresentationUpdateFailedEvent() = default;
BaseRepresentation *rep;
};
class FormatChangedEvent : public TrackerEvent
{
public:
......@@ -111,10 +142,12 @@ namespace adaptive
{
public:
SegmentChangedEvent() = delete;
SegmentChangedEvent(const ID &, vlc_tick_t, vlc_tick_t, vlc_tick_t = VLC_TICK_INVALID);
SegmentChangedEvent(const ID &, uint64_t,
vlc_tick_t, vlc_tick_t, vlc_tick_t = VLC_TICK_INVALID);
virtual ~SegmentChangedEvent() = default;
const ID *id;
uint64_t sequence;
vlc_tick_t displaytime;
vlc_tick_t starttime;
vlc_tick_t duration;
......@@ -149,8 +182,10 @@ namespace adaptive
class PositionChangedEvent : public TrackerEvent
{
public:
PositionChangedEvent();
PositionChangedEvent(vlc_tick_t);
virtual ~PositionChangedEvent() = default;
vlc_tick_t resumeTime;
};
class SegmentTrackerListenerInterface
......@@ -166,7 +201,8 @@ namespace adaptive
SegmentTracker(SharedResources *,
AbstractAdaptationLogic *,
const AbstractBufferingLogic *,
BaseAdaptationSet *);
BaseAdaptationSet *,
SynchronizationReferences *);
~SegmentTracker();
class Position
......@@ -183,11 +219,10 @@ namespace adaptive
bool index_sent;
};
StreamFormat getCurrentFormat() const;
void getCodecsDesc(CodecDescriptionList *) const;
const Role & getStreamRole() const;
void reset();
ChunkInterface* getNextChunk(bool, AbstractConnectionManager *);
ChunkInterface* getNextChunk(bool);
bool setPositionByTime(vlc_tick_t, bool, bool);
void setPosition(const Position &, bool);
bool setStartPosition();
......@@ -195,6 +230,8 @@ namespace adaptive
vlc_tick_t getPlaybackTime(bool = false) const; /* Current segment start time if selected */
bool getMediaPlaybackRange(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *) const;
vlc_tick_t getMinAheadTime() const;
bool getSynchronizationReference(uint64_t, vlc_tick_t, SynchronizationReference &) const;
void updateSynchronizationReference(uint64_t, const Times &);
void notifyBufferingState(bool) const;
void notifyBufferingLevel(vlc_tick_t, vlc_tick_t, vlc_tick_t, vlc_tick_t) const;
void registerListener(SegmentTrackerListenerInterface *);
......@@ -215,8 +252,7 @@ namespace adaptive
vlc_tick_t duration;
};
std::list<ChunkEntry> chunkssequence;
ChunkEntry prepareChunk(bool switch_allowed, Position pos,
AbstractConnectionManager *connManager) const;
ChunkEntry prepareChunk(bool switch_allowed, Position pos) const;
void resetChunksSequence();
void setAdaptationLogic(AbstractAdaptationLogic *);
void notify(const TrackerEvent &) const;
......@@ -226,6 +262,7 @@ namespace adaptive
Position next;
StreamFormat format;
SharedResources *resources;
SynchronizationReferences *synchronizationReferences;
AbstractAdaptationLogic *logic;
const AbstractBufferingLogic *bufferingLogic;
BaseAdaptationSet *adaptationSet;
......
......@@ -126,13 +126,14 @@ StreamFormat::StreamFormat(const void *data_, size_t sz)
{
const uint8_t *data = reinterpret_cast<const uint8_t *>(data_);
type = Type::Unknown;
const char moov[] = "ftypmoovmoof";
const char moov[] = "ftypmoovmoofemsg";
if(sz > 188 && data[0] == 0x47 && data[188] == 0x47)
type = StreamFormat::Type::MPEG2TS;
else if(sz > 8 && (!memcmp(&moov, &data[4], 4) ||
!memcmp(&moov[4], &data[4], 4) ||
!memcmp(&moov[8], &data[4], 4)))
!memcmp(&moov[8], &data[4], 4) ||
!memcmp(&moov[12], &data[4], 4)))
type = StreamFormat::Type::MP4;
else if(IsWebVTT((const char *)data, sz))
type = StreamFormat::Type::WebVTT;
......
......@@ -47,6 +47,7 @@ AbstractStream::AbstractStream(demux_t * demux_)
eof = false;
valid = true;
disabled = false;
segmentgap = false;
discontinuity = false;
needrestart = false;
inrestart = false;
......@@ -56,11 +57,14 @@ AbstractStream::AbstractStream(demux_t * demux_)
demuxer = nullptr;
fakeesout = nullptr;
notfound_sequence = 0;
mightalwaysstartfromzero = false;
last_buffer_status = BufferingStatus::Lessthanmin;
currentrep.width = 0;
currentrep.height = 0;
vlc_mutex_init(&lock);
}
bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker, AbstractConnectionManager *conn)
bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker)
{
/* Don't even try if not supported or already init */
if(format_ == StreamFormat::Type::Unsupported || demuxersource)
......@@ -88,7 +92,6 @@ bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker,
segmentTracker = tracker;
segmentTracker->registerListener(this);
segmentTracker->notifyBufferingState(true);
connManager = conn;
fakeesout->setExpectedTimestamp(segmentTracker->getPlaybackTime());
declaredCodecs();
return true;
......@@ -140,15 +143,26 @@ bool AbstractStream::resetForNewPosition(vlc_tick_t seekMediaTime)
eof = false;
demuxfirstchunk = true;
notfound_sequence = 0;
last_buffer_status = BufferingStatus::Lessthanmin;
inrestart = false;
needrestart = false;
discontinuity = false;
if(!demuxer || demuxer->needsRestartOnSeek()) /* needs (re)start */
{
delete currentChunk;
currentChunk = nullptr;
needrestart = false;
segmentgap = false;
fakeEsOut()->resetTimestamps();
fakeEsOut()->setExpectedTimestamp(seekMediaTime);
fakeEsOut()->commandsQueue()->Abort( true );
startTimeContext = SegmentTimes();
currentTimeContext = SegmentTimes();
prevTimeContext = SegmentTimes();
currentChunk = getNextChunk();
if(mightalwaysstartfromzero)
fakeEsOut()->setExpectedTimestamp(seekMediaTime);
if( !restartDemux() )
{
msg_Info(p_realdemux, "Restart demux failed");
......@@ -182,17 +196,17 @@ vlc_tick_t AbstractStream::getMinAheadTime() const
return segmentTracker->getMinAheadTime();
}
vlc_tick_t AbstractStream::getFirstDTS() const
Times AbstractStream::getFirstTimes() const
{
vlc_mutex_locker locker(&lock);
if(!valid || disabled)
return VLC_TICK_INVALID;
return Times();
vlc_tick_t dts = fakeEsOut()->commandsQueue()->getFirstDTS();
if(dts == VLC_TICK_INVALID)
dts = fakeEsOut()->commandsQueue()->getPCR();
return dts;
Times times = fakeEsOut()->commandsQueue()->getFirstTimes();
if(times.continuous == VLC_TICK_INVALID)
times = fakeEsOut()->commandsQueue()->getPCR();
return times;
}
int AbstractStream::esCount() const
......@@ -226,10 +240,16 @@ bool AbstractStream::isSelected() const
return fakeEsOut()->hasSelectedEs();
}
bool AbstractStream::reactivate(vlc_tick_t basetime)
AbstractStream::StreamPosition::StreamPosition()
{
number = std::numeric_limits<uint64_t>::max();
pos = -1;
}
bool AbstractStream::reactivate(const StreamPosition &pos)
{
vlc_mutex_locker locker(&lock);
if(setPosition(basetime, false))
if(setPosition(pos, false))
{
setDisabled(false);
return true;
......@@ -248,6 +268,7 @@ bool AbstractStream::startDemux()
if(!currentChunk)
{
segmentgap = false;
currentChunk = getNextChunk();
needrestart = false;
discontinuity = false;
......@@ -297,6 +318,11 @@ void AbstractStream::setDisabled(bool b)
disabled = b;
}
bool AbstractStream::isContiguousMux() const
{
return true;
}
bool AbstractStream::isValid() const
{
vlc_mutex_locker locker(&lock);
......@@ -324,28 +350,52 @@ bool AbstractStream::decodersDrained()
return fakeEsOut()->decodersDrained();
}
AbstractStream::BufferingStatus AbstractStream::getLastBufferStatus() const
Times AbstractStream::getDemuxedAmount(Times from) const
{
return last_buffer_status;
return fakeEsOut()->commandsQueue()->getDemuxedAmount(from);
}
vlc_tick_t AbstractStream::getDemuxedAmount(vlc_tick_t from) const
AbstractStream::BufferingStatus
AbstractStream::getBufferAndStatus(const Times &deadline,
vlc_tick_t i_min_buffering,
vlc_tick_t i_max_buffering,
vlc_tick_t *pi_demuxed)
{
return fakeEsOut()->commandsQueue()->getDemuxedAmount(from);
if(last_buffer_status == BufferingStatus::End)
return BufferingStatus::End;
*pi_demuxed = getDemuxedAmount(deadline).continuous;
bool b_contiguous = isContiguousMux();
if(!b_contiguous &&
prevTimeContext.media != VLC_TICK_INVALID &&
deadline.segment.media != VLC_TICK_INVALID)
{
if(prevTimeContext.media - deadline.segment.media > *pi_demuxed)
*pi_demuxed = prevTimeContext.media - deadline.segment.media;
}
if(*pi_demuxed < i_max_buffering) /* need to read more */
{
if(*pi_demuxed < i_min_buffering)
return BufferingStatus::Lessthanmin; /* high prio */
return BufferingStatus::Ongoing;
}
return BufferingStatus::Full;
}
AbstractStream::BufferingStatus AbstractStream::bufferize(vlc_tick_t nz_deadline,
AbstractStream::BufferingStatus AbstractStream::bufferize(Times deadline,
vlc_tick_t i_min_buffering,
vlc_tick_t i_extra_buffering,
vlc_tick_t i_target_buffering,
bool b_keep_alive)
{
last_buffer_status = doBufferize(nz_deadline, i_min_buffering, i_extra_buffering,
last_buffer_status = doBufferize(deadline, i_min_buffering, i_extra_buffering,
i_target_buffering, b_keep_alive);
return last_buffer_status;
}
AbstractStream::BufferingStatus AbstractStream::doBufferize(vlc_tick_t nz_deadline,
AbstractStream::BufferingStatus AbstractStream::doBufferize(Times deadline,
vlc_tick_t i_min_buffering,
vlc_tick_t i_max_buffering,
vlc_tick_t i_target_buffering,
......@@ -354,7 +404,7 @@ AbstractStream::BufferingStatus AbstractStream::doBufferize(vlc_tick_t nz_deadli
vlc_mutex_lock(&lock);
/* Ensure it is configured */
if(!segmentTracker || !connManager || !valid)
if(!segmentTracker || !valid)
{
vlc_mutex_unlock(&lock);
return BufferingStatus::End;
......@@ -387,6 +437,40 @@ AbstractStream::BufferingStatus AbstractStream::doBufferize(vlc_tick_t nz_deadli
return BufferingStatus::Suspended;
}
if(!isContiguousMux())
{
if(!fakeEsOut()->hasSynchronizationReference())
{
if(!demuxer)
{
/* We always need a prepared chunk info for querying a syncref */
if(!currentChunk)
{
currentChunk = getNextChunk();
if(!currentChunk)
{
vlc_mutex_unlock(&lock);
return BufferingStatus::End;
}
segmentgap = false;
needrestart = false;
discontinuity = false;
}
}
SynchronizationReference r;
if(segmentTracker->getSynchronizationReference(currentSequence, startTimeContext.media, r))
{
fakeEsOut()->setSynchronizationReference(r);
}
else
{
msg_Dbg(p_realdemux, "Waiting sync reference for seq %ld", currentSequence);
vlc_mutex_unlock(&lock);
return BufferingStatus::Suspended;
}
}
}
if(!demuxer)
{
if(!startDemux())
......@@ -398,17 +482,30 @@ AbstractStream::BufferingStatus AbstractStream::doBufferize(vlc_tick_t nz_deadli
}
}
vlc_tick_t i_demuxed = fakeEsOut()->commandsQueue()->getDemuxedAmount(nz_deadline);
vlc_tick_t i_demuxed = fakeEsOut()->commandsQueue()->getDemuxedAmount(deadline).continuous;
if(!isContiguousMux() && prevTimeContext.media != VLC_TICK_INVALID)
{
if(prevTimeContext.media - deadline.segment.media > i_demuxed)
i_demuxed = prevTimeContext.media - deadline.segment.media;
}
segmentTracker->notifyBufferingLevel(i_min_buffering, i_max_buffering, i_demuxed, i_target_buffering);
if(i_demuxed < i_max_buffering) /* not already demuxed */
{
vlc_tick_t nz_extdeadline = fakeEsOut()->commandsQueue()->getBufferingLevel() +
(i_max_buffering - i_demuxed) / 4;
nz_deadline = std::min(nz_extdeadline, nz_deadline + VLC_TICK_FROM_SEC(1));
Times extdeadline = fakeEsOut()->commandsQueue()->getBufferingLevel();
extdeadline.offsetBy((i_max_buffering - i_demuxed) / 4);
Times newdeadline = deadline;
newdeadline.offsetBy(VLC_TICK_FROM_SEC(1));
if(extdeadline.continuous < newdeadline.continuous)
deadline = extdeadline;
else
deadline = newdeadline;
/* need to read, demuxer still buffering, ... */
vlc_mutex_unlock(&lock);
Demuxer::Status demuxStatus = demuxer->demux(nz_deadline);
Demuxer::Status demuxStatus = demuxer->demux(deadline.continuous);
fakeEsOut()->scheduleNecessaryMilestone();
vlc_mutex_lock(&lock);
if(demuxStatus != Demuxer::Status::Success)
......@@ -421,8 +518,18 @@ AbstractStream::BufferingStatus AbstractStream::doBufferize(vlc_tick_t nz_deadli
{
msg_Dbg(p_realdemux, "Draining on discontinuity");
fakeEsOut()->commandsQueue()->setDraining();
discontinuity = false;
fakeEsOut()->setSegmentStartTimes(startTimeContext);
assert(startTimeContext.media);
}
assert(startTimeContext.media);
if(!fakeEsOut()->hasSegmentStartTimes())
fakeEsOut()->setSegmentStartTimes(startTimeContext);
if(!fakeEsOut()->hasSynchronizationReference())
{
SynchronizationReference r(currentSequence, Times());
fakeEsOut()->setSynchronizationReference(r);
}
discontinuity = false;
needrestart = false;
vlc_mutex_unlock(&lock);
return BufferingStatus::Ongoing;
......@@ -431,11 +538,15 @@ AbstractStream::BufferingStatus AbstractStream::doBufferize(vlc_tick_t nz_deadli
vlc_mutex_unlock(&lock);
return BufferingStatus::End;
}
i_demuxed = fakeEsOut()->commandsQueue()->getDemuxedAmount(nz_deadline);
i_demuxed = fakeEsOut()->commandsQueue()->getDemuxedAmount(deadline).continuous;
segmentTracker->notifyBufferingLevel(i_min_buffering, i_max_buffering, i_demuxed, i_target_buffering);
}
vlc_mutex_unlock(&lock);
Times first = fakeEsOut()->commandsQueue()->getFirstTimes();
if(isContiguousMux() && first.continuous != VLC_TICK_INVALID && first.segment.demux != VLC_TICK_INVALID)
segmentTracker->updateSynchronizationReference(currentSequence, first);
if(i_demuxed < i_max_buffering) /* need to read more */
{
if(i_demuxed < i_min_buffering)
......@@ -445,23 +556,21 @@ AbstractStream::BufferingStatus AbstractStream::doBufferize(vlc_tick_t nz_deadli
return BufferingStatus::Full;
}
AbstractStream::Status AbstractStream::dequeue(vlc_tick_t nz_deadline, vlc_tick_t *pi_pcr)
AbstractStream::Status AbstractStream::dequeue(Times deadline, Times *times)
{
vlc_mutex_locker locker(&lock);
*pi_pcr = nz_deadline;
if(fakeEsOut()->commandsQueue()->isDraining())
{
AdvDebug(vlc_tick_t pcrvalue = fakeEsOut()->commandsQueue()->getPCR();
vlc_tick_t dtsvalue = fakeEsOut()->commandsQueue()->getFirstDTS();
vlc_tick_t bufferingLevel = fakeEsOut()->commandsQueue()->getBufferingLevel();
AdvDebug(vlc_tick_t pcrvalue = fakeEsOut()->commandsQueue()->getPCR().continuous;
vlc_tick_t dtsvalue = fakeEsOut()->commandsQueue()->getFirstTimes().continuous;
vlc_tick_t bufferingLevel = fakeEsOut()->commandsQueue()->getBufferingLevel().continuous;
msg_Dbg(p_realdemux, "Stream pcr %" PRId64 " dts %" PRId64 " deadline %" PRId64 " buflevel %" PRId64 "(+%" PRId64 ") [DRAINING] :%s",
pcrvalue, dtsvalue, nz_deadline, bufferingLevel,
pcrvalue, dtsvalue, deadline.continuous, bufferingLevel,
pcrvalue ? bufferingLevel - pcrvalue : 0,
description.c_str()));
*pi_pcr = fakeEsOut()->commandsQueue()->Process(VLC_TICK_0 + nz_deadline);
*times = fakeEsOut()->commandsQueue()->Process(deadline);
if(!fakeEsOut()->commandsQueue()->isEmpty())
return Status::Demuxed;
......@@ -474,22 +583,33 @@ AbstractStream::Status AbstractStream::dequeue(vlc_tick_t nz_deadline, vlc_tick_
if(!valid || disabled || fakeEsOut()->commandsQueue()->isEOF())
{
*pi_pcr = nz_deadline;
*times = deadline;
return Status::Eof;
}
vlc_tick_t bufferingLevel = fakeEsOut()->commandsQueue()->getBufferingLevel();
AdvDebug(vlc_tick_t pcrvalue = fakeEsOut()->commandsQueue()->getPCR();
vlc_tick_t dtsvalue = fakeEsOut()->commandsQueue()->getFirstDTS();
vlc_tick_t bufferingLevel = fakeEsOut()->commandsQueue()->getBufferingLevel().continuous;
AdvDebug(vlc_tick_t pcrvalue = fakeEsOut()->commandsQueue()->getPCR().continuous;
vlc_tick_t dtsvalue = fakeEsOut()->commandsQueue()->getFirstTimes().continuous;
msg_Dbg(p_realdemux, "Stream pcr %" PRId64 " dts %" PRId64 " deadline %" PRId64 " buflevel %" PRId64 "(+%" PRId64 "): %s",
pcrvalue, dtsvalue, nz_deadline, bufferingLevel,
pcrvalue, dtsvalue, deadline.continuous, bufferingLevel,
pcrvalue ? bufferingLevel - pcrvalue : 0,
description.c_str()));
if(nz_deadline + VLC_TICK_0 <= bufferingLevel) /* demuxed */
Times head = fakeEsOut()->commandsQueue()->getFirstTimes();
if(deadline.continuous <= bufferingLevel) /* demuxed */
{
*times = fakeEsOut()->commandsQueue()->Process(deadline);
return Status::Demuxed;
}
else if(!isContiguousMux() &&
deadline.continuous != VLC_TICK_INVALID &&
prevTimeContext.media != VLC_TICK_INVALID &&
deadline.segment.media < prevTimeContext.media &&
head.segment.media <= prevTimeContext.media )
{
*pi_pcr = fakeEsOut()->commandsQueue()->Process( VLC_TICK_0 + nz_deadline );
*times = deadline;
times->segment.offsetBy(prevTimeContext.media - times->segment.media);
times->continuous += (prevTimeContext.media - times->segment.media);
return Status::Demuxed;
}
......@@ -499,13 +619,27 @@ AbstractStream::Status AbstractStream::dequeue(vlc_tick_t nz_deadline, vlc_tick_
ChunkInterface * AbstractStream::getNextChunk() const
{
const bool b_restarting = fakeEsOut()->restarting();
return segmentTracker->getNextChunk(!b_restarting, connManager);
ChunkInterface *ck = segmentTracker->getNextChunk(!b_restarting);
if(ck && !fakeEsOut()->hasSegmentStartTimes())
fakeEsOut()->setSegmentStartTimes(startTimeContext);
if(ck && !fakeEsOut()->hasSynchronizationReference())
{
assert(fakeEsOut()->hasSegmentStartTimes());
SynchronizationReference r;
if(segmentTracker->getSynchronizationReference(currentSequence, startTimeContext.media, r))
fakeEsOut()->setSynchronizationReference(r);
}
return ck;
}
block_t * AbstractStream::readNextBlock()
{
if (currentChunk == nullptr && !eof)
{
segmentgap = false;
currentChunk = getNextChunk();
}
if(demuxfirstchunk)
{
......@@ -536,7 +670,7 @@ block_t * AbstractStream::readNextBlock()
if(currentChunk->getRequestStatus() == RequestStatus::NotFound &&
++notfound_sequence < 3)
{
discontinuity = true;
segmentgap = true;
}
delete currentChunk;
currentChunk = nullptr;
......@@ -557,13 +691,14 @@ block_t * AbstractStream::readNextBlock()
return block;
}
bool AbstractStream::setPosition(vlc_tick_t time, bool tryonly)
bool AbstractStream::setPosition(const StreamPosition &pos, bool tryonly)
{
if(!seekAble())
return false;
bool b_needs_restart = demuxer ? demuxer->needsRestartOnSeek() : true;
bool ret = segmentTracker->setPositionByTime(time, b_needs_restart, tryonly);
bool ret = segmentTracker->setPositionByTime(pos.times.segment.media,
b_needs_restart, tryonly);
if(!tryonly && ret)
{
// in some cases, media time seek != sent dts
......@@ -574,12 +709,17 @@ bool AbstractStream::setPosition(vlc_tick_t time, bool tryonly)
}
bool AbstractStream::getMediaPlaybackTimes(vlc_tick_t *start, vlc_tick_t *end,
vlc_tick_t *length,
vlc_tick_t *mediaStart,
vlc_tick_t *demuxStart) const
vlc_tick_t *length) const
{
return (segmentTracker->getMediaPlaybackRange(start, end, length) &&
fakeEsOut()->getStartTimestamps(mediaStart, demuxStart));
return segmentTracker->getMediaPlaybackRange(start, end, length);
}
bool AbstractStream::getMediaAdvanceAmount(vlc_tick_t *duration) const
{
if(startTimeContext.media == VLC_TICK_INVALID)
return false;
*duration = currentTimeContext.media - startTimeContext.media;
return true;
}
void AbstractStream::runUpdates()
......@@ -594,6 +734,11 @@ void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const
p_fmt->psz_language = strdup(language.c_str());
if(!p_fmt->psz_description && !description.empty())
p_fmt->psz_description = strdup(description.c_str());
if( p_fmt->i_cat == VIDEO_ES && p_fmt->video.i_visible_width == 0)
{
p_fmt->video.i_visible_width = currentrep.width;
p_fmt->video.i_visible_height = currentrep.height;
}
}
AbstractDemuxer * AbstractStream::createDemux(const StreamFormat &format)
......@@ -636,7 +781,16 @@ void AbstractStream::trackerEvent(const TrackerEvent &ev)
switch(ev.getType())
{
case TrackerEvent::Type::Discontinuity:
{
const DiscontinuityEvent &event =
static_cast<const DiscontinuityEvent &>(ev);
discontinuity = true;
currentSequence = event.discontinuitySequenceNumber;
}
break;
case TrackerEvent::Type::SegmentGap:
segmentgap = true;
break;
case TrackerEvent::Type::FormatChange:
......@@ -674,18 +828,57 @@ void AbstractStream::trackerEvent(const TrackerEvent &ev)
event.prev ? event.prev->getStreamFormat().str().c_str() : "",
event.next ? event.next->getID().str().c_str() : "",
event.next ? event.next->getStreamFormat().str().c_str() : ""));
if(event.next)
{
currentrep.width = event.next->getWidth() > 0 ? event.next->getWidth() : 0;
currentrep.height = event.next->getHeight() > 0 ? event.next->getHeight() : 0;
}
else
{
currentrep.width = 0;
currentrep.height = 0;
}
}
break;
case TrackerEvent::Type::RepresentationUpdated:
{
if(last_buffer_status == BufferingStatus::Suspended)
last_buffer_status = BufferingStatus::Lessthanmin;
}
break;
case TrackerEvent::Type::RepresentationUpdateFailed:
{
fakeEsOut()->commandsQueue()->setEOF(true);
msg_Err(p_realdemux, "Could not update %s anymore, disabling", description.c_str());
}
break;
case TrackerEvent::Type::SegmentChange:
{
const SegmentChangedEvent &event =
static_cast<const SegmentChangedEvent &>(ev);
if(demuxer && demuxer->needsRestartOnEachSegment() && !inrestart)
{
needrestart = true;
}
prevTimeContext = currentTimeContext;
currentTimeContext.media = event.starttime;
currentTimeContext.display = event.displaytime;
currentSequence = event.sequence;
currentDuration = event.duration;
if(startTimeContext.media == VLC_TICK_INVALID)
startTimeContext = currentTimeContext;
}
break;
case TrackerEvent::Type::PositionChange:
resetForNewPosition(segmentTracker->getPlaybackTime(true));
{
const PositionChangedEvent &event =
static_cast<const PositionChangedEvent &>(ev);
resetForNewPosition(event.resumeTime);
}
break;
default:
......
......@@ -30,6 +30,8 @@
#include "plumbing/SourceStream.hpp"
#include "plumbing/FakeESOut.hpp"
#include "Time.hpp"
#include <string>
namespace adaptive
......@@ -38,7 +40,6 @@ namespace adaptive
namespace http
{
class AbstractConnectionManager;
class ChunkInterface;
}
......@@ -58,15 +59,14 @@ namespace adaptive
public:
AbstractStream(demux_t *);
virtual ~AbstractStream();
bool init(const StreamFormat &, SegmentTracker *, AbstractConnectionManager *);
bool init(const StreamFormat &, SegmentTracker *);
void setLanguage(const std::string &);
void setDescription(const std::string &);
vlc_tick_t getMinAheadTime() const;
vlc_tick_t getFirstDTS() const;
Times getFirstTimes() const;
int esCount() const;
bool isSelected() const;
virtual bool reactivate(vlc_tick_t);
bool isDisabled() const;
bool isValid() const;
void setLivePause(bool);
......@@ -83,15 +83,25 @@ namespace adaptive
Ongoing,
Lessthanmin,
};
BufferingStatus bufferize(vlc_tick_t, vlc_tick_t, vlc_tick_t,
BufferingStatus bufferize(Times, vlc_tick_t, vlc_tick_t,
vlc_tick_t, bool = false);
BufferingStatus getLastBufferStatus() const;
vlc_tick_t getDemuxedAmount(vlc_tick_t) const;
Status dequeue(vlc_tick_t, vlc_tick_t *);
BufferingStatus getBufferAndStatus(const Times &, vlc_tick_t, vlc_tick_t, vlc_tick_t *);
Times getDemuxedAmount(Times) const;
Status dequeue(Times, Times *);
bool decodersDrained();
virtual bool setPosition(vlc_tick_t, bool);
bool getMediaPlaybackTimes(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *,
vlc_tick_t *, vlc_tick_t *) const;
class StreamPosition
{
public:
StreamPosition();
Times times;
uint64_t number;
double pos;
};
virtual bool reactivate(const StreamPosition &);
virtual bool setPosition(const StreamPosition &, bool);
bool getMediaPlaybackTimes(vlc_tick_t *, vlc_tick_t *, vlc_tick_t *) const;
bool getMediaAdvanceAmount(vlc_tick_t *) const;
void runUpdates();
/* Used by demuxers fake streams */
......@@ -110,19 +120,22 @@ namespace adaptive
es_out_t *, AbstractSourceStream *) const override;
virtual bool startDemux();
virtual bool restartDemux();
virtual bool isContiguousMux() const;
virtual void prepareRestart(bool = true);
bool resetForNewPosition(vlc_tick_t);
bool segmentgap;
bool discontinuity;
bool needrestart;
bool inrestart;
bool demuxfirstchunk;
bool mightalwaysstartfromzero;
demux_t *p_realdemux;
StreamFormat format;
AbstractConnectionManager *connManager; /* not owned */
SegmentTracker *segmentTracker;
ChunkInterface * getNextChunk() const;
......@@ -130,6 +143,11 @@ namespace adaptive
bool eof;
std::string language;
std::string description;
struct
{
unsigned width;
unsigned height;
} currentrep;
AbstractDemuxer *demuxer;
AbstractSourceStream *demuxersource;
......@@ -138,9 +156,15 @@ namespace adaptive
FakeESOut *fakeesout; /* to intercept/proxy what is sent from demuxstream */
mutable vlc_mutex_t lock; /* lock for everything accessed by dequeuing */
SegmentTimes startTimeContext;
SegmentTimes currentTimeContext;
SegmentTimes prevTimeContext;
vlc_tick_t currentDuration;
uint64_t currentSequence;
private:
void declaredCodecs();
BufferingStatus doBufferize(vlc_tick_t, vlc_tick_t, vlc_tick_t,
BufferingStatus doBufferize(Times, vlc_tick_t, vlc_tick_t,
vlc_tick_t, bool);
BufferingStatus last_buffer_status;
bool valid;
......@@ -153,7 +177,7 @@ namespace adaptive
public:
virtual ~AbstractStreamFactory() {}
virtual AbstractStream *create(demux_t*, const StreamFormat &,
SegmentTracker *, AbstractConnectionManager *) const = 0;
SegmentTracker *) const = 0;
};
}
#endif // STREAMS_HPP
......@@ -21,6 +21,7 @@
#define TIME_HPP
#include <vlc_common.h>
#include <list>
namespace adaptive
{
......@@ -55,6 +56,97 @@ class Timescale
uint64_t scale;
};
class SegmentTimes
{
public:
SegmentTimes()
{
demux = VLC_TICK_INVALID;
media = VLC_TICK_INVALID;
display = VLC_TICK_INVALID;
}
SegmentTimes(vlc_tick_t a, vlc_tick_t b, vlc_tick_t c = VLC_TICK_INVALID)
{
demux = a;
media = b;
display = c;
}
void offsetBy(vlc_tick_t v)
{
if(v == 0)
return;
if(demux != VLC_TICK_INVALID)
demux += v;
if(media != VLC_TICK_INVALID)
media += v;
if(display != VLC_TICK_INVALID)
display += v;
}
vlc_tick_t demux;
vlc_tick_t media;
vlc_tick_t display;
};
class Times
{
public:
Times()
{
continuous = VLC_TICK_INVALID;
}
Times(const SegmentTimes &s, vlc_tick_t a)
{
segment = s;
continuous = a;
}
void offsetBy(vlc_tick_t v)
{
if(continuous != VLC_TICK_INVALID)
continuous += v;
segment.offsetBy(v);
}
vlc_tick_t continuous;
SegmentTimes segment;
};
using SynchronizationReference = std::pair<uint64_t, Times>;
class SynchronizationReferences
{
public:
SynchronizationReferences() = default;
void addReference(uint64_t seq, const Times &t)
{
for(auto &r : refs)
if(r.first == seq)
{
/* update reference when the timestamps are really old to prevent false roll */
constexpr vlc_tick_t quarterroll = (INT64_C(0x1FFFFFFFF) * 100 / 9) >> 2;
if(t.continuous - r.second.continuous > quarterroll)
r.second = t;
return;
}
while(refs.size() > 10)
refs.pop_back();
refs.push_front(SynchronizationReference(seq, t));
}
bool getReference(uint64_t seq, vlc_tick_t,
SynchronizationReference &ref) const
{
for(auto t : refs)
{
if(t.first != seq)
continue;
ref = t;
return true;
}
return false;
}
private:
std::list<SynchronizationReference> refs;
};
}
#endif // TIME_HPP
......
......@@ -68,6 +68,11 @@ RequestStatus AbstractChunkSource::getRequestStatus() const
return requeststatus;
}
const StorageID & AbstractChunkSource::getStorageID() const
{
return storeid;
}
ChunkType AbstractChunkSource::getChunkType() const
{
return type;
......@@ -152,6 +157,7 @@ HTTPChunkSource::HTTPChunkSource(const std::string& url, AbstractConnectionManag
eof = false;
sourceid = id;
setUseAccess(access);
setIdentifier(url, range);
if(!init(url))
eof = true;
}
......@@ -252,6 +258,11 @@ void HTTPChunkSource::recycle()
connManager->recycleSource(this);
}
StorageID HTTPChunkSource::makeStorageID(const std::string &s, const BytesRange &r)
{
return std::to_string(r.getStartByte())+ std::to_string(r.getEndByte()) + '@' + s;
}
std::string HTTPChunkSource::getContentType() const
{
mutex_locker locker {lock};
......@@ -261,6 +272,11 @@ std::string HTTPChunkSource::getContentType() const
return std::string();
}
void HTTPChunkSource::setIdentifier(const std::string &s, const BytesRange &r)
{
storeid = makeStorageID(s, r);
}
bool HTTPChunkSource::prepare()
{
if(prepared)
......@@ -325,6 +341,8 @@ HTTPChunkBufferedSource::HTTPChunkBufferedSource(const std::string& url, Abstrac
done = false;
eof = false;
held = false;
p_read = nullptr;
inblockreadoffset = 0;
}
HTTPChunkBufferedSource::~HTTPChunkBufferedSource()
......@@ -341,6 +359,7 @@ HTTPChunkBufferedSource::~HTTPChunkBufferedSource()
{
block_ChainRelease(p_head);
p_head = nullptr;
p_read = nullptr;
pp_tail = &p_head;
}
buffered = 0;
......@@ -406,7 +425,7 @@ void HTTPChunkBufferedSource::bufferize(size_t readsize)
mutex_locker locker {lock};
done = true;
downloadEndTime = vlc_tick_now();
rate.size = buffered + consumed;
rate.size = buffered;
rate.time = downloadEndTime - requestStartTime;
rate.latency = responseTime - requestStartTime;
}
......@@ -416,11 +435,16 @@ void HTTPChunkBufferedSource::bufferize(size_t readsize)
mutex_locker locker {lock};
buffered += p_block->i_buffer;
block_ChainLastAppend(&pp_tail, p_block);
if(p_read == nullptr)
{
p_read = p_block;
inblockreadoffset = 0;
}
if((size_t) ret < readsize)
{
done = true;
downloadEndTime = vlc_tick_now();
rate.size = buffered + consumed;
rate.size = buffered;
rate.time = downloadEndTime - requestStartTime;
rate.latency = responseTime - requestStartTime;
}
......@@ -441,16 +465,24 @@ bool HTTPChunkBufferedSource::hasMoreData() const
return !eof;
}
void HTTPChunkBufferedSource::recycle()
{
p_read = p_head;
inblockreadoffset = 0;
consumed = 0;
HTTPChunkSource::recycle();
}
block_t * HTTPChunkBufferedSource::readBlock()
{
block_t *p_block = nullptr;
mutex_locker locker {lock};
while(!p_head && !done)
while(!p_read && !done)
avail.wait(lock);
if(!p_head && done)
if(!p_read && done)
{
if(!eof)
p_block = block_Alloc(0);
......@@ -459,18 +491,12 @@ block_t * HTTPChunkBufferedSource::readBlock()
}
/* dequeue */
p_block = p_head;
p_head = p_head->p_next;
if(p_head == nullptr)
{
pp_tail = &p_head;
if(done)
eof = true;
}
p_block->p_next = nullptr;
p_block = block_Duplicate(p_read);
consumed += p_block->i_buffer;
buffered -= p_block->i_buffer;
p_read = p_read->p_next;
inblockreadoffset = 0;
if(p_read == nullptr && done)
eof = true;
return p_block;
}
......@@ -479,34 +505,28 @@ block_t * HTTPChunkBufferedSource::read(size_t readsize)
{
mutex_locker locker {lock};
while(readsize > buffered && !done)
while(readsize > (buffered - consumed) && !done)
avail.wait(lock);
block_t *p_block = nullptr;
if(!readsize || !buffered || !(p_block = block_Alloc(readsize)) )
if(!readsize || (buffered == consumed) || !(p_block = block_Alloc(readsize)) )
{
eof = true;
return nullptr;
}
size_t copied = 0;
while(buffered && readsize)
while(buffered && readsize && p_read)
{
const size_t toconsume = std::min(p_head->i_buffer, readsize);
memcpy(&p_block->p_buffer[copied], p_head->p_buffer, toconsume);
const size_t toconsume = std::min(p_read->i_buffer - inblockreadoffset, readsize);
memcpy(&p_block->p_buffer[copied], &p_read->p_buffer[inblockreadoffset], toconsume);
copied += toconsume;
readsize -= toconsume;
buffered -= toconsume;
p_head->i_buffer -= toconsume;
p_head->p_buffer += toconsume;
if(p_head->i_buffer == 0)
inblockreadoffset += toconsume;
if(inblockreadoffset >= p_head->i_buffer)
{
block_t *next = p_head->p_next;
p_head->p_next = nullptr;
block_Release(p_head);
p_head = next;
if(next == nullptr)
pp_tail = &p_head;
p_read = p_read->p_next;
inblockreadoffset = 0;
}
}
......
......@@ -65,6 +65,8 @@ namespace adaptive
virtual size_t getBytesRead () const = 0;
};
using StorageID = std::string;
class AbstractChunkSource : public ChunkInterface
{
friend class AbstractConnectionManager;
......@@ -72,6 +74,7 @@ namespace adaptive
public:
const BytesRange & getBytesRange () const;
ChunkType getChunkType () const;
const StorageID & getStorageID () const;
virtual std::string getContentType () const override;
virtual RequestStatus getRequestStatus() const override;
virtual void recycle() = 0;
......@@ -79,6 +82,7 @@ namespace adaptive
protected:
AbstractChunkSource(ChunkType, const BytesRange & = BytesRange());
virtual ~AbstractChunkSource();
StorageID storeid;
ChunkType type;
RequestStatus requeststatus;
size_t contentLength;
......@@ -125,6 +129,7 @@ namespace adaptive
virtual void recycle() override;
static const size_t CHUNK_SIZE = 32768;
static StorageID makeStorageID(const std::string &, const BytesRange &);
protected:
HTTPChunkSource(const std::string &url, AbstractConnectionManager *,
......@@ -132,6 +137,7 @@ namespace adaptive
bool = false);
virtual bool prepare();
void setIdentifier(const std::string &, const BytesRange &);
AbstractConnection *connection;
AbstractConnectionManager *connManager;
mutable vlc::threads::mutex lock;
......@@ -158,6 +164,7 @@ namespace adaptive
virtual block_t * readBlock () override;
virtual block_t * read (size_t) override;
virtual bool hasMoreData () const override;
virtual void recycle() override;
protected:
HTTPChunkBufferedSource(const std::string &url, AbstractConnectionManager *,
......@@ -171,6 +178,8 @@ namespace adaptive
private:
block_t *p_head; /* read cache buffer */
block_t **pp_tail;
const block_t *p_read;
size_t inblockreadoffset;
size_t buffered; /* read cache size */
bool done;
bool eof;
......
......@@ -79,6 +79,8 @@ HTTPConnectionManager::HTTPConnectionManager (vlc_object_t *p_object_)
downloaderhp = new Downloader();
downloader->start();
downloaderhp->start();
cache_total = 0;
cache_max = 1 << 19;
}
HTTPConnectionManager::~HTTPConnectionManager ()
......@@ -162,12 +164,24 @@ AbstractChunkSource *HTTPConnectionManager::makeSource(const std::string &url,
const ID &id, ChunkType type,
const BytesRange &range)
{
StorageID storageid = HTTPChunkSource::makeStorageID(url, range);
switch(type)
{
case ChunkType::Init:
case ChunkType::Index:
for(HTTPChunkBufferedSource *s : cache)
{
if(s->getStorageID() == storageid)
{
cache.remove(s);
cache_total -= s->contentLength;
CacheDebug(msg_Dbg(p_object, "Cache GET '%s' usage %u bytes",
storageid.c_str(), cache_total));
return s;
}
}
// fallthrough
case ChunkType::Segment:
case ChunkType::Key:
case ChunkType::Playlist:
default:
......@@ -177,7 +191,41 @@ AbstractChunkSource *HTTPConnectionManager::makeSource(const std::string &url,
void HTTPConnectionManager::recycleSource(AbstractChunkSource *source)
{
deleteSource(source);
bool b_cacheable;
switch(source->getChunkType())
{
case ChunkType::Index:
case ChunkType::Init:
b_cacheable = true;
break;
case ChunkType::Key:
case ChunkType::Playlist:
case ChunkType::Segment:
default:
b_cacheable = false;
break;
}
HTTPChunkBufferedSource *buf = dynamic_cast<HTTPChunkBufferedSource *>(source);
if(buf && b_cacheable && !buf->getStorageID().empty() &&
buf->contentLength < cache_max)
{
while(cache_max < cache_total + buf->contentLength)
{
HTTPChunkBufferedSource *purged = cache.back();
cache.pop_back();
cache_total -= purged->contentLength;
CacheDebug(msg_Dbg(p_object, "Cache DEL '%s' usage %u bytes",
purged->getStorageID().c_str(), cache_total));
deleteSource(purged);
}
cache.push_front(buf);
cache_total += buf->contentLength;
CacheDebug(msg_Dbg(p_object, "Cache PUT '%s' usage %u bytes",
buf->getStorageID().c_str(), cache_total));
}
else
deleteSource(source);
}
Downloader * HTTPConnectionManager::getDownloadQueue(const AbstractChunkSource *source) const
......
......@@ -43,6 +43,7 @@ namespace adaptive
class AbstractConnection;
class Downloader;
class AbstractChunkSource;
class HTTPChunkBufferedSource;
enum class ChunkType;
class AbstractConnectionManager : public IDownloadRateObserver
......@@ -100,6 +101,9 @@ namespace adaptive
bool localAllowed;
AbstractConnection * reuseConnection(ConnectionParams &);
Downloader * getDownloadQueue(const AbstractChunkSource *) const;
std::list<HTTPChunkBufferedSource *> cache;
unsigned cache_total;
unsigned cache_max;
};
}
}
......
......@@ -48,7 +48,6 @@ BaseRepresentation::BaseRepresentation( BaseAdaptationSet *set ) :
adaptationSet ( set ),
bandwidth (0)
{
b_consistent = true;
}
BaseRepresentation::~BaseRepresentation ()
......@@ -112,6 +111,8 @@ void BaseRepresentation::getCodecsDesc(CodecDescriptionList *desc) const
CodecDescription *dsc = makeCodecDescription(*it);
dsc->setDescription(adaptationSet->description.Get());
dsc->setLanguage(adaptationSet->getLang());
if(getWidth() > 0 && getHeight() > 0)
dsc->setDimensions(getWidth(), getHeight());
desc->push_back(dsc);
}
}
......@@ -142,9 +143,9 @@ void BaseRepresentation::scheduleNextUpdate(uint64_t, bool)
}
bool BaseRepresentation::consistentSegmentNumber() const
bool BaseRepresentation::canNoLongerUpdate() const
{
return b_consistent;
return false;
}
void BaseRepresentation::pruneByPlaybackTime(vlc_tick_t time)
......@@ -201,11 +202,8 @@ bool BaseRepresentation::validateCodec(const std::string &) const
return true;
}
uint64_t BaseRepresentation::translateSegmentNumber(uint64_t num, const BaseRepresentation *from) const
uint64_t BaseRepresentation::translateSegmentNumber(uint64_t num, const BaseRepresentation *) const
{
vlc_tick_t time, duration;
if( from->getPlaybackTimeDurationBySegmentNumber(num, &time, &duration) )
getSegmentNumberByTime(time, &num);
return num;
}
......
......@@ -63,7 +63,6 @@ namespace adaptive
const std::list<std::string> & getCodecs () const;
void addCodecs (const std::string &);
void getCodecsDesc (CodecDescriptionList *) const;
bool consistentSegmentNumber () const;
virtual void pruneByPlaybackTime (vlc_tick_t) override;
virtual vlc_tick_t getMinAheadTime (uint64_t) const;
......@@ -71,6 +70,7 @@ namespace adaptive
virtual bool needsIndex () const;
virtual bool runLocalUpdates (SharedResources *);
virtual void scheduleNextUpdate (uint64_t, bool);
virtual bool canNoLongerUpdate () const;
virtual void debug (vlc_object_t *,int = 0) const;
......@@ -93,7 +93,6 @@ namespace adaptive
BaseAdaptationSet *adaptationSet;
uint64_t bandwidth;
std::list<std::string> codecs;
bool b_consistent;
};
}
}
......
......@@ -50,6 +50,14 @@ const es_format_t * CodecDescription::getFmt() const
return &fmt;
}
void CodecDescription::setDimensions(unsigned w, unsigned h)
{
if(fmt.i_cat != VIDEO_ES || !w || !h)
return;
fmt.video.i_visible_width = w;
fmt.video.i_visible_height = h;
}
void CodecDescription::setDescription(const std::string &d)
{
free(fmt.psz_description);
......
......@@ -38,6 +38,7 @@ namespace adaptive
void operator=(const CodecDescription&) = delete;
virtual ~CodecDescription();
const es_format_t *getFmt() const;
void setDimensions(unsigned, unsigned);
void setDescription(const std::string &);
void setLanguage(const std::string &);
void setAspectRatio(const AspectRatio &);
......
......@@ -31,6 +31,7 @@
#include "BaseRepresentation.h"
#include "BasePlaylist.hpp"
#include "SegmentChunk.hpp"
#include "../SharedResources.hpp"
#include "../http/BytesRange.hpp"
#include "../http/HTTPConnectionManager.h"
#include "../http/Downloader.hpp"
......@@ -48,6 +49,7 @@ ISegment::ISegment(const ICanonicalUrl *parent):
startTime.Set(0);
duration.Set(0);
sequence = 0;
discontinuitySequenceNumber = std::numeric_limits<uint64_t>::max();
templated = false;
discontinuity = false;
displayTime = VLC_TICK_INVALID;
......@@ -75,8 +77,7 @@ bool ISegment::prepareChunk(SharedResources *res, SegmentChunk *chunk, BaseRepre
return true;
}
SegmentChunk* ISegment::toChunk(SharedResources *res, AbstractConnectionManager *connManager,
size_t index, BaseRepresentation *rep)
SegmentChunk* ISegment::toChunk(SharedResources *res, size_t index, BaseRepresentation *rep)
{
const std::string url = getUrlSegment().toString(index, rep);
BytesRange range;
......@@ -89,7 +90,7 @@ SegmentChunk* ISegment::toChunk(SharedResources *res, AbstractConnectionManager
chunkType = ChunkType::Index;
else
chunkType = ChunkType::Segment;
AbstractChunkSource *source = connManager->makeSource(url,
AbstractChunkSource *source = res->getConnManager()->makeSource(url,
rep->getAdaptationSet()->getID(),
chunkType,
range);
......@@ -100,17 +101,18 @@ SegmentChunk* ISegment::toChunk(SharedResources *res, AbstractConnectionManager
{
chunk->sequence = index;
chunk->discontinuity = discontinuity;
chunk->discontinuitySequenceNumber = getDiscontinuitySequenceNumber();
if(!prepareChunk(res, chunk, rep))
{
delete chunk;
return nullptr;
}
connManager->start(source);
res->getConnManager()->start(source);
return chunk;
}
else
{
connManager->recycleSource(source);
res->getConnManager()->recycleSource(source);
}
}
return nullptr;
......@@ -137,6 +139,16 @@ uint64_t ISegment::getSequenceNumber() const
return sequence;
}
void ISegment::setDiscontinuitySequenceNumber(uint64_t seq)
{
discontinuitySequenceNumber = seq;
}
uint64_t ISegment::getDiscontinuitySequenceNumber() const
{
return discontinuitySequenceNumber;
}
size_t ISegment::getOffset() const
{
return startByte;
......@@ -153,6 +165,12 @@ void ISegment::debug(vlc_object_t *obj, int indent) const
if(startTime.Get() > 0)
ss << " stime " << startTime.Get();
ss << " duration " << duration.Get();
if(discontinuity)
{
ss << " dty";
if(discontinuitySequenceNumber != std::numeric_limits<uint64_t>::max())
ss << "#" << discontinuitySequenceNumber;
}
msg_Dbg(obj, "%s", ss.str().c_str());
}
......@@ -164,29 +182,6 @@ bool ISegment::contains(size_t byte) const
(!endByte || byte <= endByte) );
}
int ISegment::compare(ISegment *other) const
{
if(duration.Get())
{
if(startTime.Get() > other->startTime.Get())
return 1;
else if(startTime.Get() < other->startTime.Get())
return -1;
}
if(startByte > other->startByte)
return 1;
else if(startByte < other->startByte)
return -1;
if(endByte > other->endByte)
return 1;
else if(endByte < other->endByte)
return -1;
return 0;
}
void ISegment::setEncryption(CommonEncryption &e)
{
encryption = e;
......
......@@ -38,11 +38,6 @@ namespace adaptive
{
class SharedResources;
namespace http
{
class AbstractConnectionManager;
}
namespace playlist
{
class BaseRepresentation;
......@@ -63,17 +58,17 @@ namespace adaptive
* That is basically true when using an Url, and false
* when using an UrlTemplate
*/
virtual SegmentChunk* toChunk (SharedResources *, AbstractConnectionManager *,
size_t, BaseRepresentation *);
virtual SegmentChunk* toChunk (SharedResources *, size_t, BaseRepresentation *);
virtual SegmentChunk* createChunk (AbstractChunkSource *, BaseRepresentation *) = 0;
virtual void setByteRange (size_t start, size_t end);
virtual void setSequenceNumber(uint64_t);
virtual uint64_t getSequenceNumber() const;
virtual void setDiscontinuitySequenceNumber(uint64_t);
virtual uint64_t getDiscontinuitySequenceNumber() const;
virtual bool isTemplate () const;
virtual size_t getOffset () const;
virtual void debug (vlc_object_t *,int = 0) const;
virtual bool contains (size_t byte) const;
virtual int compare (ISegment *) const;
void setEncryption (CommonEncryption &);
void setDisplayTime (vlc_tick_t);
vlc_tick_t getDisplayTime () const;
......@@ -91,6 +86,7 @@ namespace adaptive
std::string debugName;
bool templated;
uint64_t sequence;
uint64_t discontinuitySequenceNumber;
vlc_tick_t displayTime;
};
......