[vlc-commits] [Git][videolan/vlc][3.0.x] 8 commits: demux: adaptive: fix unitialized var

François Cartegnie (@fcartegnie) gitlab at videolan.org
Fri Nov 4 16:42:35 UTC 2022



François Cartegnie pushed to branch 3.0.x at VideoLAN / VLC


Commits:
b607efd5 by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: adaptive: fix unitialized var

- - - - -
f8a1f5d5 by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: hls: prefer average bandwidth when available

(cherry picked from commit f9b0cad3896c0276d467c5ad3be104baf946acdf)

- - - - -
d8ae0f09 by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: adaptive: codecs does not belong to ext-x-media

(cherry picked from commit 7d37ad40e40419c28bf45ecf97fd0ea47cfa7f1e)

- - - - -
4ff3adad by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: hls: rework stream/media attributes propagation

(cherry picked from commit a54d02b0c9a5b0a2073f393a33235d9adfd6c25d)

- - - - -
ea8e33c8 by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: hls: set channels

(cherry picked from commit c5b37cb43da4cd2507e970e05de53b24200d63bd)

- - - - -
7d9d51ac by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: adaptive: return tracker update status

(cherry picked from commit 9d83a7ee1a6ec993e73e419fc84357cc6433c908)

- - - - -
9e50bef3 by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: adaptive: forward update status through stream

(cherry picked from commit aeca11e9627781f05e9baee86fda2af87306e76c)

- - - - -
ee321360 by Francois Cartegnie at 2022-11-04T16:20:45+00:00
demux: adaptive: allow implementations to preparse

(cherry picked from commit 0f9cde94991d12e253c480324f95ba513e5b99b1)

- - - - -


16 changed files:

- modules/demux/adaptive/ID.cpp
- modules/demux/adaptive/ID.hpp
- modules/demux/adaptive/PlaylistManager.cpp
- modules/demux/adaptive/PlaylistManager.h
- modules/demux/adaptive/SegmentTracker.cpp
- modules/demux/adaptive/SegmentTracker.hpp
- modules/demux/adaptive/Streams.cpp
- modules/demux/adaptive/Streams.hpp
- modules/demux/adaptive/logic/NearOptimalAdaptationLogic.cpp
- modules/demux/adaptive/playlist/CodecDescription.cpp
- modules/demux/adaptive/playlist/CodecDescription.hpp
- modules/demux/adaptive/test/playlist/M3U8.cpp
- modules/demux/hls/playlist/HLSRepresentation.cpp
- modules/demux/hls/playlist/HLSRepresentation.hpp
- modules/demux/hls/playlist/Parser.cpp
- modules/demux/hls/playlist/Parser.hpp


Changes:

=====================================
modules/demux/adaptive/ID.cpp
=====================================
@@ -39,6 +39,11 @@ ID::ID(uint64_t id_)
     id = ss.str();
 }
 
+bool ID::isValid() const
+{
+    return !id.empty();
+}
+
 bool ID::operator==(const ID &other) const
 {
     return (!id.empty() && id == other.id);


=====================================
modules/demux/adaptive/ID.hpp
=====================================
@@ -33,6 +33,7 @@ namespace adaptive
             bool operator==(const ID &) const;
             bool operator<(const ID &) const;
             std::string str() const;
+            bool isValid() const;
 
         private:
             std::string id;


=====================================
modules/demux/adaptive/PlaylistManager.cpp
=====================================
@@ -161,6 +161,8 @@ bool PlaylistManager::init(bool b_preparsing)
     playlist->playbackStart.Set(time(nullptr));
     nextPlaylistupdate = playlist->playbackStart.Get();
 
+    if(b_preparsing)
+        preparsePlaylist();
     updateControlsPosition();
 
     return true;
@@ -422,6 +424,11 @@ bool PlaylistManager::updatePlaylist()
     return true;
 }
 
+void PlaylistManager::preparsePlaylist()
+{
+
+}
+
 Times PlaylistManager::getTimes(bool b_first) const
 {
     vlc_mutex_locker locker(&demux.lock);


=====================================
modules/demux/adaptive/PlaylistManager.h
=====================================
@@ -66,6 +66,7 @@ namespace adaptive
             virtual bool needsUpdate() const;
             virtual bool updatePlaylist();
             virtual void scheduleNextUpdate();
+            virtual void preparsePlaylist();
 
             /* static callbacks */
             static int control_callback(demux_t *, int, va_list);
@@ -105,6 +106,7 @@ namespace adaptive
             demux_t                             *p_demux;
             std::vector<AbstractStream *>        streams;
             BasePeriod                          *currentPeriod;
+            bool                                 b_preparsing;
 
             enum class TimestampSynchronizationPoint
             {
@@ -151,7 +153,6 @@ namespace adaptive
             bool         b_buffering;
             bool         b_canceled;
             mtime_t      pause_start;
-            bool         b_preparsing;
     };
 
 }


=====================================
modules/demux/adaptive/SegmentTracker.cpp
=====================================
@@ -596,18 +596,22 @@ bool SegmentTracker::bufferingAvailable() const
     return true;
 }
 
-void SegmentTracker::updateSelected()
+bool SegmentTracker::updateSelected()
 {
+    bool b_updated;
     if(current.rep && current.rep->needsUpdate(next.number))
     {
-        bool b_updated = current.rep->runLocalUpdates(resources);
+        b_updated = current.rep->runLocalUpdates(resources);
         current.rep->scheduleNextUpdate(current.number, b_updated);
         if(b_updated)
             notify(RepresentationUpdatedEvent(current.rep));
     }
+    else b_updated = false;
 
     if(current.rep && current.rep->canNoLongerUpdate())
         notify(RepresentationUpdateFailedEvent(current.rep));
+
+    return b_updated;
 }
 
 void SegmentTracker::notify(const TrackerEvent &event) const


=====================================
modules/demux/adaptive/SegmentTracker.hpp
=====================================
@@ -235,7 +235,7 @@ namespace adaptive
             void notifyBufferingState(bool) const;
             void notifyBufferingLevel(mtime_t, mtime_t, mtime_t, mtime_t) const;
             void registerListener(SegmentTrackerListenerInterface *);
-            void updateSelected();
+            bool updateSelected();
             bool bufferingAvailable() const;
 
         private:


=====================================
modules/demux/adaptive/Streams.cpp
=====================================
@@ -727,10 +727,15 @@ bool AbstractStream::getMediaAdvanceAmount(mtime_t *duration) const
     return true;
 }
 
-void AbstractStream::runUpdates()
+bool AbstractStream::runUpdates(bool)
 {
-    if(valid && !disabled)
-        segmentTracker->updateSelected();
+    if(!valid)
+        return false;
+
+    if(!disabled)
+        return segmentTracker->updateSelected();
+    else
+        return false;
 }
 
 void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const


=====================================
modules/demux/adaptive/Streams.hpp
=====================================
@@ -102,7 +102,7 @@ namespace adaptive
         virtual bool setPosition(const StreamPosition &, bool);
         bool getMediaPlaybackTimes(mtime_t *, mtime_t *, mtime_t *) const;
         bool getMediaAdvanceAmount(mtime_t *) const;
-        void runUpdates();
+        bool runUpdates(bool = false);
 
         /* Used by demuxers fake streams */
         virtual block_t *readNextBlock() override;


=====================================
modules/demux/adaptive/logic/NearOptimalAdaptationLogic.cpp
=====================================
@@ -70,7 +70,7 @@ NearOptimalAdaptationLogic::getNextQualityIndex( BaseAdaptationSet *adaptSet, Re
 {
     BaseRepresentation *ret = nullptr;
     BaseRepresentation *prev = nullptr;
-    float argmax;
+    float argmax = 0;
     for(BaseRepresentation *rep = selector.lowest(adaptSet);
                             rep && rep != prev; rep = selector.higher(adaptSet, rep))
     {


=====================================
modules/demux/adaptive/playlist/CodecDescription.cpp
=====================================
@@ -93,6 +93,11 @@ void CodecDescription::setSampleRate(const Rate &r)
     fmt.audio.i_rate = r.num();
 }
 
+void CodecDescription::setChannelsCount(unsigned c)
+{
+    fmt.audio.i_channels = c;
+}
+
 CodecDescriptionList::CodecDescriptionList()
 {
 


=====================================
modules/demux/adaptive/playlist/CodecDescription.hpp
=====================================
@@ -44,6 +44,7 @@ namespace adaptive
                 void setAspectRatio(const AspectRatio &);
                 void setFrameRate(const Rate &);
                 void setSampleRate(const Rate &);
+                void setChannelsCount(unsigned);
 
             protected:
                 es_format_t fmt;


=====================================
modules/demux/adaptive/test/playlist/M3U8.cpp
=====================================
@@ -27,6 +27,7 @@
 #include "../../playlist/BaseAdaptationSet.h"
 #include "../../playlist/BaseRepresentation.h"
 #include "../../logic/BufferingLogic.hpp"
+#include "../../tools/FormatNamespace.hpp"
 #include "../../SegmentTracker.hpp"
 #include "../../../hls/playlist/Parser.hpp"
 #include "../../../hls/playlist/M3U8.hpp"
@@ -125,10 +126,10 @@ int M3U8MasterPlaylist_test()
     {
         Expect(m3u);
         Expect(m3u->getPeriods().size() == 1);
-        Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 4);
+        Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 3);
         BaseAdaptationSet *set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("aac English"));
         Expect(set);
-        Expect(set->getRepresentations().size() == 1);
+        Expect(set->getRepresentations().size() == 2);
         Expect(set->getLang() == "en");
         Expect(set->getRole().autoSelectable());
         Expect(set->getRole().isDefault());
@@ -140,6 +141,131 @@ int M3U8MasterPlaylist_test()
         return 1;
     }
 
+    /* Empty MEDIA URI property group propagation test */
+    {
+        const char srcmanifest[] =
+        "#EXTM3U\n"
+        "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aach-64\",NAME=\"audio 64\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"2\"\n"
+        "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aacl-128\",NAME=\"audio 128\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"2\"\n"
+        "#EXT-X-STREAM-INF:BANDWIDTH=75000,AVERAGE-BANDWIDTH=70000,CODECS=\"mp4a.40.5\",AUDIO=\"aach-64\"\n"
+        "streaminf0.m3u8\n"
+        "#EXT-X-STREAM-INF:BANDWIDTH=150000,AVERAGE-BANDWIDTH=125000,CODECS=\"mp4a.40.2\",AUDIO=\"aacl-128\"\n"
+        "streaminf1.m3u8\n"
+        ;
+
+        m3u = ParseM3U8(obj, srcmanifest, sizeof(srcmanifest));
+        try
+        {
+            Expect(m3u);
+            Expect(m3u->getFirstPeriod());
+            Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 1);
+            BaseAdaptationSet *set = m3u->getFirstPeriod()->getAdaptationSets().front();
+            Expect(set->getRole().autoSelectable());
+            Expect(set->getRole().isDefault());
+            auto reps = set->getRepresentations();
+            Expect(reps.size() == 2);
+            Expect(reps[0]->getBandwidth() == 70000);
+            Expect(reps[1]->getBandwidth() == 125000);
+
+            FormatNamespace fns("mp4a.40.5");
+            CodecDescriptionList codecsdesclist;
+            reps[0]->getCodecsDesc(&codecsdesclist);
+            Expect(codecsdesclist.size() == 1);
+            const es_format_t *fmt = codecsdesclist.front()->getFmt();
+            Expect(fmt != nullptr);
+            Expect(fmt->i_codec == fns.getFmt()->i_codec);
+            Expect(fmt->i_profile == fns.getFmt()->i_profile);
+            Expect(fmt->i_cat == AUDIO_ES);
+            Expect(fmt->audio.i_channels == 2);
+
+            delete m3u;
+        }
+        catch (...)
+        {
+            delete m3u;
+            return 1;
+        }
+    }
+
+    /* check codec assignment per group */
+    {
+        const char srcmanifest[] =
+        "#EXTM3U\n"
+        "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"Audio\",NAME=\"en_aud\",DEFAULT=YES,AUTOSELECT=YES,"
+        " LANGUAGE=\"en\",CHANNELS=\"2\",URI=\"a0.m3u8\"\n"
+        "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"Subtitles\",NAME=\"sub_fr\",DEFAULT=YES,FORCED=NO,LANGUAGE=\"fr\","
+        " URI=\"cc0.m3u8\"\n"
+        "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID=\"Closed Captions\",NAME=\"cc_en\",DEFAULT=YES,AUTOSELECT=YES,"
+        " LANGUAGE=\"en\",INSTREAM-ID=\"CC1\"\n"
+        "#EXT-X-STREAM-INF:BANDWIDTH=629758,AVERAGE-BANDWIDTH=572508,RESOLUTION=426x240,CODECS=\"avc1.42E015,mp4a.40.2,wvtt\","
+        " FRAME-RATE=25,AUDIO=\"Audio\",SUBTITLES=\"Subtitles\",CLOSED-CAPTIONS=\"Closed Captions\"\n"
+        "v0.m3u8\n"
+        "#EXT-X-STREAM-INF:BANDWIDTH=1069758,AVERAGE-BANDWIDTH=972508,RESOLUTION=640x360,CODECS=\"avc1.4D401E,mp4a.40.2,wvtt\","
+        " FRAME-RATE=29.970,AUDIO=\"Audio\",SUBTITLES=\"Subtitles\",CLOSED-CAPTIONS=\"Closed Captions\"\n"
+        "v1.m3u8\n"
+        ;
+
+        m3u = ParseM3U8(obj, srcmanifest, sizeof(srcmanifest));
+        try
+        {
+            Expect(m3u);
+            Expect(m3u->getFirstPeriod());
+            Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 3);
+
+            {
+                auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("Audio en_aud"));
+                Expect(set != nullptr);
+                auto reps = set->getRepresentations();
+                Expect(reps.size() == 1);
+                FormatNamespace fns("mp4a.40.2");
+                CodecDescriptionList codecsdesclist;
+                reps[0]->getCodecsDesc(&codecsdesclist);
+                Expect(codecsdesclist.size() == 1);
+                const es_format_t *fmt = codecsdesclist.front()->getFmt();
+                Expect(fmt != nullptr);
+                Expect(fmt->i_codec == fns.getFmt()->i_codec);
+                Expect(fmt->i_cat == AUDIO_ES);
+                Expect(fmt->audio.i_channels == 2);
+            }
+
+            {
+                auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("Subtitles sub_fr"));
+                Expect(set != nullptr);
+                auto reps = set->getRepresentations();
+                Expect(reps.size() == 1);
+                FormatNamespace fns("wvtt");
+                CodecDescriptionList codecsdesclist;
+                reps[0]->getCodecsDesc(&codecsdesclist);
+                Expect(codecsdesclist.size() == 1);
+                const es_format_t *fmt = codecsdesclist.front()->getFmt();
+                Expect(fmt != nullptr);
+                Expect(fmt->i_codec == fns.getFmt()->i_codec);
+                Expect(fmt->i_cat == SPU_ES);
+            }
+
+            {
+                auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("default_id#0"));
+                Expect(set != nullptr);
+                auto reps = set->getRepresentations();
+                Expect(reps.size() == 2);
+                FormatNamespace fns("avc1.42E015");
+                CodecDescriptionList codecsdesclist;
+                reps[0]->getCodecsDesc(&codecsdesclist);
+                Expect(codecsdesclist.size() == 1);
+                const es_format_t *fmt = codecsdesclist.front()->getFmt();
+                Expect(fmt != nullptr);
+                Expect(fmt->i_codec == fns.getFmt()->i_codec);
+                Expect(fmt->i_cat == VIDEO_ES);
+            }
+
+            delete m3u;
+        }
+        catch (...)
+        {
+            delete m3u;
+            return 1;
+        }
+    }
     return 0;
 }
 
@@ -420,6 +546,5 @@ int M3U8Playlist_test()
         return 1;
     }
 
-
     return 0;
 }


=====================================
modules/demux/hls/playlist/HLSRepresentation.cpp
=====================================
@@ -48,6 +48,7 @@ HLSRepresentation::HLSRepresentation  ( BaseAdaptationSet *set ) :
     lastUpdateTime = 0;
     targetDuration = 0;
     streamFormat = StreamFormat::Type::Unknown;
+    channels = 0;
 }
 
 HLSRepresentation::~HLSRepresentation ()
@@ -178,6 +179,21 @@ bool HLSRepresentation::canNoLongerUpdate() const
     return updateFailureCount > MAX_UPDATE_FAILED_UPDATE_COUNT;
 }
 
+void HLSRepresentation::setChannelsCount(unsigned c)
+{
+    channels = c;
+}
+
+CodecDescription * HLSRepresentation::makeCodecDescription(const std::string &s) const
+{
+    CodecDescription *desc = BaseRepresentation::makeCodecDescription(s);
+    if(desc)
+    {
+        desc->setChannelsCount(channels);
+    }
+    return desc;
+}
+
 uint64_t HLSRepresentation::translateSegmentNumber(uint64_t num, const BaseRepresentation *from) const
 {
     if(targetDuration == static_cast<const HLSRepresentation *>(from)->targetDuration)


=====================================
modules/demux/hls/playlist/HLSRepresentation.hpp
=====================================
@@ -54,6 +54,9 @@ namespace hls
                 virtual bool canNoLongerUpdate() const override;
 
                 virtual uint64_t translateSegmentNumber(uint64_t, const BaseRepresentation *) const override;
+                virtual CodecDescription * makeCodecDescription(const std::string &) const override;
+
+                void setChannelsCount(unsigned);
 
             protected:
                 time_t targetDuration;
@@ -66,6 +69,7 @@ namespace hls
                 bool b_loaded;
                 unsigned updateFailureCount;
                 mtime_t lastUpdateTime;
+                unsigned channels;
         };
     }
 }


=====================================
modules/demux/hls/playlist/Parser.cpp
=====================================
@@ -32,6 +32,7 @@
 #include "../../adaptive/tools/Retrieve.hpp"
 #include "../../adaptive/tools/Helper.h"
 #include "../../adaptive/tools/Conversions.hpp"
+#include "../../adaptive/tools/FormatNamespace.hpp"
 #include "M3U8.hpp"
 #include "Tags.hpp"
 
@@ -39,7 +40,8 @@
 #include <vlc_stream.h>
 #include <cstdio>
 #include <sstream>
-#include <map>
+#include <array>
+#include <unordered_map>
 #include <cctype>
 #include <algorithm>
 #include <limits>
@@ -91,7 +93,9 @@ static void releaseTagsList(std::list<Tag *> &list)
 HLSRepresentation * M3U8Parser::createRepresentation(BaseAdaptationSet *adaptSet, const AttributesTag * tag)
 {
     const Attribute *uriAttr = tag->getAttributeByName("URI");
-    const Attribute *bwAttr = tag->getAttributeByName("BANDWIDTH");
+    const Attribute *bwAttr = tag->getAttributeByName("AVERAGE-BANDWIDTH");
+    if(!bwAttr)
+        bwAttr = tag->getAttributeByName("BANDWIDTH");
     const Attribute *resAttr = tag->getAttributeByName("RESOLUTION");
 
     HLSRepresentation *rep = new (std::nothrow) HLSRepresentation(adaptSet);
@@ -121,9 +125,6 @@ HLSRepresentation * M3U8Parser::createRepresentation(BaseAdaptationSet *adaptSet
         if(bwAttr)
             rep->setBandwidth(bwAttr->decimal());
 
-        if(tag->getAttributeByName("CODECS"))
-            rep->addCodecs(tag->getAttributeByName("CODECS")->quotedString());
-
         if(resAttr)
         {
             std::pair<int, int> res = resAttr->getResolution();
@@ -159,6 +160,68 @@ void M3U8Parser::createAndFillRepresentation(vlc_object_t *p_obj, BaseAdaptation
     }
 }
 
+void M3U8Parser::fillRepresentationFromMediainfo(const AttributesTag *mediatag,
+                                                 const std::string &type,
+                                                 HLSRepresentation *rep)
+{
+    if(type == "AUDIO")
+    {
+        const Attribute *channelsAttr = mediatag->getAttributeByName("CHANNELS");
+        if(channelsAttr)
+            rep->setChannelsCount(std::atoi(channelsAttr->quotedString().c_str()));
+    }
+
+    if(type != "AUDIO" && type != "VIDEO" && type != "SUBTITLES")
+    {
+        rep->streamFormat = StreamFormat(StreamFormat::Type::Unsupported);
+    }
+}
+
+void M3U8Parser::fillAdaptsetFromMediainfo(const AttributesTag *mediatag,
+                                           const std::string &type,
+                                           const std::string &group,
+                                           BaseAdaptationSet *altAdaptSet)
+{
+    if(mediatag->getAttributeByName("DEFAULT"))
+    {
+        if(mediatag->getAttributeByName("DEFAULT")->value == "YES")
+            altAdaptSet->setRole(Role(Role::Value::Main));
+        else
+            altAdaptSet->setRole(Role(Role::Value::Alternate));
+    }
+
+    if(mediatag->getAttributeByName("AUTOSELECT"))
+    {
+        if(mediatag->getAttributeByName("AUTOSELECT")->value == "NO" &&
+           !mediatag->getAttributeByName("DEFAULT"))
+            altAdaptSet->setRole(Role(Role::Value::Supplementary));
+    }
+
+    /* Subtitles unsupported for now */
+    if(type == "SUBTITLES")
+    {
+        altAdaptSet->setRole(Role(Role::Value::Subtitle));
+    }
+
+    if(mediatag->getAttributeByName("LANGUAGE"))
+        altAdaptSet->setLang(mediatag->getAttributeByName("LANGUAGE")->quotedString());
+
+    std::string desc = group;
+    const Attribute *nameAttr = mediatag->getAttributeByName("NAME");
+    if(nameAttr)
+    {
+        if(!desc.empty())
+            desc += " ";
+        desc += nameAttr->quotedString();
+    }
+
+    if(!desc.empty())
+    {
+        altAdaptSet->description.Set(desc);
+        altAdaptSet->setID(ID(desc));
+    }
+}
+
 bool M3U8Parser::appendSegmentsFromPlaylistURI(vlc_object_t *p_obj, HLSRepresentation *rep)
 {
     block_t *p_block = Retrieve::HTTP(resources, ChunkType::Playlist, rep->getPlaylistUrl().toString());
@@ -425,11 +488,12 @@ M3U8 * M3U8Parser::parse(vlc_object_t *p_object, stream_t *p_stream, const std::
         return playlist;
 
     std::list<Tag *> tagslist = parseEntries(p_stream);
-    bool b_masterplaylist = !getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF).empty();
+    std::list<Tag *> streaminfotags = getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF);
+    bool b_masterplaylist = !streaminfotags.empty();
     if(b_masterplaylist)
     {
         std::list<Tag *>::const_iterator it;
-        std::map<std::string, AttributesTag *> groupsmap;
+        std::list<BaseAdaptationSet *> setstoadd;
 
         /* Preload Session Key */
         Tag *sessionKey = getTagFromList(tagslist, AttributesTag::EXTXSESSIONKEY);
@@ -446,119 +510,255 @@ M3U8 * M3U8Parser::parse(vlc_object_t *p_object, stream_t *p_stream, const std::
 
         /* We'll need to create an adaptation set for each media group / alternative rendering
          * we create a list of playlist being and alternative/group */
+        struct typecat_s
+        {
+            const char *type;
+            es_format_category_e cat;
+        };
+        std::array<struct typecat_s, 3> const typescats =
+        {{
+            { "AUDIO",      AUDIO_ES },
+            { "VIDEO",      VIDEO_ES },
+            { "SUBTITLES",  SPU_ES },
+        }};
+
+        struct StreamCodec
+        {
+            std::string codec;
+            es_format_category_e cat;
+        };
+
+        struct StreamInfos
+        {
+            const AttributesTag *tag;
+            std::string uri;
+            HLSRepresentation *rep;
+            std::list<struct StreamCodec> codecs;
+        };
+        std::list<struct StreamInfos> streaminfolist;
+
+        struct MediaInfos
+        {
+            const AttributesTag *tag;
+            std::string uri;
+            std::string group;
+        };
+
+        using CodecStats = std::unordered_map<std::string, unsigned>;
+
+        std::unordered_map<std::string, CodecStats> groupsmap;
+        std::list<struct MediaInfos> mediainfos;
+
+        /* create group info */
         std::list<Tag *> mediainfotags = getTagsFromList(tagslist, AttributesTag::EXTXMEDIA);
         for(it = mediainfotags.begin(); it != mediainfotags.end(); ++it)
         {
             AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
-            if(tag && tag->getAttributeByName("URI"))
-            {
-                std::pair<std::string, AttributesTag *> pair(tag->getAttributeByName("URI")->quotedString(), tag);
-                groupsmap.insert(pair);
-            }
+            if(!tag)
+                continue;
+            const Attribute *groupid = tag->getAttributeByName("GROUP-ID");
+            if(!groupid) /* invalid */
+                continue;
+            const Attribute *uri = tag->getAttributeByName("URI");
+            MediaInfos entry;
+            entry.tag = tag;
+            entry.uri = uri ? uri->quotedString() : std::string();
+            entry.group = groupid->quotedString();
+            groupsmap.insert(std::pair<std::string, CodecStats>(entry.group, CodecStats()));
+            mediainfos.push_back(entry);
         }
 
-        /* Then we parse all playlists uri and add them, except when alternative */
-        BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
-        if(adaptSet)
+        /* Gather info from EXT-X-STREAMINF */
+        for(it = streaminfotags.begin(); it != streaminfotags.end(); ++it)
         {
-            /* adaptSet->setSegmentAligned(true); FIXME: based on streamformat */
-            std::list<Tag *> streaminfotags = getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF);
-            for(it = streaminfotags.begin(); it != streaminfotags.end(); ++it)
+            AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
+            if(!tag)
+                continue;
+
+            const Attribute *uri = tag->getAttributeByName("URI");
+            if(!uri)
+                continue;
+
+            StreamInfos entry;
+            entry.tag = tag;
+            entry.uri = uri->quotedString();
+            entry.rep = nullptr;
+
+            const Attribute *codecsAttr = tag->getAttributeByName("CODECS");
+            if(codecsAttr)
             {
-                AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
-                if(tag && tag->getAttributeByName("URI"))
+                auto codecs = Helper::tokenize(codecsAttr->quotedString(), ',');
+                for(auto codec : codecs)
+                {
+                    FormatNamespace fns(codec);
+                    struct StreamCodec s;
+                    s.cat = fns.getFmt()->i_cat;
+                    s.codec = codec;
+                    entry.codecs.push_front(s);
+                }
+
+                /* create codec reference count info per group */
+                std::list<std::string> mediasCodecs;
+                for(auto typecat : typescats)
                 {
-                    if(groupsmap.find(tag->getAttributeByName("URI")->value) == groupsmap.end())
+                    if(tag->getAttributeByName(typecat.type))
                     {
-                        /* not a group, belong to default adaptation set */
-                        HLSRepresentation *rep  = createRepresentation(adaptSet, tag);
-                        if(rep)
+                        for(auto codec : entry.codecs)
                         {
-                            adaptSet->addRepresentation(rep);
+                            if(codec.cat == typecat.cat)
+                            {
+                                auto mit = groupsmap.find(tag->getAttributeByName(typecat.type)->quotedString());
+                                if(mit != groupsmap.cend())
+                                {
+                                    auto eit = (*mit).second.find(codec.codec);
+                                    if(eit != (*mit).second.end())
+                                        ++(*eit).second;
+                                    else
+                                        (*mit).second.insert(std::pair<std::string, unsigned>(codec.codec, 0));
+                                    mediasCodecs.push_front(codec.codec);
+                                }
+                                break;
+                            }
                         }
                     }
                 }
+
+                /* remove most frequent group codecs from streaminfo */
+                for(auto codec : mediasCodecs)
+                    entry.codecs.remove_if([codec, entry](struct StreamCodec &v)
+                                        { return v.codec == codec && entry.codecs.size() > 1; });
+
+                /* deduplicate codecs by category as variants can have different profile */
+                entry.codecs.sort([](const struct StreamCodec &a, const struct StreamCodec &b)
+                    { return a.cat < b.cat ; });
+                entry.codecs.unique([](const struct StreamCodec &a, const struct StreamCodec &b)
+                    { return a.cat == b.cat ; });
             }
-            if(!adaptSet->getRepresentations().empty())
-                period->addAdaptationSet(adaptSet);
-            else
-                delete adaptSet;
+
+            streaminfolist.push_back(entry);
         }
 
-        /* Finally add all groups */
-        unsigned set_id = 1;
-        std::map<std::string, AttributesTag *>::const_iterator groupsit;
-        for(groupsit = groupsmap.begin(); groupsit != groupsmap.end(); ++groupsit)
+        /* process all EXT-X-STREAMINF and add them */
+        BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
+        if(adaptSet)
         {
-            std::pair<std::string, AttributesTag *> pair = *groupsit;
-            if(!pair.second->getAttributeByName("TYPE"))
-                continue;
-
-            BaseAdaptationSet *altAdaptSet = new (std::nothrow) BaseAdaptationSet(period);
-            if(altAdaptSet)
+            /* adaptSet->setSegmentAligned(true); FIXME: based on streamformat */
+            for(auto &info : streaminfolist)
             {
-                HLSRepresentation *rep  = createRepresentation(altAdaptSet, pair.second);
-                if(rep)
-                {
-                    altAdaptSet->addRepresentation(rep);
-                }
+                if(info.uri.empty())
+                    continue;
 
-                std::string desc;
-                if(pair.second->getAttributeByName("GROUP-ID"))
-                    desc = pair.second->getAttributeByName("GROUP-ID")->quotedString();
-                if(pair.second->getAttributeByName("NAME"))
-                {
-                    if(!desc.empty())
-                        desc += " ";
-                    desc += pair.second->getAttributeByName("NAME")->quotedString();
-                }
+                HLSRepresentation *rep  = createRepresentation(adaptSet, info.tag);
+                if(!rep)
+                    continue;
 
-                if(pair.second->getAttributeByName("CODECS"))
-                    rep->addCodecs(pair.second->getAttributeByName("CODECS")->quotedString());
+                for(auto codec: info.codecs)
+                    rep->addCodecs(codec.codec);
 
-                if(!desc.empty())
+                if(adaptSet->description.Get().empty() &&
+                   info.tag->getAttributeByName("NAME"))
                 {
-                    altAdaptSet->description.Set(desc);
-                    altAdaptSet->setID(ID(desc));
+                    adaptSet->description.Set(info.tag->getAttributeByName("NAME")->quotedString());
                 }
-                else altAdaptSet->setID(ID(set_id++));
 
-                if(pair.second->getAttributeByName("DEFAULT"))
-                {
-                    if(pair.second->getAttributeByName("DEFAULT")->value == "YES")
-                        altAdaptSet->setRole(Role(Role::Value::Main));
-                    else
-                        altAdaptSet->setRole(Role(Role::Value::Alternate));
-                }
+                adaptSet->addRepresentation(rep);
+                info.rep = rep;
+            }
 
-                if(pair.second->getAttributeByName("AUTOSELECT"))
-                {
-                    if(pair.second->getAttributeByName("AUTOSELECT")->value == "NO" &&
-                       !pair.second->getAttributeByName("DEFAULT"))
-                        altAdaptSet->setRole(Role(Role::Value::Supplementary));
-                }
+            if(adaptSet->getRepresentations().empty())
+            {
+                delete adaptSet;
+                adaptSet = nullptr;
+            }
+            else setstoadd.push_front(adaptSet);
+        }
+
+        /* Finally add all EXT-X-MEDIA or propagate their attributes */
+        for(auto mediainfo : mediainfos)
+        {
+            const Attribute *typeattr = mediainfo.tag->getAttributeByName("TYPE");
+            if(!typeattr)
+                continue;
+            const std::string &mediatype = typeattr->value;
 
-                /* Subtitles unsupported for now */
-                const Attribute *typeattr = pair.second->getAttributeByName("TYPE");
-                if(typeattr->value == "SUBTITLES")
+            const StreamInfos *matchedstreaminf = nullptr;
+            if(!mediainfo.uri.empty())
+            {
+                auto sit = std::find_if(streaminfolist.begin(), streaminfolist.end(),
+                                    [mediainfo] (StreamInfos &si)
+                                   { return si.uri == mediainfo.uri; });
+                if(sit != streaminfolist.end())
+                    matchedstreaminf = & (*sit);
+            };
+
+            if(mediainfo.uri.empty() || matchedstreaminf) /* Attributes do apply to group STREAMINF members */
+            {
+                if(mediatype == "AUDIO" || mediatype == "VIDEO")
+                for(StreamInfos &si : streaminfolist)
                 {
-                    altAdaptSet->setRole(Role(Role::Value::Subtitle));
+                    if(matchedstreaminf && matchedstreaminf != &si)
+                        continue;
+                    const Attribute *groupattr = si.tag->getAttributeByName(mediatype.c_str());
+                    if(groupattr && groupattr->quotedString() == mediainfo.group)
+                    {
+                        if(si.rep)
+                        {
+                            fillAdaptsetFromMediainfo(mediainfo.tag, typeattr->value,
+                                                      mediainfo.group, si.rep->getAdaptationSet());
+                            if(!matchedstreaminf || matchedstreaminf == &si)
+                                fillRepresentationFromMediainfo(mediainfo.tag, typeattr->value, si.rep);
+                        }
+                    }
                 }
-                else if(typeattr->value != "AUDIO" && typeattr->value != "VIDEO")
+            }
+            else /* This is an alternative in the group */
+            {
+                BaseAdaptationSet *altAdaptSet = new (std::nothrow) BaseAdaptationSet(period);
+                if(altAdaptSet)
                 {
-                    rep->streamFormat = StreamFormat(StreamFormat::Type::Unsupported);
-                }
+                    fillAdaptsetFromMediainfo(mediainfo.tag, typeattr->value, mediainfo.group, altAdaptSet);
 
-                if(pair.second->getAttributeByName("LANGUAGE"))
-                    altAdaptSet->setLang(pair.second->getAttributeByName("LANGUAGE")->quotedString());
+                    HLSRepresentation *rep  = createRepresentation(altAdaptSet, mediainfo.tag);
+                    if(!rep)
+                    {
+                        delete altAdaptSet;
+                        continue;
+                    }
 
-                if(!altAdaptSet->getRepresentations().empty())
-                    period->addAdaptationSet(altAdaptSet);
-                else
-                    delete altAdaptSet;
+                    fillRepresentationFromMediainfo(mediainfo.tag, typeattr->value, rep);
+
+                    /* assign group codecs to adaptset */
+                    auto groupmapit = groupsmap.find(mediainfo.group);
+                    if(groupmapit != groupsmap.end())
+                    {
+                        for(auto p : (*groupmapit).second)
+                        {
+                            FormatNamespace fns(p.first);
+                            for(auto typecat : typescats)
+                            {
+                                if((fns.getFmt()->i_cat == typecat.cat && typeattr->value == typecat.type))
+                                {
+                                    rep->addCodecs(p.first);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+
+                    altAdaptSet->addRepresentation(rep);
+                    setstoadd.push_front(altAdaptSet);
+	}
             }
         }
 
+        /* late add to keep it ordered */
+        unsigned set_id = 1;
+        for(auto set : setstoadd)
+        {
+            if(!set->getID().isValid())
+                set->setID(ID(set_id++));
+            period->addAdaptationSet(set);
+        }
     }
     else /* Non master playlist (opened directly subplaylist or HLS v1) */
     {


=====================================
modules/demux/hls/playlist/Parser.hpp
=====================================
@@ -65,6 +65,10 @@ namespace hls
                 HLSRepresentation * createRepresentation(BaseAdaptationSet *, const AttributesTag *);
                 void createAndFillRepresentation(vlc_object_t *, BaseAdaptationSet *,
                                                  const AttributesTag *, const std::list<Tag *>&);
+                void fillRepresentationFromMediainfo(const AttributesTag *, const std::string &,
+                                                     HLSRepresentation *);
+                void fillAdaptsetFromMediainfo(const AttributesTag *, const std::string &,
+                                               const std::string &, BaseAdaptationSet *);
                 void parseSegments(vlc_object_t *, HLSRepresentation *, const std::list<Tag *>&);
                 std::list<Tag *> parseEntries(stream_t *);
                 adaptive::SharedResources *resources;



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5e58b6a9fa37d2fa11384cce6714c52811281146...ee3213605d176c0a884b1d93dff7fc48b8848400

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5e58b6a9fa37d2fa11384cce6714c52811281146...ee3213605d176c0a884b1d93dff7fc48b8848400
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list