Commit 916065b0 authored by Francois Cartegnie's avatar Francois Cartegnie

demux: adaptative: merge restart & discontinuity states

And add implicit discontinuity on format change.
Use only tracker events to change state (will need to move currentchunk away)
parent dd9a9051
...@@ -22,16 +22,17 @@ ...@@ -22,16 +22,17 @@
#include "playlist/BaseRepresentation.h" #include "playlist/BaseRepresentation.h"
#include "playlist/BaseAdaptationSet.h" #include "playlist/BaseAdaptationSet.h"
#include "playlist/Segment.h" #include "playlist/Segment.h"
#include "playlist/SegmentChunk.hpp"
#include "logic/AbstractAdaptationLogic.h" #include "logic/AbstractAdaptationLogic.h"
using namespace adaptative; using namespace adaptative;
using namespace adaptative::logic; using namespace adaptative::logic;
using namespace adaptative::playlist; using namespace adaptative::playlist;
SegmentTrackerEvent::SegmentTrackerEvent(ISegment *s) SegmentTrackerEvent::SegmentTrackerEvent(SegmentChunk *s)
{ {
type = DISCONTINUITY; type = DISCONTINUITY;
u.discontinuity.s = s; u.discontinuity.sc = s;
} }
SegmentTrackerEvent::SegmentTrackerEvent(BaseRepresentation *prev, BaseRepresentation *next) SegmentTrackerEvent::SegmentTrackerEvent(BaseRepresentation *prev, BaseRepresentation *next)
...@@ -41,6 +42,12 @@ SegmentTrackerEvent::SegmentTrackerEvent(BaseRepresentation *prev, BaseRepresent ...@@ -41,6 +42,12 @@ SegmentTrackerEvent::SegmentTrackerEvent(BaseRepresentation *prev, BaseRepresent
u.switching.next = next; u.switching.next = next;
} }
SegmentTrackerEvent::SegmentTrackerEvent(const StreamFormat *fmt)
{
type = FORMATCHANGE;
u.format.f = fmt;
}
SegmentTracker::SegmentTracker(AbstractAdaptationLogic *logic_, BaseAdaptationSet *adaptSet) SegmentTracker::SegmentTracker(AbstractAdaptationLogic *logic_, BaseAdaptationSet *adaptSet)
{ {
count = 0; count = 0;
...@@ -50,6 +57,7 @@ SegmentTracker::SegmentTracker(AbstractAdaptationLogic *logic_, BaseAdaptationSe ...@@ -50,6 +57,7 @@ SegmentTracker::SegmentTracker(AbstractAdaptationLogic *logic_, BaseAdaptationSe
prevRepresentation = NULL; prevRepresentation = NULL;
setAdaptationLogic(logic_); setAdaptationLogic(logic_);
adaptationSet = adaptSet; adaptationSet = adaptSet;
format = StreamFormat::UNSUPPORTED;
} }
SegmentTracker::~SegmentTracker() SegmentTracker::~SegmentTracker()
...@@ -70,6 +78,7 @@ void SegmentTracker::reset() ...@@ -70,6 +78,7 @@ void SegmentTracker::reset()
init_sent = false; init_sent = false;
index_sent = false; index_sent = false;
initializing = true; initializing = true;
format = StreamFormat::UNSUPPORTED;
} }
SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionManager *connManager) SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionManager *connManager)
...@@ -98,6 +107,7 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM ...@@ -98,6 +107,7 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM
if ( rep == NULL ) if ( rep == NULL )
return NULL; return NULL;
if(rep != prevRepresentation) if(rep != prevRepresentation)
{ {
notify(SegmentTrackerEvent(prevRepresentation, rep)); notify(SegmentTrackerEvent(prevRepresentation, rep));
...@@ -129,11 +139,6 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM ...@@ -129,11 +139,6 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM
bool b_gap = false; bool b_gap = false;
segment = rep->getNextSegment(BaseRepresentation::INFOTYPE_MEDIA, count, &count, &b_gap); segment = rep->getNextSegment(BaseRepresentation::INFOTYPE_MEDIA, count, &count, &b_gap);
if(b_gap && count)
{
notify(SegmentTrackerEvent(segment));
}
if(!segment) if(!segment)
{ {
reset(); reset();
...@@ -147,6 +152,19 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM ...@@ -147,6 +152,19 @@ SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionM
if(chunk) if(chunk)
count++; count++;
/* We need to check segment/chunk format changes, as we can't rely on representation's (HLS)*/
if(format != chunk->getStreamFormat())
{
format = chunk->getStreamFormat();
notify(SegmentTrackerEvent(&format));
}
/* Handle both implicit and explicit discontinuities */
if( (b_gap && count) || (chunk && chunk->discontinuity) )
{
notify(SegmentTrackerEvent(chunk));
}
return chunk; return chunk;
} }
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef SEGMENTTRACKER_HPP #ifndef SEGMENTTRACKER_HPP
#define SEGMENTTRACKER_HPP #define SEGMENTTRACKER_HPP
#include <StreamFormat.hpp>
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif #endif
...@@ -44,7 +46,6 @@ namespace adaptative ...@@ -44,7 +46,6 @@ namespace adaptative
class BaseAdaptationSet; class BaseAdaptationSet;
class BaseRepresentation; class BaseRepresentation;
class SegmentChunk; class SegmentChunk;
class ISegment;
} }
using namespace playlist; using namespace playlist;
...@@ -54,24 +55,30 @@ namespace adaptative ...@@ -54,24 +55,30 @@ namespace adaptative
class SegmentTrackerEvent class SegmentTrackerEvent
{ {
public: public:
SegmentTrackerEvent(ISegment *); SegmentTrackerEvent(SegmentChunk *);
SegmentTrackerEvent(BaseRepresentation *, BaseRepresentation *); SegmentTrackerEvent(BaseRepresentation *, BaseRepresentation *);
SegmentTrackerEvent(const StreamFormat *);
enum enum
{ {
DISCONTINUITY, DISCONTINUITY,
SWITCHING, SWITCHING,
FORMATCHANGE,
} type; } type;
union union
{ {
struct struct
{ {
ISegment *s; SegmentChunk *sc;
} discontinuity; } discontinuity;
struct struct
{ {
BaseRepresentation *prev; BaseRepresentation *prev;
BaseRepresentation *next; BaseRepresentation *next;
} switching; } switching;
struct
{
const StreamFormat *f;
} format;
} u; } u;
}; };
...@@ -103,6 +110,7 @@ namespace adaptative ...@@ -103,6 +110,7 @@ namespace adaptative
bool index_sent; bool index_sent;
bool init_sent; bool init_sent;
uint64_t count; uint64_t count;
StreamFormat format;
AbstractAdaptationLogic *logic; AbstractAdaptationLogic *logic;
BaseAdaptationSet *adaptationSet; BaseAdaptationSet *adaptationSet;
BaseRepresentation *prevRepresentation; BaseRepresentation *prevRepresentation;
......
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
#include "Streams.hpp" #include "Streams.hpp"
#include "http/HTTPConnection.hpp" #include "http/HTTPConnection.hpp"
#include "http/HTTPConnectionManager.h" #include "http/HTTPConnectionManager.h"
#include "playlist/BaseRepresentation.h"
#include "playlist/SegmentChunk.hpp" #include "playlist/SegmentChunk.hpp"
#include "SegmentTracker.hpp"
#include "plumbing/SourceStream.hpp" #include "plumbing/SourceStream.hpp"
#include "plumbing/CommandsQueue.hpp" #include "plumbing/CommandsQueue.hpp"
#include "tools/Debug.hpp" #include "tools/Debug.hpp"
...@@ -39,7 +39,6 @@ AbstractStream::AbstractStream(demux_t * demux_, const StreamFormat &format_) ...@@ -39,7 +39,6 @@ AbstractStream::AbstractStream(demux_t * demux_, const StreamFormat &format_)
dead = false; dead = false;
disabled = false; disabled = false;
flushing = false; flushing = false;
restarting_output = false;
discontinuity = false; discontinuity = false;
segmentTracker = NULL; segmentTracker = NULL;
pcr = VLC_TS_INVALID; pcr = VLC_TS_INVALID;
...@@ -79,6 +78,7 @@ AbstractStream::~AbstractStream() ...@@ -79,6 +78,7 @@ AbstractStream::~AbstractStream()
void AbstractStream::bind(SegmentTracker *tracker, HTTPConnectionManager *conn) void AbstractStream::bind(SegmentTracker *tracker, HTTPConnectionManager *conn)
{ {
segmentTracker = tracker; segmentTracker = tracker;
segmentTracker->registerListener(this);
connManager = conn; connManager = conn;
} }
...@@ -139,7 +139,6 @@ bool AbstractStream::seekAble() const ...@@ -139,7 +139,6 @@ bool AbstractStream::seekAble() const
{ {
return (demuxer && return (demuxer &&
!fakeesout->restarting() && !fakeesout->restarting() &&
!restarting_output &&
!discontinuity && !discontinuity &&
!flushing ); !flushing );
} }
...@@ -225,11 +224,10 @@ AbstractStream::status AbstractStream::demux(mtime_t nz_deadline, bool send) ...@@ -225,11 +224,10 @@ AbstractStream::status AbstractStream::demux(mtime_t nz_deadline, bool send)
if(!demuxer && !startDemux()) if(!demuxer && !startDemux())
{ {
/* If demux fails because of probing failure / wrong format*/ /* If demux fails because of probing failure / wrong format*/
if(restarting_output) if(discontinuity)
{ {
msg_Dbg( p_realdemux, "Flushing on format change" ); msg_Dbg( p_realdemux, "Flushing on format change" );
prepareFormatChange(); prepareFormatChange();
restarting_output = false;
discontinuity = false; discontinuity = false;
flushing = true; flushing = true;
return AbstractStream::status_buffering; return AbstractStream::status_buffering;
...@@ -243,11 +241,10 @@ AbstractStream::status AbstractStream::demux(mtime_t nz_deadline, bool send) ...@@ -243,11 +241,10 @@ AbstractStream::status AbstractStream::demux(mtime_t nz_deadline, bool send)
/* need to read, demuxer still buffering, ... */ /* need to read, demuxer still buffering, ... */
if(demuxer->demux(nz_deadline) != VLC_DEMUXER_SUCCESS) if(demuxer->demux(nz_deadline) != VLC_DEMUXER_SUCCESS)
{ {
if(restarting_output || discontinuity) if(discontinuity)
{ {
msg_Dbg( p_realdemux, "Flushing on discontinuity" ); msg_Dbg( p_realdemux, "Flushing on discontinuity" );
prepareFormatChange(); prepareFormatChange();
restarting_output = false;
discontinuity = false; discontinuity = false;
flushing = true; flushing = true;
return AbstractStream::status_buffering; return AbstractStream::status_buffering;
...@@ -281,35 +278,19 @@ AbstractStream::status AbstractStream::demux(mtime_t nz_deadline, bool send) ...@@ -281,35 +278,19 @@ AbstractStream::status AbstractStream::demux(mtime_t nz_deadline, bool send)
block_t * AbstractStream::readNextBlock(size_t toread) block_t * AbstractStream::readNextBlock(size_t toread)
{ {
if (currentChunk == NULL) if (currentChunk == NULL && !eof)
{ currentChunk = segmentTracker->getNextChunk(!fakeesout->restarting(), connManager);
if(!eof)
currentChunk = segmentTracker->getNextChunk(!fakeesout->restarting(), connManager);
if (currentChunk == NULL)
{
eof = true;
return NULL;
}
}
if(format != currentChunk->getStreamFormat()) if(discontinuity)
{ {
/* Force stream to end for this call */ msg_Info(p_realdemux, "Encountered discontinuity");
msg_Info(p_realdemux, "Changing stream format %u->%u", /* Force stream/demuxer to end for this call */
(unsigned)format, (unsigned)currentChunk->getStreamFormat());
restarting_output = true;
format = currentChunk->getStreamFormat();
/* Next stream will use current unused chunk */
return NULL; return NULL;
} }
if(currentChunk->discontinuity) if(currentChunk == NULL)
{ {
discontinuity = true; eof = true;
currentChunk->discontinuity = false;
msg_Info(p_realdemux, "Encountered discontinuity");
return NULL; return NULL;
} }
...@@ -387,3 +368,30 @@ void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const ...@@ -387,3 +368,30 @@ void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const
p_fmt->psz_description = strdup(description.c_str()); p_fmt->psz_description = strdup(description.c_str());
} }
void AbstractStream::trackerEvent(const SegmentTrackerEvent &event)
{
switch(event.type)
{
case SegmentTrackerEvent::DISCONTINUITY:
discontinuity = true;
break;
case SegmentTrackerEvent::FORMATCHANGE:
/* Check if our current demux is still valid */
if(*event.u.format.f != format)
{
/* Format has changed between segments, we need to drain and change demux */
msg_Info(p_realdemux, "Changing stream format %u->%u",
(unsigned)format, (unsigned)*event.u.format.f);
format = *event.u.format.f;
/* This is an implict discontinuity */
discontinuity = true;
}
break;
case SegmentTrackerEvent::SWITCHING:
default:
break;
}
}
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <vlc_common.h> #include <vlc_common.h>
#include "StreamFormat.hpp" #include "StreamFormat.hpp"
#include "ChunksSource.hpp" #include "ChunksSource.hpp"
#include "SegmentTracker.hpp"
#include "plumbing/Demuxer.hpp" #include "plumbing/Demuxer.hpp"
#include "plumbing/SourceStream.hpp" #include "plumbing/SourceStream.hpp"
...@@ -52,7 +53,8 @@ namespace adaptative ...@@ -52,7 +53,8 @@ namespace adaptative
using namespace playlist; using namespace playlist;
class AbstractStream : public ChunksSource, class AbstractStream : public ChunksSource,
public ExtraFMTInfoInterface public ExtraFMTInfoInterface,
public SegmentTrackerListenerInterface
{ {
public: public:
AbstractStream(demux_t *, const StreamFormat &); AbstractStream(demux_t *, const StreamFormat &);
...@@ -80,6 +82,7 @@ namespace adaptative ...@@ -80,6 +82,7 @@ namespace adaptative
virtual block_t *readNextBlock(size_t); /* impl */ virtual block_t *readNextBlock(size_t); /* impl */
virtual void fillExtraFMTInfo( es_format_t * ) const; /* impl */ virtual void fillExtraFMTInfo( es_format_t * ) const; /* impl */
virtual void trackerEvent(const SegmentTrackerEvent &); /* impl */
protected: protected:
virtual block_t *checkBlock(block_t *, bool) = 0; virtual block_t *checkBlock(block_t *, bool) = 0;
...@@ -89,7 +92,6 @@ namespace adaptative ...@@ -89,7 +92,6 @@ namespace adaptative
virtual void prepareFormatChange(); virtual void prepareFormatChange();
bool restarting_output;
bool discontinuity; bool discontinuity;
Demuxer *syncdemux; Demuxer *syncdemux;
......
...@@ -120,13 +120,13 @@ block_t * HLSStream::checkBlock(block_t *p_block, bool b_first) ...@@ -120,13 +120,13 @@ block_t * HLSStream::checkBlock(block_t *p_block, bool b_first)
return p_block; return p_block;
} }
AbstractStream * HLSStreamFactory::create(demux_t *realdemux, const StreamFormat &format, AbstractStream * HLSStreamFactory::create(demux_t *realdemux, const StreamFormat &,
SegmentTracker *tracker, HTTPConnectionManager *manager) const SegmentTracker *tracker, HTTPConnectionManager *manager) const
{ {
HLSStream *stream; HLSStream *stream;
try try
{ {
stream = new HLSStream(realdemux, format); stream = new HLSStream(realdemux, StreamFormat(StreamFormat::UNKNOWN));
} catch (int) { } catch (int) {
return NULL; return NULL;
} }
......
...@@ -91,7 +91,8 @@ void Representation::debug(vlc_object_t *obj, int indent) const ...@@ -91,7 +91,8 @@ void Representation::debug(vlc_object_t *obj, int indent) const
if(!b_loaded) if(!b_loaded)
{ {
std::string text(indent + 1, ' '); std::string text(indent + 1, ' ');
text.append(" (not loaded)"); text.append(" (not loaded) ");
text.append(getStreamFormat().str());
msg_Dbg(obj, "%s", text.c_str()); msg_Dbg(obj, "%s", text.c_str());
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment