else
return CLOCK_FREQ * mpd->getDuration();
}
+
+bool DASHManager::setPosition(mtime_t time)
+{
+ bool ret = true;
+ for(int real = 0; real < 2; real++)
+ {
+ /* Always probe if we can seek first */
+ for(int type=0; type<Streams::count; type++)
+ {
+ if(!streams[type])
+ continue;
+ ret &= streams[type]->setPosition(time, !real);
+ }
+ if(!ret)
+ break;
+ }
+ return ret;
+}
+
+bool DASHManager::seekAble() const
+{
+ for(int type=0; type<Streams::count; type++)
+ {
+ if(!streams[type])
+ continue;
+ if(!streams[type]->seekAble())
+ return false;
+ }
+ return true;
+}
mtime_t getPCR() const;
int getGroup() const;
int esCount() const;
+ bool setPosition(mtime_t);
+ bool seekAble() const;
private:
http::HTTPConnectionManager *conManager;
return chunk;
}
+
+bool SegmentTracker::setPosition(mtime_t time, bool tryonly)
+{
+ uint64_t segcount;
+ if(prevRepresentation &&
+ prevRepresentation->getSegmentNumberByTime(time, &segcount))
+ {
+ if(!tryonly)
+ count = segcount;
+ return true;
+ }
+ return false;
+}
void setAdaptationLogic(logic::AbstractAdaptationLogic *);
void resetCounter();
http::Chunk* getNextChunk(Streams::Type);
+ bool setPosition(mtime_t, bool);
private:
bool initializing;
return currentChunk;
}
+bool Stream::seekAble() const
+{
+ return (output && output->seekAble());
+}
+
size_t Stream::read(HTTPConnectionManager *connManager)
{
Chunk *chunk = getChunk();
return readsize;
}
+bool Stream::setPosition(mtime_t time, bool tryonly)
+{
+ bool ret = segmentTracker->setPosition(time, tryonly);
+ if(!tryonly && ret)
+ output->setPosition(time);
+ return ret;
+}
+
AbstractStreamOutput::AbstractStreamOutput(demux_t *demux)
{
realdemux = demux;
pcr = VLC_TS_0;
group = -1;
escount = 0;
+ seekable = true;
fakeesout = new es_out_t;
if (!fakeesout)
stream_DemuxSend(demuxstream, block);
}
+bool AbstractStreamOutput::seekAble() const
+{
+ return (demuxstream && seekable);
+}
+
+void AbstractStreamOutput::setPosition(mtime_t nztime)
+{
+ es_out_Control(realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
+ VLC_TS_0 + nztime);
+}
+
/* Static callbacks */
es_out_id_t * AbstractStreamOutput::esOutAdd(es_out_t *fakees, const es_format_t *p_fmt)
{
mtime_t getPCR() const;
int getGroup() const;
int esCount() const;
+ bool seekAble() const;
size_t read(http::HTTPConnectionManager *);
+ bool setPosition(mtime_t, bool);
private:
http::Chunk *getChunk();
mtime_t getPCR() const;
int getGroup() const;
int esCount() const;
+ bool seekAble() const;
+ void setPosition(mtime_t);
protected:
mtime_t pcr;
int escount;
es_out_t *fakeesout; /* to intercept/proxy what is sent from demuxstream */
stream_t *demuxstream;
+ bool seekable;
private:
demux_t *realdemux;
switch (i_query)
{
case DEMUX_CAN_SEEK:
- *(va_arg (args, bool *)) = false;
+ *(va_arg (args, bool *)) = p_sys->p_dashManager->seekAble();
break;
case DEMUX_CAN_CONTROL_PACE:
/ p_sys->p_dashManager->getDuration();
break;
+ case DEMUX_SET_POSITION:
+ if(!p_sys->p_dashManager->getDuration() ||
+ !p_sys->p_dashManager->setPosition( p_sys->p_dashManager->getDuration() * va_arg(args, double)))
+ return VLC_EGENERIC;
+ break;
+
+ case DEMUX_SET_TIME:
+ if(!p_sys->p_dashManager->setPosition(va_arg(args, int64_t)))
+ return VLC_EGENERIC;
+ break;
+
case DEMUX_GET_PTS_DELAY:
*va_arg (args, int64_t *) = INT64_C(1000) *
var_InheritInteger(p_demux, "network-caching");
if(segListNode->hasAttribute("duration"))
list->setDuration(Integer<mtime_t>(segListNode->getAttributeValue("duration")));
+ if(segListNode->hasAttribute("timescale"))
+ list->timescale.Set(Integer<uint64_t>(segListNode->getAttributeValue("timescale")));
+
std::vector<Node *>::const_iterator it;
for(it = segments.begin(); it != segments.end(); it++)
{
delete segmentTemplate[i];
}
-vector<ISegment *> SegmentInformation::getSegments() const
+vector<ISegment *> SegmentInformation::getSegments(SegmentInfoType type) const
{
vector<ISegment *> retSegments;
- SegmentList *segList = inheritSegmentList();
-
- /* init segments are always single segment */
- ISegment *segment = getSegment( INFOTYPE_INIT );
- if( segment )
- retSegments.push_back( segment );
-
- if( inheritSegmentTemplate(INFOTYPE_MEDIA) )
+ switch (type)
{
- retSegments.push_back( inheritSegmentTemplate(INFOTYPE_MEDIA) );
- }
- else if ( segList && !segList->getSegments().empty() )
- {
- std::vector<Segment *>::const_iterator it;
- for(it=segList->getSegments().begin();
- it!=segList->getSegments().end(); it++)
+ case INFOTYPE_INIT:
{
- std::vector<ISegment *> list = (*it)->subSegments();
- retSegments.insert( retSegments.end(), list.begin(), list.end() );
+ /* init segments are always single segment */
+ ISegment *segment = getSegment( INFOTYPE_INIT );
+ if( segment )
+ retSegments.push_back( segment );
+ }
+ break;
+
+ case INFOTYPE_MEDIA:
+ {
+ SegmentList *segList = inheritSegmentList();
+ if( inheritSegmentTemplate(INFOTYPE_MEDIA) )
+ {
+ retSegments.push_back( inheritSegmentTemplate(INFOTYPE_MEDIA) );
+ }
+ else if ( segList && !segList->getSegments().empty() )
+ {
+ std::vector<Segment *>::const_iterator it;
+ for(it=segList->getSegments().begin();
+ it!=segList->getSegments().end(); it++)
+ {
+ std::vector<ISegment *> list = (*it)->subSegments();
+ retSegments.insert( retSegments.end(), list.begin(), list.end() );
+ }
+ }
}
+
+ default:
+ break;
}
return retSegments;
}
+vector<ISegment *> SegmentInformation::getSegments() const
+{
+ vector<ISegment *> retSegments;
+ for(int i=0; i<InfoTypeCount; i++)
+ {
+ vector<ISegment *> segs = getSegments(static_cast<SegmentInfoType>(i));
+ retSegments.insert( retSegments.end(), segs.begin(), segs.end() );
+ }
+ return retSegments;
+}
+
ISegment * SegmentInformation::getSegment(SegmentInfoType type, uint64_t pos) const
{
SegmentBase *segBase = inheritSegmentBase();
return segment;
}
+bool SegmentInformation::getSegmentNumberByTime(mtime_t time, uint64_t *ret) const
+{
+ SegmentList *segList = inheritSegmentList();
+ if ( segList->getDuration() )
+ {
+ uint64_t timescale = segList->timescale.Get();
+ if(!timescale)
+ timescale = getTimescale();
+ *ret = time / (CLOCK_FREQ * segList->getDuration() / timescale);
+ return true;
+ }
+ return false;
+}
+
bool SegmentInformation::canBitswitch() const
{
if(bitswitch_policy == BITSWITCH_INHERIT)
SegmentInformation( SegmentInformation * = 0 );
explicit SegmentInformation( ICanonicalUrl * );
virtual ~SegmentInformation();
- std::vector<ISegment *> getSegments() const;
bool canBitswitch() const;
uint64_t getTimescale() const;
virtual mtime_t getPeriodStart() const;
static const int InfoTypeCount = INFOTYPE_INDEX + 1;
ISegment * getSegment(SegmentInfoType, uint64_t = 0) const;
+ bool getSegmentNumberByTime(mtime_t, uint64_t *) const;
+
+ protected:
+ std::vector<ISegment *> getSegments() const;
+ std::vector<ISegment *> getSegments(SegmentInfoType) const;
private:
void setSegmentList(SegmentList *);
SegmentList::SegmentList( ICanonicalUrl *parent ):
SegmentInfoCommon( parent )
{
-
+ timescale.Set(0);
}
SegmentList::~SegmentList()
{
#ifndef SEGMENTLIST_H_
#define SEGMENTLIST_H_
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include "mpd/SegmentInfoCommon.h"
#include "mpd/ICanonicalUrl.hpp"
+#include "Properties.hpp"
+
+#include <vlc_common.h>
namespace dash
{
const std::vector<Segment *>& getSegments() const;
void addSegment(Segment *seg);
+ Property<uint64_t> timescale;
+
private:
std::vector<Segment *> segments;
};