demux: dash: add basic seeking using next segment
authorFrancois Cartegnie <fcvlcdev@free.fr>
Thu, 1 Jan 2015 15:47:05 +0000 (16:47 +0100)
committerFrancois Cartegnie <fcvlcdev@free.fr>
Fri, 2 Jan 2015 14:38:44 +0000 (15:38 +0100)
Still doesn't control streamDemux

12 files changed:
modules/demux/dash/DASHManager.cpp
modules/demux/dash/DASHManager.h
modules/demux/dash/SegmentTracker.cpp
modules/demux/dash/SegmentTracker.hpp
modules/demux/dash/Streams.cpp
modules/demux/dash/Streams.hpp
modules/demux/dash/dash.cpp
modules/demux/dash/mpd/IsoffMainParser.cpp
modules/demux/dash/mpd/SegmentInformation.cpp
modules/demux/dash/mpd/SegmentInformation.hpp
modules/demux/dash/mpd/SegmentList.cpp
modules/demux/dash/mpd/SegmentList.h

index b3085fb..f60e647 100644 (file)
@@ -156,3 +156,33 @@ mtime_t DASHManager::getDuration() const
     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;
+}
index f0f4ed3..b2fc7e3 100644 (file)
@@ -44,6 +44,8 @@ namespace dash
             mtime_t getPCR() const;
             int     getGroup() const;
             int     esCount() const;
+            bool    setPosition(mtime_t);
+            bool    seekAble() const;
 
         private:
             http::HTTPConnectionManager         *conManager;
index 347083d..8559dc4 100644 (file)
@@ -95,3 +95,16 @@ Chunk * SegmentTracker::getNextChunk(Streams::Type type)
 
     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;
+}
index c545362..d76d525 100644 (file)
@@ -56,6 +56,7 @@ namespace dash
             void setAdaptationLogic(logic::AbstractAdaptationLogic *);
             void resetCounter();
             http::Chunk* getNextChunk(Streams::Type);
+            bool setPosition(mtime_t, bool);
 
         private:
             bool initializing;
index fcabd63..9e2ac47 100644 (file)
@@ -141,6 +141,11 @@ Chunk * Stream::getChunk()
     return currentChunk;
 }
 
+bool Stream::seekAble() const
+{
+    return (output && output->seekAble());
+}
+
 size_t Stream::read(HTTPConnectionManager *connManager)
 {
     Chunk *chunk = getChunk();
@@ -210,6 +215,14 @@ size_t Stream::read(HTTPConnectionManager *connManager)
     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;
@@ -217,6 +230,7 @@ AbstractStreamOutput::AbstractStreamOutput(demux_t *demux)
     pcr = VLC_TS_0;
     group = -1;
     escount = 0;
+    seekable = true;
 
     fakeesout = new es_out_t;
     if (!fakeesout)
@@ -257,6 +271,17 @@ void AbstractStreamOutput::pushBlock(block_t *block)
     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)
 {
index 445640a..10404f4 100644 (file)
@@ -53,7 +53,9 @@ namespace dash
                 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();
@@ -77,6 +79,8 @@ namespace dash
                 mtime_t getPCR() const;
                 int getGroup() const;
                 int esCount() const;
+                bool seekAble() const;
+                void setPosition(mtime_t);
 
             protected:
                 mtime_t   pcr;
@@ -84,6 +88,7 @@ namespace dash
                 int       escount;
                 es_out_t *fakeesout; /* to intercept/proxy what is sent from demuxstream */
                 stream_t *demuxstream;
+                bool      seekable;
 
             private:
                 demux_t  *realdemux;
index 23431dd..924e1f8 100644 (file)
@@ -195,7 +195,7 @@ static int  Control         (demux_t *p_demux, int i_query, va_list args)
     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:
@@ -222,6 +222,17 @@ static int  Control         (demux_t *p_demux, int i_query, va_list args)
                                          / 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");
index 9271e41..ed5aea8 100644 (file)
@@ -280,6 +280,9 @@ size_t IsoffMainParser::parseSegmentList(Node * segListNode, SegmentInformation
             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++)
             {
index 7d26f69..53ff8c7 100644 (file)
@@ -59,35 +59,58 @@ SegmentInformation::~SegmentInformation()
         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();
@@ -134,6 +157,20 @@ ISegment * SegmentInformation::getSegment(SegmentInfoType type, uint64_t pos) co
     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)
index 4240068..c72ee6a 100644 (file)
@@ -48,7 +48,6 @@ namespace dash
                 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;
@@ -70,6 +69,11 @@ namespace dash
                 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 *);
index 9af77d7..87c7bcd 100644 (file)
@@ -34,7 +34,7 @@ using namespace dash::mpd;
 SegmentList::SegmentList( ICanonicalUrl *parent ):
     SegmentInfoCommon( parent )
 {
-
+    timescale.Set(0);
 }
 SegmentList::~SegmentList()
 {
index b081bbc..8e685e0 100644 (file)
 #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
 {
@@ -41,6 +48,8 @@ namespace dash
                 const std::vector<Segment *>&   getSegments() const;
                 void                    addSegment(Segment *seg);
 
+                Property<uint64_t> timescale;
+
             private:
                 std::vector<Segment *>  segments;
         };