[vlc-commits] demux: adaptive: rework attributes inheritance to match siblings first

Francois Cartegnie git at videolan.org
Fri Nov 27 11:23:28 CET 2020


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Tue Oct 27 11:24:56 2020 +0100| [573752cfad0e024806e29ccef23986aaff0166db] | committer: Francois Cartegnie

demux: adaptive: rework attributes inheritance to match siblings first

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=573752cfad0e024806e29ccef23986aaff0166db
---

 modules/demux/adaptive/logic/BufferingLogic.cpp    |   7 +-
 .../demux/adaptive/playlist/AbstractPlaylist.cpp   |  23 +--
 .../demux/adaptive/playlist/AbstractPlaylist.hpp   |  12 +-
 .../demux/adaptive/playlist/BaseRepresentation.cpp |   3 +-
 modules/demux/adaptive/playlist/Inheritables.cpp   | 228 ++++++++++++++++++++-
 modules/demux/adaptive/playlist/Inheritables.hpp   | 104 +++++++++-
 modules/demux/adaptive/playlist/SegmentBase.cpp    |   3 +-
 .../demux/adaptive/playlist/SegmentBaseType.cpp    | 105 +---------
 .../demux/adaptive/playlist/SegmentBaseType.hpp    |  21 +-
 .../demux/adaptive/playlist/SegmentInformation.cpp | 138 ++++---------
 .../demux/adaptive/playlist/SegmentInformation.hpp |  18 +-
 modules/demux/adaptive/playlist/SegmentList.cpp    |  17 +-
 modules/demux/adaptive/playlist/SegmentList.h      |   1 +
 .../demux/adaptive/playlist/SegmentTemplate.cpp    |  28 +--
 .../demux/adaptive/playlist/SegmentTimeline.cpp    |  37 +---
 modules/demux/adaptive/playlist/SegmentTimeline.h  |   4 +-
 modules/demux/dash/mp4/IndexReader.cpp             |   2 +-
 modules/demux/dash/mpd/IsoffMainParser.cpp         |  30 +--
 modules/demux/dash/mpd/Representation.cpp          |   4 +-
 modules/demux/hls/playlist/Parser.cpp              |   7 +-
 modules/demux/hls/playlist/Representation.cpp      |   4 +-
 modules/demux/smooth/mp4/IndexReader.cpp           |   2 +-
 modules/demux/smooth/playlist/Manifest.cpp         |   4 +-
 modules/demux/smooth/playlist/Manifest.hpp         |   5 +-
 modules/demux/smooth/playlist/Parser.cpp           |  33 +--
 25 files changed, 471 insertions(+), 369 deletions(-)

diff --git a/modules/demux/adaptive/logic/BufferingLogic.cpp b/modules/demux/adaptive/logic/BufferingLogic.cpp
index a3db24368a..0fd79232cc 100644
--- a/modules/demux/adaptive/logic/BufferingLogic.cpp
+++ b/modules/demux/adaptive/logic/BufferingLogic.cpp
@@ -214,7 +214,8 @@ uint64_t DefaultBufferingLogic::getLiveStartSegmentNumber(BaseRepresentation *re
     {
         /* Else compute, current time and timeshiftdepth based */
         uint64_t start = 0;
-        if(mediaSegmentTemplate->duration.Get())
+        stime_t scaledduration = mediaSegmentTemplate->inheritDuration();
+        if(scaledduration)
         {
             /* Compute playback offset and effective finished segment from wall time */
             vlc_tick_t now = vlc_tick_from_sec(time(NULL));
@@ -224,7 +225,7 @@ uint64_t DefaultBufferingLogic::getLiveStartSegmentNumber(BaseRepresentation *re
             const Timescale timescale = mediaSegmentTemplate->inheritTimescale();
             if(!timescale)
                 return startnumber;
-            const vlc_tick_t duration = timescale.ToTime(mediaSegmentTemplate->inheritDuration());
+            const vlc_tick_t duration = timescale.ToTime(scaledduration);
             if(!duration)
                 return startnumber;
 
@@ -336,6 +337,8 @@ uint64_t DefaultBufferingLogic::getLiveStartSegmentNumber(BaseRepresentation *re
             return segmentBase->getSequenceNumber();
 
         const Timescale timescale = rep->inheritTimescale();
+        if(!timeline->isValid())
+            return std::numeric_limits<uint64_t>::max();
         const Segment *back = list.back();
         const stime_t bufferingstart = back->startTime.Get() + back->duration.Get() -
                                        timescale.ToScaled(i_buffering);
diff --git a/modules/demux/adaptive/playlist/AbstractPlaylist.cpp b/modules/demux/adaptive/playlist/AbstractPlaylist.cpp
index cf1f930140..a1255431c7 100644
--- a/modules/demux/adaptive/playlist/AbstractPlaylist.cpp
+++ b/modules/demux/adaptive/playlist/AbstractPlaylist.cpp
@@ -34,7 +34,7 @@
 using namespace adaptive::playlist;
 
 AbstractPlaylist::AbstractPlaylist (vlc_object_t *p_object_) :
-    ICanonicalUrl(),
+    ICanonicalUrl(), AttrsNode(Type::PLAYLIST),
     p_object(p_object_)
 {
     playbackStart.Set(0);
@@ -71,28 +71,9 @@ void AbstractPlaylist::setPlaylistUrl(const std::string &url)
     playlistUrl = url;
 }
 
-void AbstractPlaylist::setAvailabilityTimeOffset(vlc_tick_t t)
-{
-    availabilityTimeOffset = t;
-}
-
-void AbstractPlaylist::setAvailabilityTimeComplete(bool b)
-{
-    availabilityTimeComplete = b;
-}
-
-vlc_tick_t AbstractPlaylist::getAvailabilityTimeOffset() const
-{
-    return availabilityTimeOffset.isSet() ? availabilityTimeOffset.value() : 0;
-}
-
-bool AbstractPlaylist::getAvailabilityTimeComplete() const
-{
-    return !availabilityTimeComplete.isSet() || availabilityTimeComplete.value();
-}
-
 void AbstractPlaylist::addPeriod(BasePeriod *period)
 {
+    period->setParentNode(this);
     periods.push_back(period);
 }
 
diff --git a/modules/demux/adaptive/playlist/AbstractPlaylist.hpp b/modules/demux/adaptive/playlist/AbstractPlaylist.hpp
index 3d0e3cf66d..f8c665941d 100644
--- a/modules/demux/adaptive/playlist/AbstractPlaylist.hpp
+++ b/modules/demux/adaptive/playlist/AbstractPlaylist.hpp
@@ -25,6 +25,7 @@
 #include <string>
 
 #include "ICanonicalUrl.hpp"
+#include "Inheritables.hpp"
 #include "../tools/Properties.hpp"
 
 namespace adaptive
@@ -34,7 +35,8 @@ namespace adaptive
     {
         class BasePeriod;
 
-        class AbstractPlaylist : public ICanonicalUrl
+        class AbstractPlaylist : public ICanonicalUrl,
+                                 public AttrsNode
         {
             public:
                 AbstractPlaylist(vlc_object_t *);
@@ -52,10 +54,6 @@ namespace adaptive
                 void    addPeriod               (BasePeriod *period);
                 void    addBaseUrl              (const std::string &);
                 void    setPlaylistUrl          (const std::string &);
-                void    setAvailabilityTimeOffset(vlc_tick_t);
-                void    setAvailabilityTimeComplete(bool);
-                vlc_tick_t getAvailabilityTimeOffset() const;
-                bool    getAvailabilityTimeComplete() const;
 
                 virtual Url         getUrlSegment() const; /* impl */
                 vlc_object_t *      getVLCObject()  const;
@@ -85,10 +83,6 @@ namespace adaptive
                 vlc_tick_t                          minBufferTime;
                 vlc_tick_t                          maxBufferTime;
                 bool                                b_needsUpdates;
-
-             private:
-                Undef<bool>                         availabilityTimeComplete;
-                Undef<vlc_tick_t>                   availabilityTimeOffset;
         };
     }
 }
diff --git a/modules/demux/adaptive/playlist/BaseRepresentation.cpp b/modules/demux/adaptive/playlist/BaseRepresentation.cpp
index e0529705e8..787be04cdd 100644
--- a/modules/demux/adaptive/playlist/BaseRepresentation.cpp
+++ b/modules/demux/adaptive/playlist/BaseRepresentation.cpp
@@ -215,7 +215,7 @@ bool BaseRepresentation::getMediaPlaybackRange(vlc_tick_t *rangeBegin,
             return true;
         }
         /* Else compute, current time and timeshiftdepth based */
-        else if( mediaSegmentTemplate->duration.Get() )
+        else if( mediaSegmentTemplate->inheritDuration() )
         {
             *rangeEnd = 0;
             *rangeBegin = -1 * getPlaylist()->timeShiftBufferDepth.Get();
@@ -229,7 +229,6 @@ bool BaseRepresentation::getMediaPlaybackRange(vlc_tick_t *rangeBegin,
     {
         const Timescale timescale = segmentList->inheritTimescale();
         const std::vector<Segment *> &list = segmentList->getSegments();
-
         const ISegment *back = list.back();
         const stime_t startTime = list.front()->startTime.Get();
         const stime_t endTime = back->startTime.Get() + back->duration.Get();
diff --git a/modules/demux/adaptive/playlist/Inheritables.cpp b/modules/demux/adaptive/playlist/Inheritables.cpp
index 4e938cbfe5..dfdf56c4c1 100644
--- a/modules/demux/adaptive/playlist/Inheritables.cpp
+++ b/modules/demux/adaptive/playlist/Inheritables.cpp
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * Inheritables.cpp
  *****************************************************************************
- * Copyright (C) 1998-2015 VLC authors and VideoLAN
+ * Copyright (C) 2016-2020 VideoLabs, VLC authors and VideoLAN
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -23,10 +23,236 @@
 #endif
 
 #include "Inheritables.hpp"
+#include "SegmentBase.h"
+#include "SegmentList.h"
+#include "SegmentTemplate.h"
+#include "SegmentTimeline.h"
+
+#include <algorithm>
 
 using namespace adaptive::playlist;
 using namespace adaptive;
 
+AbstractAttr::AbstractAttr(Type t)
+{
+    type = t;
+    parentNode = NULL;
+}
+
+AbstractAttr::~AbstractAttr()
+{
+
+}
+
+AbstractAttr::Type AbstractAttr::getType() const
+{
+    return type;
+}
+
+AttrsNode::AttrsNode(Type t, AttrsNode *parent_)
+    : AbstractAttr( t )
+{
+    setParentNode(parent_);
+    is_canonical_root = (t == SEGMENTINFORMATION);
+}
+
+AttrsNode::~AttrsNode()
+{
+    while(props.front())
+    {
+        delete props.front();
+        props.pop_front();
+    }
+}
+
+void AttrsNode::addAttribute(AbstractAttr *p)
+{
+    props.push_front(p);
+    p->setParentNode(this);
+}
+
+void AttrsNode::replaceAttribute(AbstractAttr *p)
+{
+    AbstractAttr *old = getAttribute(p->getType());
+    if(old)
+    {
+        props.remove(old);
+        delete old;
+    }
+    props.push_front(p);
+    p->setParentNode(this);
+}
+
+AbstractAttr * AttrsNode::inheritAttribute(AbstractAttr::Type type)
+{
+    AbstractAttr *p = getAttribute(type);
+    if(p && p->isValid())
+        return p;
+
+    /* List our path elements up to pseudo root node */
+    AttrsNode *rootNode;
+    std::list<AbstractAttr::Type> matchingpath;
+    for(rootNode = this; rootNode; rootNode = rootNode->parentNode)
+    {
+        if(rootNode->is_canonical_root)
+            break;
+        matchingpath.push_front(rootNode->getType());
+    }
+
+    if(rootNode && !matchingpath.empty())
+    {
+        /* Try matching at each sibling level */
+        for(;;)
+        {
+            /* Try same path on each sibling first */
+            for(AttrsNode *node = rootNode->parentNode; node; node = node->parentNode)
+            {
+                p = node->getAttribute(type, matchingpath);
+                if(p && p->isValid())
+                    return p;
+            }
+
+            matchingpath.pop_back();
+            if(matchingpath.empty())
+                break;
+        }
+    }
+
+    {
+        /* Just try anything below */
+        for(AttrsNode *node = this->parentNode; node ; node = node->parentNode)
+        {
+            p = node->getAttribute(type);
+            if(p && p->isValid())
+                return p;
+        }
+    }
+
+    return p;
+}
+
+AbstractAttr * AttrsNode::inheritAttribute(AbstractAttr::Type type) const
+{
+    return const_cast<AttrsNode *>(this)->inheritAttribute(type);
+}
+
+stime_t AttrsNode::inheritDuration() const
+{
+    const AbstractAttr *p = inheritAttribute(Type::DURATION);
+    if(p && p->isValid())
+        return (const stime_t &) *(static_cast<const DurationAttr *>(p));
+    return 0;
+}
+
+uint64_t AttrsNode::inheritStartNumber() const
+{
+    const AbstractAttr *p = inheritAttribute(Type::STARTNUMBER);
+    if(p && p->isValid())
+        return (const uint64_t &) *(static_cast<const StartnumberAttr *>(p));
+    return std::numeric_limits<uint64_t>::max();
+}
+
+Timescale AttrsNode::inheritTimescale() const
+{
+    const AbstractAttr *p = inheritAttribute(Type::TIMESCALE);
+    if(p && p->isValid())
+        return (Timescale) *(static_cast<const TimescaleAttr *>(p));
+    else
+        return Timescale(1);
+}
+
+vlc_tick_t AttrsNode::inheritAvailabilityTimeOffset() const
+{
+    const AbstractAttr *p = inheritAttribute(Type::AVAILABILITYTTIMEOFFSET);
+    if(p && p->isValid())
+        return (const vlc_tick_t &) *(static_cast<const AvailabilityTimeOffsetAttr *>(p));
+    return 0;
+}
+
+bool AttrsNode::inheritAvailabilityTimeComplete() const
+{
+    const AbstractAttr *p = inheritAttribute(Type::AVAILABILITYTTIMECOMPLETE);
+    if(p && p->isValid())
+        return (const bool &) *(static_cast<const AvailabilityTimeCompleteAttr *>(p));
+    return true;
+}
+
+SegmentBase * AttrsNode::inheritSegmentBase() const
+{
+    AbstractAttr *p = inheritAttribute(Type::SEGMENTBASE);
+    if(p && p->isValid())
+        return static_cast<SegmentBase *>(p);
+    return NULL;
+}
+
+SegmentList * AttrsNode::inheritSegmentList() const
+{
+    AbstractAttr *p = inheritAttribute(Type::SEGMENTLIST);
+    if(p && p->isValid())
+        return static_cast<SegmentList *> (p);
+    return NULL;
+}
+
+SegmentTemplate * AttrsNode::inheritSegmentTemplate() const
+{
+    AbstractAttr *p = inheritAttribute(Type::SEGMENTTEMPLATE);
+    if(p && p->isValid())
+        return static_cast<SegmentTemplate *> (p);
+    return NULL;
+}
+
+SegmentTimeline * AttrsNode::inheritSegmentTimeline() const
+{
+    AbstractAttr *p = inheritAttribute(Type::TIMELINE);
+    if(p && p->isValid())
+        return static_cast<SegmentTimeline *> (p);
+    return NULL;
+}
+
+AttrsNode * AttrsNode::matchPath(std::list<AbstractAttr::Type>&path)
+{
+    AttrsNode *pn = this;
+    std::list<AbstractAttr::Type>::const_iterator it;
+    for(it = path.begin(); it != path.end(); it++)
+    {
+        AbstractAttr *p = pn->getAttribute(*it);
+        if(!p || !p->isValid())
+            return NULL;
+        pn = dynamic_cast<AttrsNode *>(p);
+        if(pn == NULL)
+            return NULL;
+    }
+    return pn;
+}
+
+AbstractAttr * AttrsNode::getAttribute(AbstractAttr::Type type)
+{
+    for(auto it = props.begin(); it != props.end(); ++it)
+    {
+        if((*it)->getType() == type)
+            return *it;
+    }
+    return NULL;
+}
+
+AbstractAttr * AttrsNode::getAttribute(AbstractAttr::Type type) const
+{
+    return const_cast<AttrsNode *>(this)->getAttribute(type);
+}
+
+AbstractAttr * AttrsNode::getAttribute(AbstractAttr::Type type,
+                                           std::list<AbstractAttr::Type>&path)
+{
+    AttrsNode *matched = matchPath(path);
+    if(matched)
+    {
+        AbstractAttr *p = matched->getAttribute(type);
+        if(p && p->isValid())
+            return p;
+    }
+    return NULL;
+}
+
 TimescaleAble::TimescaleAble(TimescaleAble *parent)
 {
     parentTimescaleAble = parent;
diff --git a/modules/demux/adaptive/playlist/Inheritables.hpp b/modules/demux/adaptive/playlist/Inheritables.hpp
index 593391e056..8fa04f5ad8 100644
--- a/modules/demux/adaptive/playlist/Inheritables.hpp
+++ b/modules/demux/adaptive/playlist/Inheritables.hpp
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * Inheritables.hpp Nodes inheritables properties
  *****************************************************************************
- * Copyright (C) 1998-2015 VLC authors and VideoLAN
+ * Copyright (C) 2016-2020 VideoLabs, VLC authors and VideoLAN
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
@@ -20,7 +20,6 @@
 #ifndef INHERITABLES_H
 #define INHERITABLES_H
 
-#include "../tools/Properties.hpp"
 #include <list>
 #include <limits>
 #include <stdint.h>
@@ -30,6 +29,107 @@ namespace adaptive
 {
     namespace playlist
     {
+        class AttrsNode;
+        class SegmentTimeline;
+        class SegmentTemplate;
+        class SegmentList;
+        class SegmentBase;
+
+        class AbstractAttr
+        {
+            public:
+                enum Type
+                {
+                    NONE,
+                    PLAYLIST,
+                    SEGMENTINFORMATION,
+                    SEGMENTLIST,
+                    SEGMENTBASE,
+                    SEGMENTTEMPLATE,
+                    TIMESCALE,
+                    TIMELINE,
+                    DURATION,
+                    STARTNUMBER,
+                    AVAILABILITYTTIMEOFFSET,
+                    AVAILABILITYTTIMECOMPLETE,
+                };
+                AbstractAttr(enum Type);
+                virtual ~AbstractAttr();
+                Type getType() const;
+                bool operator ==(const AbstractAttr &t) const { return type == t.getType(); }
+                bool operator !=(const AbstractAttr &t) const { return type != t.getType(); }
+                virtual bool isValid() const { return true; }
+                void setParentNode(AttrsNode *n) { parentNode = n; }
+
+            protected:
+                Type type;
+                AttrsNode *parentNode;
+        };
+
+        class AttrsNode : public AbstractAttr
+        {
+            public:
+                AttrsNode( enum Type, AttrsNode * = NULL );
+                ~AttrsNode();
+                void addAttribute( AbstractAttr * );
+                void replaceAttribute( AbstractAttr * );
+                AbstractAttr * inheritAttribute(AbstractAttr::Type);
+                AbstractAttr * inheritAttribute(AbstractAttr::Type) const;
+                /* helpers */
+                uint64_t          inheritStartNumber() const;
+                stime_t           inheritDuration() const;
+                Timescale         inheritTimescale() const;
+                vlc_tick_t        inheritAvailabilityTimeOffset() const;
+                bool              inheritAvailabilityTimeComplete() const;
+                SegmentTimeline * inheritSegmentTimeline() const;
+                SegmentTemplate * inheritSegmentTemplate() const;
+                SegmentList *     inheritSegmentList() const;
+                SegmentBase *     inheritSegmentBase() const;
+
+            protected:
+                AttrsNode * matchPath(std::list<AbstractAttr::Type>&);
+                AbstractAttr * getAttribute(AbstractAttr::Type,
+                                            std::list<AbstractAttr::Type>&);
+                AbstractAttr * getAttribute(AbstractAttr::Type);
+                AbstractAttr * getAttribute(AbstractAttr::Type) const;
+                std::list<AbstractAttr *> props;
+                bool is_canonical_root;
+        };
+
+        template<enum AbstractAttr::Type e, typename T>
+        class AttrWrapper : public AbstractAttr
+        {
+            public:
+                AttrWrapper(T v) : AbstractAttr(e) { value = v; }
+                virtual ~AttrWrapper() {}
+                operator const T&() const { return value; }
+
+            protected:
+                T value;
+        };
+
+        typedef AttrWrapper<AbstractAttr::Type::AVAILABILITYTTIMEOFFSET, vlc_tick_t> AvailabilityTimeOffsetAttr;
+        typedef AttrWrapper<AbstractAttr::Type::AVAILABILITYTTIMECOMPLETE, bool>     AvailabilityTimeCompleteAttr;
+        typedef AttrWrapper<AbstractAttr::Type::STARTNUMBER, uint64_t>               StartnumberAttr;
+
+        class TimescaleAttr:
+                public AttrWrapper<AbstractAttr::Type::TIMESCALE, Timescale>
+        {
+            public:
+                TimescaleAttr(Timescale v) :
+                    AttrWrapper<AbstractAttr::Type::TIMESCALE, Timescale>( v ) {}
+                virtual bool isValid() const { return value.isValid(); }
+        };
+
+        class DurationAttr:
+                public AttrWrapper<AbstractAttr::Type::DURATION, stime_t>
+        {
+            public:
+                DurationAttr(stime_t v) :
+                    AttrWrapper<AbstractAttr::Type::DURATION, stime_t>( v ) {}
+                virtual bool isValid() const { return value > 0; }
+        };
+
         class TimescaleAble
         {
             public:
diff --git a/modules/demux/adaptive/playlist/SegmentBase.cpp b/modules/demux/adaptive/playlist/SegmentBase.cpp
index 16f3ff1c1f..b28dc72834 100644
--- a/modules/demux/adaptive/playlist/SegmentBase.cpp
+++ b/modules/demux/adaptive/playlist/SegmentBase.cpp
@@ -33,7 +33,8 @@
 using namespace adaptive::playlist;
 
 SegmentBase::SegmentBase(SegmentInformation *parent) :
-             Segment(parent), AbstractSegmentBaseType(parent)
+             Segment(parent),
+             AbstractSegmentBaseType(parent, AttrsNode::Type::SEGMENTBASE)
 {
     this->parent = parent;
 }
diff --git a/modules/demux/adaptive/playlist/SegmentBaseType.cpp b/modules/demux/adaptive/playlist/SegmentBaseType.cpp
index defc491041..1cc85fb474 100644
--- a/modules/demux/adaptive/playlist/SegmentBaseType.cpp
+++ b/modules/demux/adaptive/playlist/SegmentBaseType.cpp
@@ -65,8 +65,8 @@ uint64_t AbstractSegmentBaseType::findSegmentNumberByScaledTime(const std::vecto
     return s->getSequenceNumber();
 }
 
-AbstractSegmentBaseType::AbstractSegmentBaseType(SegmentInformation *parent)
-                : TimescaleAble(parent)
+AbstractSegmentBaseType::AbstractSegmentBaseType(SegmentInformation *parent, AttrsNode::Type t)
+                : AttrsNode(t, parent)
 {
     this->parent = parent;
 }
@@ -85,30 +85,6 @@ IndexSegment *AbstractSegmentBaseType::getIndexSegment() const
     return indexSegment.Get();
 }
 
-Timescale AbstractSegmentBaseType::inheritTimescale() const
-{
-    if(getTimescale().isValid())
-        return getTimescale();
-    if(parent)
-    {
-        if(parent->getTimescale().isValid())
-            return parent->getTimescale();
-        if(parent->getParent())
-        {
-            AbstractSegmentBaseType *bt =
-                dynamic_cast<AbstractSegmentBaseType *>(parent->getParent()->getProfile());
-            if(bt)
-                return bt->inheritTimescale();
-        }
-    }
-    return Timescale(1);
-}
-
-SegmentInformation *AbstractSegmentBaseType::getParent() const
-{
-    return parent;
-}
-
 void AbstractSegmentBaseType::debug(vlc_object_t *obj, int indent) const
 {
     if(initialisationSegment.Get())
@@ -117,84 +93,21 @@ void AbstractSegmentBaseType::debug(vlc_object_t *obj, int indent) const
         indexSegment.Get()->debug(obj, indent);
 }
 
-AbstractMultipleSegmentBaseType::AbstractMultipleSegmentBaseType(SegmentInformation *parent)
-                : AbstractSegmentBaseType(parent)
+AbstractMultipleSegmentBaseType::AbstractMultipleSegmentBaseType(SegmentInformation *parent,
+                                                                 AttrsNode::Type type)
+                : AbstractSegmentBaseType(parent, type)
 {
-    startNumber = std::numeric_limits<uint64_t>::max();
-    segmentTimeline = NULL;
-    duration.Set(0);
 }
 
 AbstractMultipleSegmentBaseType::~AbstractMultipleSegmentBaseType()
 {
-    delete segmentTimeline;
-}
-
-void AbstractMultipleSegmentBaseType::setSegmentTimeline( SegmentTimeline *v )
-{
-    delete segmentTimeline;
-    segmentTimeline = v;
-}
-
-SegmentTimeline * AbstractMultipleSegmentBaseType::inheritSegmentTimeline() const
-{
-    if( segmentTimeline )
-        return segmentTimeline;
-    const SegmentInformation *ulevel = parent ? parent->getParent() : NULL;
-    for( ; ulevel ; ulevel = ulevel->getParent() )
-    {
-        AbstractMultipleSegmentBaseType *bt =
-            dynamic_cast<AbstractMultipleSegmentBaseType *>(ulevel->getProfile());
-        if( bt && bt->segmentTimeline )
-            return bt->segmentTimeline;
-    }
-    return NULL;
-}
-
-SegmentTimeline * AbstractMultipleSegmentBaseType::getSegmentTimeline() const
-{
-    return segmentTimeline;
-}
-
-void AbstractMultipleSegmentBaseType::setStartNumber( uint64_t v )
-{
-    startNumber = v;
-}
-
-uint64_t AbstractMultipleSegmentBaseType::inheritStartNumber() const
-{
-    if( startNumber != std::numeric_limits<uint64_t>::max() )
-        return startNumber;
-
-    const SegmentInformation *ulevel = parent ? parent->getParent() : NULL;
-    for( ; ulevel ; ulevel = ulevel->parent )
-    {
-        AbstractMultipleSegmentBaseType *bt =
-            dynamic_cast<AbstractMultipleSegmentBaseType *>(ulevel->getProfile());
-        if( bt && bt->startNumber != std::numeric_limits<uint64_t>::max() )
-            return bt->startNumber;
-    }
-    return std::numeric_limits<uint64_t>::max();
-}
-
-stime_t AbstractMultipleSegmentBaseType::inheritDuration() const
-{
-    if(duration.Get() > 0)
-        return duration.Get();
-    const SegmentInformation *ulevel = parent ? parent->getParent() : NULL;
-    for( ; ulevel ; ulevel = ulevel->parent )
-    {
-        AbstractMultipleSegmentBaseType *bt =
-            dynamic_cast<AbstractMultipleSegmentBaseType *>(ulevel->getProfile());
-        if( bt && bt->duration.Get() > 0 )
-            return bt->duration.Get();
-    }
-    return 0;
 }
 
 void AbstractMultipleSegmentBaseType::updateWith(AbstractMultipleSegmentBaseType *updated,
                                                  bool)
 {
-    if(segmentTimeline && updated->segmentTimeline)
-        segmentTimeline->updateWith(*updated->segmentTimeline);
+    SegmentTimeline *local = static_cast<SegmentTimeline *>(getAttribute(Type::TIMELINE));
+    SegmentTimeline *other = static_cast<SegmentTimeline *>(updated->getAttribute(Type::TIMELINE));
+    if(local && other)
+        local->updateWith(*other);
 }
diff --git a/modules/demux/adaptive/playlist/SegmentBaseType.hpp b/modules/demux/adaptive/playlist/SegmentBaseType.hpp
index 89432bcd41..16c094b69d 100644
--- a/modules/demux/adaptive/playlist/SegmentBaseType.hpp
+++ b/modules/demux/adaptive/playlist/SegmentBaseType.hpp
@@ -34,10 +34,10 @@ namespace adaptive
 
         class AbstractSegmentBaseType : public Initializable<InitSegment>,
                                         public Indexable<IndexSegment>,
-                                        public TimescaleAble
+                                        public AttrsNode
         {
             public:
-                AbstractSegmentBaseType( SegmentInformation * );
+                AbstractSegmentBaseType( SegmentInformation *, AttrsNode::Type );
                 virtual ~AbstractSegmentBaseType();
 
                 virtual vlc_tick_t getMinAheadTime(uint64_t) const = 0;
@@ -51,15 +51,12 @@ namespace adaptive
                 virtual bool getPlaybackTimeDurationBySegmentNumber(uint64_t number,
                                                 vlc_tick_t *time, vlc_tick_t *duration) const = 0;
 
-                Timescale inheritTimescale() const; /* reimpl */
-
                 virtual void debug(vlc_object_t *, int = 0) const;
 
                 static Segment * findSegmentByScaledTime(const std::vector<Segment *> &,
                                                          stime_t);
                 static uint64_t findSegmentNumberByScaledTime(const std::vector<Segment *> &,
                                                              stime_t);
-                SegmentInformation * getParent() const;
 
             protected:
                 SegmentInformation *parent;
@@ -68,22 +65,10 @@ namespace adaptive
         class AbstractMultipleSegmentBaseType : public AbstractSegmentBaseType
         {
             public:
-                AbstractMultipleSegmentBaseType( SegmentInformation * );
+                AbstractMultipleSegmentBaseType( SegmentInformation *, AttrsNode::Type );
                 virtual ~AbstractMultipleSegmentBaseType();
 
-                void setSegmentTimeline( SegmentTimeline * );
-                SegmentTimeline * inheritSegmentTimeline() const;
-                SegmentTimeline * getSegmentTimeline() const;
-                void setStartNumber( uint64_t );
-                uint64_t inheritStartNumber() const;
-                stime_t inheritDuration() const;
                 virtual void updateWith(AbstractMultipleSegmentBaseType *, bool = false);
-                Property<stime_t>       duration;
-
-            protected:
-                uint64_t startNumber;
-                SegmentTimeline *segmentTimeline;
-
         };
     }
 }
diff --git a/modules/demux/adaptive/playlist/SegmentInformation.cpp b/modules/demux/adaptive/playlist/SegmentInformation.cpp
index faae1a7639..c4fe204783 100644
--- a/modules/demux/adaptive/playlist/SegmentInformation.cpp
+++ b/modules/demux/adaptive/playlist/SegmentInformation.cpp
@@ -39,7 +39,7 @@ using namespace adaptive::playlist;
 
 SegmentInformation::SegmentInformation(SegmentInformation *parent_) :
     ICanonicalUrl( parent_ ),
-    TimescaleAble( parent_ )
+    AttrsNode( AbstractAttr::SEGMENTINFORMATION, parent_ )
 {
     parent = parent_;
     init();
@@ -47,7 +47,7 @@ SegmentInformation::SegmentInformation(SegmentInformation *parent_) :
 
 SegmentInformation::SegmentInformation(AbstractPlaylist * parent_) :
     ICanonicalUrl(parent_),
-    TimescaleAble()
+    AttrsNode( AbstractAttr::SEGMENTINFORMATION, NULL )
 {
     parent = NULL;
     init();
@@ -56,16 +56,10 @@ SegmentInformation::SegmentInformation(AbstractPlaylist * parent_) :
 void SegmentInformation::init()
 {
     baseUrl.Set(NULL);
-    segmentBase = NULL;
-    segmentList = NULL;
-    mediaSegmentTemplate = NULL;
 }
 
 SegmentInformation::~SegmentInformation()
 {
-    delete segmentBase;
-    delete segmentList;
-    delete mediaSegmentTemplate;
     delete baseUrl.Get();
 }
 
@@ -136,11 +130,17 @@ SegmentInformation * SegmentInformation::getChildByID(const adaptive::ID &id)
 void SegmentInformation::updateWith(SegmentInformation *updated)
 {
     /* Support Segment List for now */
-    if(segmentList && updated->segmentList)
-        segmentList->updateWith(updated->segmentList);
+    AbstractAttr *p = getAttribute(Type::SEGMENTLIST);
+    if(p && p->isValid() && updated->getAttribute(Type::SEGMENTLIST))
+    {
+        inheritSegmentList()->updateWith(updated->inheritSegmentList());
+    }
 
-    if(mediaSegmentTemplate && updated->mediaSegmentTemplate)
-        mediaSegmentTemplate->updateWith(updated->mediaSegmentTemplate);
+    p = getAttribute(Type::SEGMENTTEMPLATE);
+    if(p && p->isValid() && updated->getAttribute(Type::SEGMENTTEMPLATE))
+    {
+        inheritSegmentTemplate()->updateWith(updated->inheritSegmentTemplate());
+    }
 
     std::vector<SegmentInformation *>::const_iterator it;
     for(it=childs.begin(); it!=childs.end(); ++it)
@@ -155,11 +155,13 @@ void SegmentInformation::updateWith(SegmentInformation *updated)
 
 void SegmentInformation::pruneByPlaybackTime(vlc_tick_t time)
 {
+    SegmentList *segmentList = static_cast<SegmentList *>(getAttribute(Type::SEGMENTLIST));
     if(segmentList)
         segmentList->pruneByPlaybackTime(time);
 
-    if(mediaSegmentTemplate)
-        mediaSegmentTemplate->pruneByPlaybackTime(time);
+    SegmentTemplate *templ = static_cast<SegmentTemplate *>(getAttribute(Type::SEGMENTTEMPLATE));
+    if(templ)
+        templ->pruneByPlaybackTime(time);
 
     std::vector<SegmentInformation *>::const_iterator it;
     for(it=childs.begin(); it!=childs.end(); ++it)
@@ -170,11 +172,13 @@ void SegmentInformation::pruneBySegmentNumber(uint64_t num)
 {
     assert(dynamic_cast<BaseRepresentation *>(this));
 
+    SegmentList *segmentList = static_cast<SegmentList *>(getAttribute(Type::SEGMENTLIST));
     if(segmentList)
         segmentList->pruneBySegmentNumber(num);
 
-    if(mediaSegmentTemplate)
-         mediaSegmentTemplate->pruneBySequenceNumber(num);
+    SegmentTemplate *templ = static_cast<SegmentTemplate *>(getAttribute(Type::SEGMENTTEMPLATE));
+    if(templ)
+        templ->pruneBySequenceNumber(num);
 }
 
 const CommonEncryption & SegmentInformation::intheritEncryption() const
@@ -205,25 +209,22 @@ vlc_tick_t SegmentInformation::getPeriodDuration() const
         return 0;
 }
 
-SegmentInformation * SegmentInformation::getParent() const
-{
-    return parent;
-}
-
 AbstractSegmentBaseType * SegmentInformation::getProfile() const
 {
-    if(mediaSegmentTemplate)
-        return mediaSegmentTemplate;
-    else if(segmentList)
-        return segmentList;
-    else if(segmentBase)
-        return segmentBase;
-    else
-        return NULL;
+    AbstractAttr *p;
+    if((p = getAttribute(Type::SEGMENTTEMPLATE)))
+        return (SegmentTemplate *) p;
+    else if((p = getAttribute(Type::SEGMENTLIST)))
+        return (SegmentList *) p;
+    else if((p = getAttribute(Type::SEGMENTBASE)))
+        return (SegmentBase *) p;
+
+    return NULL;
 }
 
 void SegmentInformation::updateSegmentList(SegmentList *list, bool restamp)
 {
+    SegmentList *segmentList = static_cast<SegmentList *>(getAttribute(Type::SEGMENTLIST));
     if(segmentList && restamp)
     {
         segmentList->updateWith(list, restamp);
@@ -231,27 +232,22 @@ void SegmentInformation::updateSegmentList(SegmentList *list, bool restamp)
     }
     else
     {
-        delete segmentList;
-        segmentList = list;
+        replaceAttribute(list);
     }
 }
 
-void SegmentInformation::setSegmentBase(SegmentBase *base)
-{
-    if(segmentBase)
-        delete segmentBase;
-    segmentBase = base;
-}
-
 void SegmentInformation::setSegmentTemplate(SegmentTemplate *templ)
 {
-    if(mediaSegmentTemplate)
+    SegmentTemplate *local = static_cast<SegmentTemplate *>(getAttribute(Type::SEGMENTTEMPLATE));
+    if(local)
     {
-        mediaSegmentTemplate->updateWith(templ);
+        local->updateWith(templ);
         delete templ;
     }
     else
-        mediaSegmentTemplate = templ;
+    {
+        addAttribute(templ);
+    }
 }
 
 static void insertIntoSegment(std::vector<Segment *> &seglist, size_t start,
@@ -323,63 +319,3 @@ Url SegmentInformation::getUrlSegment() const
         return ret;
     }
 }
-
-SegmentBase * SegmentInformation::inheritSegmentBase() const
-{
-    if(segmentBase)
-        return segmentBase;
-    else if (parent)
-        return parent->inheritSegmentBase();
-    else
-        return NULL;
-}
-
-SegmentList * SegmentInformation::inheritSegmentList() const
-{
-    if(segmentList)
-        return segmentList;
-    else if (parent)
-        return parent->inheritSegmentList();
-    else
-        return NULL;
-}
-
-SegmentTemplate * SegmentInformation::inheritSegmentTemplate() const
-{
-    if(mediaSegmentTemplate)
-        return mediaSegmentTemplate;
-    else if (parent)
-        return parent->inheritSegmentTemplate();
-    else
-        return NULL;
-}
-
-void SegmentInformation::setAvailabilityTimeOffset(vlc_tick_t t)
-{
-    availabilityTimeOffset = t;
-}
-
-void SegmentInformation::setAvailabilityTimeComplete(bool b)
-{
-    availabilityTimeComplete = b;
-}
-
-vlc_tick_t SegmentInformation::inheritAvailabilityTimeOffset() const
-{
-    for(const SegmentInformation *p = this; p; p = p->parent)
-    {
-        if(availabilityTimeOffset.isSet())
-            return availabilityTimeOffset.value();
-    }
-    return getPlaylist()->getAvailabilityTimeOffset();
-}
-
-bool SegmentInformation::inheritAvailabilityTimeComplete() const
-{
-    for(const SegmentInformation *p = this; p; p = p->parent)
-    {
-        if(availabilityTimeComplete.isSet())
-            return availabilityTimeComplete.value();
-    }
-    return getPlaylist()->getAvailabilityTimeComplete();
-}
diff --git a/modules/demux/adaptive/playlist/SegmentInformation.hpp b/modules/demux/adaptive/playlist/SegmentInformation.hpp
index 6704c3cca6..66e36d5c6f 100644
--- a/modules/demux/adaptive/playlist/SegmentInformation.hpp
+++ b/modules/demux/adaptive/playlist/SegmentInformation.hpp
@@ -44,8 +44,8 @@ namespace adaptive
         /* common segment elements for period/adaptset/rep 5.3.9.1,
          * with properties inheritance */
         class SegmentInformation : public ICanonicalUrl,
-                                   public TimescaleAble,
-                                   public Unique
+                                   public Unique,
+                                   public AttrsNode
         {
             friend class AbstractMultipleSegmentBaseType;
 
@@ -84,30 +84,16 @@ namespace adaptive
                 SegmentInformation *parent;
 
             public:
-                SegmentInformation *getParent() const;
                 AbstractSegmentBaseType *getProfile() const;
                 void updateSegmentList(SegmentList *, bool = false);
-                void setSegmentBase(SegmentBase *);
                 void setSegmentTemplate(SegmentTemplate *);
                 virtual Url getUrlSegment() const; /* impl */
                 Property<Url *> baseUrl;
-                void setAvailabilityTimeOffset(vlc_tick_t);
-                void setAvailabilityTimeComplete(bool);
                 const AbstractSegmentBaseType * inheritSegmentProfile() const;
-                SegmentBase *     inheritSegmentBase() const;
-                SegmentList *     inheritSegmentList() const;
-                SegmentTemplate * inheritSegmentTemplate() const;
-                vlc_tick_t        inheritAvailabilityTimeOffset() const;
-                bool              inheritAvailabilityTimeComplete() const;
 
             private:
                 void init();
-                SegmentBase     *segmentBase;
-                SegmentList     *segmentList;
-                SegmentTemplate *mediaSegmentTemplate;
                 CommonEncryption commonEncryption;
-                Undef<bool>      availabilityTimeComplete;
-                Undef<vlc_tick_t>availabilityTimeOffset;
         };
     }
 }
diff --git a/modules/demux/adaptive/playlist/SegmentList.cpp b/modules/demux/adaptive/playlist/SegmentList.cpp
index 211b9ef80c..92d12b56f7 100644
--- a/modules/demux/adaptive/playlist/SegmentList.cpp
+++ b/modules/demux/adaptive/playlist/SegmentList.cpp
@@ -34,8 +34,8 @@
 
 using namespace adaptive::playlist;
 
-SegmentList::SegmentList( SegmentInformation *parent ):
-    AbstractMultipleSegmentBaseType( parent )
+SegmentList::SegmentList( SegmentInformation *parent_ ):
+    AbstractMultipleSegmentBaseType( parent_, AttrsNode::Type::SEGMENTLIST )
 {
     totalLength = 0;
 }
@@ -80,7 +80,7 @@ Segment * SegmentList::getMediaSegment(uint64_t number) const
 
 void SegmentList::addSegment(Segment *seg)
 {
-    seg->setParent(parent);
+    seg->setParent(AbstractSegmentBaseType::parent);
     segments.push_back(seg);
     totalLength += seg->duration.Get();
 }
@@ -188,7 +188,7 @@ bool SegmentList::getPlaybackTimeDurationBySegmentNumber(uint64_t number,
             if(seg->duration.Get())
                 sduration = seg->duration.Get();
             else
-                sduration = duration.Get();
+                sduration = inheritDuration();
 
             /* Assuming there won't be any discontinuity in sequence */
             if(seg->getSequenceNumber() == number)
@@ -280,9 +280,7 @@ bool SegmentList::getSegmentNumberByTime(vlc_tick_t time, uint64_t *ret) const
     const SegmentTimeline *timeline = inheritSegmentTimeline();
     if(timeline)
     {
-        const Timescale timescale = timeline->getTimescale().isValid()
-                                  ? timeline->getTimescale()
-                                  : inheritTimescale();
+        const Timescale timescale = timeline->inheritTimescale();
         stime_t st = timescale.ToScaled(time);
         *ret = timeline->getElementNumberByScaledPlaybackTime(st);
         return true;
@@ -302,6 +300,7 @@ void SegmentList::debug(vlc_object_t *obj, int indent) const
     std::vector<Segment *>::const_iterator it;
     for(it = segments.begin(); it != segments.end(); ++it)
         (*it)->debug(obj, indent);
-    if(segmentTimeline)
-        segmentTimeline->debug(obj, indent + 1);
+    const AbstractAttr *p = getAttribute(Type::TIMELINE);
+    if(p)
+        ((SegmentTimeline *) p)->debug(obj, indent + 1);
 }
diff --git a/modules/demux/adaptive/playlist/SegmentList.h b/modules/demux/adaptive/playlist/SegmentList.h
index f67d64ad8a..28f63e2439 100644
--- a/modules/demux/adaptive/playlist/SegmentList.h
+++ b/modules/demux/adaptive/playlist/SegmentList.h
@@ -26,6 +26,7 @@
 #define SEGMENTLIST_H_
 
 #include "SegmentBaseType.hpp"
+#include "Inheritables.hpp"
 
 namespace adaptive
 {
diff --git a/modules/demux/adaptive/playlist/SegmentTemplate.cpp b/modules/demux/adaptive/playlist/SegmentTemplate.cpp
index f66fe7eb02..d3b7928f31 100644
--- a/modules/demux/adaptive/playlist/SegmentTemplate.cpp
+++ b/modules/demux/adaptive/playlist/SegmentTemplate.cpp
@@ -52,7 +52,7 @@ void SegmentTemplateSegment::setSourceUrl(const std::string &url)
 }
 
 SegmentTemplate::SegmentTemplate( SegmentInformation *parent ) :
-    AbstractMultipleSegmentBaseType( NULL ) /* we don't want auto inherit */
+    AbstractMultipleSegmentBaseType( parent, AbstractAttr::Type::SEGMENTTEMPLATE )
 {
     initialisationSegment.Set( NULL );
     parentSegmentInformation = parent;
@@ -71,14 +71,16 @@ void SegmentTemplate::setSourceUrl( const std::string &url )
 
 void SegmentTemplate::pruneByPlaybackTime(vlc_tick_t time)
 {
-    if(segmentTimeline)
-        return segmentTimeline->pruneByPlaybackTime(time);
+    const AbstractAttr *p = getAttribute(Type::TIMELINE);
+    if(p)
+        return ((SegmentTimeline *) p)->pruneByPlaybackTime(time);
 }
 
 size_t SegmentTemplate::pruneBySequenceNumber(uint64_t number)
 {
-    if(segmentTimeline)
-        return segmentTimeline->pruneBySequenceNumber(number);
+    const AbstractAttr *p = getAttribute(Type::TIMELINE);
+    if(p)
+        return ((SegmentTimeline *) p)->pruneBySequenceNumber(number);
     return 0;
 }
 
@@ -111,16 +113,18 @@ void SegmentTemplate::debug(vlc_object_t *obj, int indent) const
 {
     AbstractSegmentBaseType::debug(obj, indent);
     (*segments.begin())->debug(obj, indent);
-    if(segmentTimeline)
-        segmentTimeline->debug(obj, indent + 1);
+    const AbstractAttr *p = getAttribute(Type::TIMELINE);
+    if(p)
+        ((SegmentTimeline *) p)->debug(obj, indent + 1);
 }
 
 vlc_tick_t SegmentTemplate::getMinAheadTime(uint64_t number) const
 {
-    if( segmentTimeline )
+    SegmentTimeline *timeline = inheritSegmentTimeline();
+    if( timeline )
     {
-        const Timescale timescale = segmentTimeline->inheritTimescale();
-        return timescale.ToTime(segmentTimeline->getMinAheadScaledTime(number));
+        const Timescale timescale = timeline->inheritTimescale();
+        return timescale.ToTime(timeline->getMinAheadScaledTime(number));
     }
     else
     {
@@ -197,9 +201,7 @@ bool SegmentTemplate::getSegmentNumberByTime(vlc_tick_t time, uint64_t *ret) con
     const SegmentTimeline *timeline = inheritSegmentTimeline();
     if(timeline)
     {
-        const Timescale timescale = timeline->getTimescale().isValid()
-                                  ? timeline->getTimescale()
-                                  : inheritTimescale();
+        const Timescale timescale = timeline->inheritTimescale();
         stime_t st = timescale.ToScaled(time);
         *ret = timeline->getElementNumberByScaledPlaybackTime(st);
         return true;
diff --git a/modules/demux/adaptive/playlist/SegmentTimeline.cpp b/modules/demux/adaptive/playlist/SegmentTimeline.cpp
index a8e60ccc66..51e2873c13 100644
--- a/modules/demux/adaptive/playlist/SegmentTimeline.cpp
+++ b/modules/demux/adaptive/playlist/SegmentTimeline.cpp
@@ -33,20 +33,12 @@
 using namespace adaptive::playlist;
 
 SegmentTimeline::SegmentTimeline(AbstractMultipleSegmentBaseType *parent_)
-    :TimescaleAble(NULL)
+    : AttrsNode(Type::TIMELINE, parent_)
 {
     totalLength = 0;
     parent = parent_;
 }
 
-SegmentTimeline::SegmentTimeline(uint64_t scale)
-    :TimescaleAble(NULL)
-{
-    setTimescale(scale);
-    totalLength = 0;
-    parent = NULL;
-}
-
 SegmentTimeline::~SegmentTimeline()
 {
     std::list<Element *>::iterator it;
@@ -93,33 +85,6 @@ stime_t SegmentTimeline::getMinAheadScaledTime(uint64_t number) const
     return totalscaledtime;
 }
 
-Timescale SegmentTimeline::inheritTimescale() const
-{
-    if(getTimescale().isValid())
-        return getTimescale();
-
-    if(parent && parent->getTimescale().isValid())
-        return parent->getTimescale();
-
-    SegmentInformation *info = NULL;
-    if(parent && parent->getParent() && parent->getParent()->getParent())
-        info = parent->getParent()->getParent();
-    else
-        info = NULL;
-
-    AbstractMultipleSegmentBaseType *bt;
-    for(; info; info = info->getParent())
-    {
-        bt = dynamic_cast<AbstractMultipleSegmentBaseType *>(info->getProfile());
-        if(bt && bt->getSegmentTimeline() && bt->getSegmentTimeline()->getTimescale().isValid())
-            return bt->getSegmentTimeline()->getTimescale();
-        if(info->getTimescale().isValid())
-            return info->getTimescale();
-    }
-
-    return Timescale(1);
-}
-
 uint64_t SegmentTimeline::getElementNumberByScaledPlaybackTime(stime_t scaled) const
 {
     const Element *prevel = NULL;
diff --git a/modules/demux/adaptive/playlist/SegmentTimeline.h b/modules/demux/adaptive/playlist/SegmentTimeline.h
index 668f7d5389..e56f16437f 100644
--- a/modules/demux/adaptive/playlist/SegmentTimeline.h
+++ b/modules/demux/adaptive/playlist/SegmentTimeline.h
@@ -34,20 +34,18 @@ namespace adaptive
     {
         class AbstractMultipleSegmentBaseType;
 
-        class SegmentTimeline : public TimescaleAble
+        class SegmentTimeline : public AttrsNode
         {
             class Element;
 
             public:
                 SegmentTimeline(AbstractMultipleSegmentBaseType *);
-                SegmentTimeline(uint64_t);
                 virtual ~SegmentTimeline();
                 void addElement(uint64_t, stime_t d, uint64_t r = 0, stime_t t = 0);
                 uint64_t getElementNumberByScaledPlaybackTime(stime_t) const;
                 bool    getScaledPlaybackTimeDurationBySegmentNumber(uint64_t, stime_t *, stime_t *) const;
                 stime_t getScaledPlaybackTimeByElementNumber(uint64_t) const;
                 stime_t getMinAheadScaledTime(uint64_t) const;
-                Timescale inheritTimescale() const; /* reimpl */
                 stime_t getTotalLength() const;
                 uint64_t maxElementNumber() const;
                 uint64_t minElementNumber() const;
diff --git a/modules/demux/dash/mp4/IndexReader.cpp b/modules/demux/dash/mp4/IndexReader.cpp
index 5dc8089a6d..4e4312a72d 100644
--- a/modules/demux/dash/mp4/IndexReader.cpp
+++ b/modules/demux/dash/mp4/IndexReader.cpp
@@ -57,7 +57,7 @@ bool IndexReader::parseIndex(block_t *p_block, BaseRepresentation *rep, uint64_t
             point.duration = sidx->p_items[i].i_subsegment_duration;
             point.time += point.duration;
         }
-        rep->setTimescale(Timescale(sidx->i_timescale));
+        rep->replaceAttribute(new TimescaleAttr(Timescale(sidx->i_timescale)));
         rep->SplitUsingIndex(splitlist);
         rep->getPlaylist()->debug();
     }
diff --git a/modules/demux/dash/mpd/IsoffMainParser.cpp b/modules/demux/dash/mpd/IsoffMainParser.cpp
index 6f158a81aa..408c61b567 100644
--- a/modules/demux/dash/mpd/IsoffMainParser.cpp
+++ b/modules/demux/dash/mpd/IsoffMainParser.cpp
@@ -70,12 +70,12 @@ static void parseAvailability(MPD *mpd, Node *node, T *s)
     if(node->hasAttribute("availabilityTimeOffset"))
     {
         double val = Integer<double>(node->getAttributeValue("availabilityTimeOffset"));
-        s->setAvailabilityTimeOffset(val * CLOCK_FREQ);
+        s->addAttribute(new AvailabilityTimeOffsetAttr(val * CLOCK_FREQ));
     }
     if(node->hasAttribute("availabilityTimeComplete"))
     {
         bool b = (node->getAttributeValue("availabilityTimeComplete") == "false");
-        s->setAvailabilityTimeComplete(!b);
+        s->addAttribute(new AvailabilityTimeCompleteAttr(!b));
         if(b)
             mpd->setLowLatency(b);
     }
@@ -206,8 +206,10 @@ void IsoffMainParser::parseSegmentBaseType(MPD *, Node *node,
     }
 
     if(node->hasAttribute("timescale"))
-        base->setTimescale(Integer<uint64_t>(node->getAttributeValue("timescale")));
-
+    {
+        TimescaleAttr *prop = new TimescaleAttr(Timescale(Integer<uint64_t>(node->getAttributeValue("timescale"))));
+        base->addAttribute(prop);
+    }
 }
 
 void IsoffMainParser::parseMultipleSegmentBaseType(MPD *mpd, Node *node,
@@ -217,10 +219,10 @@ void IsoffMainParser::parseMultipleSegmentBaseType(MPD *mpd, Node *node,
     parseSegmentBaseType(mpd, node, base, parent);
 
     if(node->hasAttribute("duration"))
-        base->duration.Set(Integer<stime_t>(node->getAttributeValue("duration")));
+        base->addAttribute(new DurationAttr(Integer<stime_t>(node->getAttributeValue("duration"))));
 
     if(node->hasAttribute("startNumber"))
-        base->setStartNumber(Integer<uint64_t>(node->getAttributeValue("startNumber")));
+        base->addAttribute(new StartnumberAttr(Integer<uint64_t>(node->getAttributeValue("startNumber"))));
 
     parseTimeline(DOMHelper::getFirstChildElementByName(node, "SegmentTimeline"), base);
 }
@@ -269,7 +271,7 @@ size_t IsoffMainParser::parseSegmentInformation(MPD *mpd, Node *node,
     total += parseSegmentList(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentList"), info);
     total += parseSegmentTemplate(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentTemplate" ), info);
     if(node->hasAttribute("timescale"))
-        info->setTimescale(Integer<uint64_t>(node->getAttributeValue("timescale")));
+        info->addAttribute(new TimescaleAttr(Timescale(Integer<uint64_t>(node->getAttributeValue("timescale")))));
 
     parseAvailability<SegmentInformation>(mpd, node, info);
 
@@ -394,7 +396,7 @@ void    IsoffMainParser::parseRepresentations (MPD *mpd, Node *adaptationSetNode
         {
             SegmentBase *base = new (std::nothrow) SegmentBase(currentRepresentation);
             if(base)
-                currentRepresentation->setSegmentBase(base);
+                currentRepresentation->addAttribute(base);
         }
 
         adaptationSet->addRepresentation(currentRepresentation);
@@ -419,7 +421,7 @@ size_t IsoffMainParser::parseSegmentBase(MPD *mpd, Node * segmentBaseNode, Segme
         base->initialisationSegment.Set(initSeg);
     }
 
-    info->setSegmentBase(base);
+    info->addAttribute(base);
 
     return 1;
 }
@@ -458,11 +460,12 @@ size_t IsoffMainParser::parseSegmentList(MPD *mpd, Node * segListNode, SegmentIn
                     seg->setByteRange(atoi(range.substr(0, pos).c_str()), atoi(range.substr(pos + 1, range.size()).c_str()));
                 }
 
-                if(list->duration.Get())
+                stime_t duration = list->inheritDuration();
+                if(duration)
                 {
                     seg->startTime.Set(nzStartTime);
-                    seg->duration.Set(list->duration.Get());
-                    nzStartTime += list->duration.Get();
+                    seg->duration.Set(duration);
+                    nzStartTime += duration;
                 }
 
                 seg->setSequenceNumber(total);
@@ -534,7 +537,8 @@ void IsoffMainParser::parseTimeline(Node *node, AbstractMultipleSegmentBaseType
 
             number += (1 + r);
         }
-        base->setSegmentTimeline(timeline);
+        //base->setSegmentTimeline(timeline);
+        base->addAttribute(timeline);
     }
 }
 
diff --git a/modules/demux/dash/mpd/Representation.cpp b/modules/demux/dash/mpd/Representation.cpp
index 9f936fe4ef..e0026e3902 100644
--- a/modules/demux/dash/mpd/Representation.cpp
+++ b/modules/demux/dash/mpd/Representation.cpp
@@ -109,9 +109,9 @@ stime_t Representation::getScaledTimeBySegmentNumber(uint64_t index, const Segme
     {
         time = tl->getScaledPlaybackTimeByElementNumber(index);
     }
-    else if(templ->duration.Get())
+    else if(templ->inheritDuration())
     {
-        time = templ->duration.Get() * index;
+        time = templ->inheritDuration() * index;
     }
     return time;
 }
diff --git a/modules/demux/hls/playlist/Parser.cpp b/modules/demux/hls/playlist/Parser.cpp
index 5a6de6049d..e2e1aaefe4 100644
--- a/modules/demux/hls/playlist/Parser.cpp
+++ b/modules/demux/hls/playlist/Parser.cpp
@@ -209,7 +209,8 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l
 {
     SegmentList *segmentList = new (std::nothrow) SegmentList(rep);
 
-    rep->setTimescale(100);
+    Timescale timescale(100);
+    rep->addAttribute(new TimescaleAttr(timescale));
     rep->b_loaded = true;
 
     vlc_tick_t totalduration = 0;
@@ -266,8 +267,8 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l
                         nzDuration = vlc_tick_from_sec(durAttribute->floatingPoint());
                     ctx_extinf = NULL;
                 }
-                segment->duration.Set(rep->getTimescale().ToScaled(nzDuration));
-                segment->startTime.Set(rep->getTimescale().ToScaled(nzStartTime));
+                segment->duration.Set(timescale.ToScaled(nzDuration));
+                segment->startTime.Set(timescale.ToScaled(nzStartTime));
                 nzStartTime += nzDuration;
                 totalduration += nzDuration;
                 if(absReferenceTime != VLC_TICK_INVALID)
diff --git a/modules/demux/hls/playlist/Representation.cpp b/modules/demux/hls/playlist/Representation.cpp
index 08f7b40249..4103478f46 100644
--- a/modules/demux/hls/playlist/Representation.cpp
+++ b/modules/demux/hls/playlist/Representation.cpp
@@ -169,8 +169,10 @@ uint64_t Representation::translateSegmentNumber(uint64_t num, const BaseRepresen
     HLSSegment *fromHlsSeg = dynamic_cast<HLSSegment *>(fromSeg);
     if(!fromHlsSeg)
         return 1;
+
+    const Timescale timescale = inheritTimescale();
     const vlc_tick_t utcTime = fromHlsSeg->getUTCTime() +
-                               getTimescale().ToTime(fromHlsSeg->duration.Get()) / 2;
+                               timescale.ToTime(fromHlsSeg->duration.Get()) / 2;
 
     const std::vector<Segment *> &list = inheritSegmentList()->getSegments();
     std::vector<Segment *>::const_iterator it;
diff --git a/modules/demux/smooth/mp4/IndexReader.cpp b/modules/demux/smooth/mp4/IndexReader.cpp
index ef3e363030..597918a9e5 100644
--- a/modules/demux/smooth/mp4/IndexReader.cpp
+++ b/modules/demux/smooth/mp4/IndexReader.cpp
@@ -60,7 +60,7 @@ bool IndexReader::parseIndex(block_t *p_block, BaseRepresentation *rep)
     if(!uuid_box)
         return false;
 
-    SegmentTimeline *timelineadd = new (std::nothrow) SegmentTimeline(rep->inheritTimescale());
+    SegmentTimeline *timelineadd = new (std::nothrow) SegmentTimeline(NULL);
     if (timelineadd)
     {
         const MP4_Box_data_tfrf_t *p_tfrfdata = uuid_box->data.p_tfrf;
diff --git a/modules/demux/smooth/playlist/Manifest.cpp b/modules/demux/smooth/playlist/Manifest.cpp
index 5538bc644f..c967feb29f 100644
--- a/modules/demux/smooth/playlist/Manifest.cpp
+++ b/modules/demux/smooth/playlist/Manifest.cpp
@@ -29,10 +29,10 @@
 using namespace smooth::playlist;
 
 Manifest::Manifest (vlc_object_t *p_object) :
-    AbstractPlaylist(p_object), TimescaleAble()
+    AbstractPlaylist(p_object)
 {
     minUpdatePeriod.Set( VLC_TICK_FROM_SEC(5) );
-    setTimescale( 10000000 ); // 100ns
+    addAttribute(new TimescaleAttr(Timescale(10000000))); // 100ns
     b_live = false;
 }
 
diff --git a/modules/demux/smooth/playlist/Manifest.hpp b/modules/demux/smooth/playlist/Manifest.hpp
index 94facfd503..b0e0e6a3f7 100644
--- a/modules/demux/smooth/playlist/Manifest.hpp
+++ b/modules/demux/smooth/playlist/Manifest.hpp
@@ -21,8 +21,6 @@
 #define MANIFEST_HPP
 
 #include "../../adaptive/playlist/AbstractPlaylist.hpp"
-#include "../../adaptive/playlist/Inheritables.hpp"
-#include "../../adaptive/Time.hpp"
 
 namespace smooth
 {
@@ -30,8 +28,7 @@ namespace smooth
     {
         using namespace adaptive::playlist;
 
-        class Manifest : public AbstractPlaylist,
-                         public TimescaleAble
+        class Manifest : public AbstractPlaylist
         {
             friend class ManifestParser;
 
diff --git a/modules/demux/smooth/playlist/Parser.cpp b/modules/demux/smooth/playlist/Parser.cpp
index 4ca85add22..08b68188be 100644
--- a/modules/demux/smooth/playlist/Parser.cpp
+++ b/modules/demux/smooth/playlist/Parser.cpp
@@ -52,9 +52,9 @@ ManifestParser::~ManifestParser()
 {
 }
 
-static SegmentTimeline *createTimeline(Node *streamIndexNode, uint64_t timescale)
+static SegmentTimeline *createTimeline(Node *streamIndexNode)
 {
-    SegmentTimeline *timeline = new (std::nothrow) SegmentTimeline(timescale);
+    SegmentTimeline *timeline = new (std::nothrow) SegmentTimeline(NULL);
     if(timeline)
     {
         std::vector<Node *> chunks = DOMHelper::getElementByTagName(streamIndexNode, "c", true);
@@ -143,7 +143,8 @@ static SegmentTimeline *createTimeline(Node *streamIndexNode, uint64_t timescale
     return timeline;
 }
 
-static void ParseQualityLevel(BaseAdaptationSet *adaptSet, Node *qualNode, const std::string &type, unsigned id, unsigned trackid)
+static void ParseQualityLevel(BaseAdaptationSet *adaptSet, Node *qualNode, const std::string &type,
+                              unsigned id, unsigned trackid, const Timescale &timescale)
 {
     Representation *rep = new (std::nothrow) Representation(adaptSet);
     if(rep)
@@ -168,7 +169,7 @@ static void ParseQualityLevel(BaseAdaptationSet *adaptSet, Node *qualNode, const
 
         ForgedInitSegment *initSegment = new (std::nothrow)
                 ForgedInitSegment(rep, type,
-                                  adaptSet->inheritTimescale(),
+                                  timescale,
                                   adaptSet->getPlaylist()->duration.Get());
         if(initSegment)
         {
@@ -225,8 +226,12 @@ static void ParseStreamIndex(BasePeriod *period, Node *streamIndexNode, unsigned
         if(streamIndexNode->hasAttribute("Name"))
             adaptSet->description.Set(streamIndexNode->getAttributeValue("Name"));
 
+        Timescale timescale(10000000);
         if(streamIndexNode->hasAttribute("TimeScale"))
-            adaptSet->setTimescale(Integer<uint64_t>(streamIndexNode->getAttributeValue("TimeScale")));
+        {
+            timescale = Timescale(Integer<uint64_t>(streamIndexNode->getAttributeValue("TimeScale")));
+            adaptSet->addAttribute(new TimescaleAttr(timescale));
+        }
 
         const std::string url = streamIndexNode->getAttributeValue("Url");
         if(!url.empty())
@@ -236,8 +241,8 @@ static void ParseStreamIndex(BasePeriod *period, Node *streamIndexNode, unsigned
             if(templ)
             {
                 templ->setSourceUrl(url);
-                SegmentTimeline *timeline = createTimeline(streamIndexNode, adaptSet->inheritTimescale());
-                templ->setSegmentTimeline(timeline);
+                SegmentTimeline *timeline = createTimeline(streamIndexNode);
+                templ->addAttribute(timeline);
                 adaptSet->setSegmentTemplate(templ);
             }
 
@@ -246,7 +251,7 @@ static void ParseStreamIndex(BasePeriod *period, Node *streamIndexNode, unsigned
             std::vector<Node *> qualLevels = DOMHelper::getElementByTagName(streamIndexNode, "QualityLevel", true);
             std::vector<Node *>::const_iterator it;
             for(it = qualLevels.begin(); it != qualLevels.end(); ++it)
-                ParseQualityLevel(adaptSet, *it, type, nextid++, id);
+                ParseQualityLevel(adaptSet, *it, type, nextid++, id, timescale);
         }
         if(!adaptSet->getRepresentations().empty())
             period->addAdaptationSet(adaptSet);
@@ -263,19 +268,24 @@ Manifest * ManifestParser::parse()
 
     manifest->setPlaylistUrl(Helper::getDirectoryPath(playlisturl).append("/"));
 
+    Timescale timescale(10000000);
+
     if(root->hasAttribute("TimeScale"))
-        manifest->setTimescale(Integer<uint64_t>(root->getAttributeValue("TimeScale")));
+    {
+        timescale = Timescale(Integer<uint64_t>(root->getAttributeValue("TimeScale")));
+        manifest->addAttribute(new TimescaleAttr(timescale));
+    }
 
     if(root->hasAttribute("Duration"))
     {
         stime_t time = Integer<stime_t>(root->getAttributeValue("Duration"));
-        manifest->duration.Set(manifest->getTimescale().ToTime(time));
+        manifest->duration.Set(timescale.ToTime(time));
     }
 
     if(root->hasAttribute("DVRWindowLength"))
     {
         stime_t time = Integer<stime_t>(root->getAttributeValue("DVRWindowLength"));
-        manifest->timeShiftBufferDepth.Set(manifest->getTimescale().ToTime(time));
+        manifest->timeShiftBufferDepth.Set(timescale.ToTime(time));
     }
 
     if(root->hasAttribute("IsLive") && root->getAttributeValue("IsLive") == "TRUE")
@@ -285,7 +295,6 @@ Manifest * ManifestParser::parse()
     BasePeriod *period = new (std::nothrow) BasePeriod(manifest);
     if(period)
     {
-        period->setTimescale(manifest->getTimescale());
         period->duration.Set(manifest->duration.Get());
         unsigned nextid = 1;
         std::vector<Node *> streamIndexes = DOMHelper::getElementByTagName(root, "StreamIndex", true);



More information about the vlc-commits mailing list