Commit 09c94ed7 authored by Francois Cartegnie's avatar Francois Cartegnie

demux: hls: modify sub/playlist parsing for lazy loading

parent 99f578d3
...@@ -143,8 +143,8 @@ static int Open(vlc_object_t *p_obj) ...@@ -143,8 +143,8 @@ static int Open(vlc_object_t *p_obj)
} }
else if(HLSManager::isHTTPLiveStreaming(p_demux->s)) else if(HLSManager::isHTTPLiveStreaming(p_demux->s))
{ {
Parser parser(p_demux->s); M3U8Parser parser;
M3U8 *p_playlist = parser.parse(playlisturl); M3U8 *p_playlist = parser.parse(p_demux->s, playlisturl);
if(!p_playlist) if(!p_playlist)
{ {
msg_Err( p_demux, "Could not parse MPD" ); msg_Err( p_demux, "Could not parse MPD" );
......
...@@ -154,8 +154,8 @@ bool HLSManager::updatePlaylist() ...@@ -154,8 +154,8 @@ bool HLSManager::updatePlaylist()
return false; return false;
} }
Parser parser(updatestream); M3U8Parser parser;
updatedplaylist = parser.parse(url); updatedplaylist = parser.parse(updatestream, url);
if(!updatedplaylist) if(!updatedplaylist)
{ {
stream_Delete(updatestream); stream_Delete(updatestream);
......
...@@ -42,12 +42,11 @@ using namespace adaptative; ...@@ -42,12 +42,11 @@ using namespace adaptative;
using namespace adaptative::playlist; using namespace adaptative::playlist;
using namespace hls::playlist; using namespace hls::playlist;
Parser::Parser(stream_t *stream) M3U8Parser::M3U8Parser()
{ {
p_stream = stream;
} }
Parser::~Parser () M3U8Parser::~M3U8Parser ()
{ {
} }
...@@ -71,52 +70,7 @@ static void releaseTagsList(std::list<Tag *> &list) ...@@ -71,52 +70,7 @@ static void releaseTagsList(std::list<Tag *> &list)
list.clear(); list.clear();
} }
void Parser::parseAdaptationSet(BasePeriod *period, const AttributesTag *) Representation * M3U8Parser::createRepresentation(BaseAdaptationSet *adaptSet, const AttributesTag * tag)
{
BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
if(adaptSet)
{
period->addAdaptationSet(adaptSet);
}
}
void Parser::parseRepresentation(BaseAdaptationSet *adaptSet, const AttributesTag * tag)
{
if(!tag->getAttributeByName("URI"))
return;
Url url;
if(tag->getType() == AttributesTag::EXTXMEDIA)
{
url = Url(tag->getAttributeByName("URI")->quotedString());
}
else
{
url = Url(tag->getAttributeByName("URI")->value);
}
if(!url.hasScheme())
url = url.prepend(adaptSet->getUrlSegment());
void *p_data;
const size_t i_data = Retrieve::HTTP((vlc_object_t*)p_stream, url.toString(), &p_data);
if(p_data)
{
stream_t *substream = stream_MemoryNew((vlc_object_t *)p_stream, (uint8_t *)p_data, i_data, false);
if(substream)
{
std::list<Tag *> tagslist = parseEntries(substream);
stream_Delete(substream);
parseRepresentation(adaptSet, tag, tagslist);
releaseTagsList(tagslist);
}
}
}
void Parser::parseRepresentation(BaseAdaptationSet *adaptSet, const AttributesTag * tag,
const std::list<Tag *> &tagslist)
{ {
const Attribute *uriAttr = tag->getAttributeByName("URI"); const Attribute *uriAttr = tag->getAttributeByName("URI");
const Attribute *bwAttr = tag->getAttributeByName("BANDWIDTH"); const Attribute *bwAttr = tag->getAttributeByName("BANDWIDTH");
...@@ -137,9 +91,14 @@ void Parser::parseRepresentation(BaseAdaptationSet *adaptSet, const AttributesTa ...@@ -137,9 +91,14 @@ void Parser::parseRepresentation(BaseAdaptationSet *adaptSet, const AttributesTa
{ {
uri = uriAttr->value; uri = uriAttr->value;
} }
size_t pos = uri.find_last_of('/'); rep->setID(uri);
if(pos != std::string::npos) rep->setPlaylistUrl(uri);
rep->baseUrl.Set(new Url(uri.substr(0, pos+1))); if(uri.find('/') != std::string::npos)
{
uri = Helper::getDirectoryPath(uri);
if(!uri.empty())
rep->baseUrl.Set(new Url(uri.append("/")));
}
} }
if(bwAttr) if(bwAttr)
...@@ -172,14 +131,45 @@ void Parser::parseRepresentation(BaseAdaptationSet *adaptSet, const AttributesTa ...@@ -172,14 +131,45 @@ void Parser::parseRepresentation(BaseAdaptationSet *adaptSet, const AttributesTa
rep->setHeight(res.second); rep->setHeight(res.second);
} }
} }
}
parseSegments(rep, tagslist); return rep;
}
void M3U8Parser::createAndFillRepresentation(vlc_object_t *p_obj, BaseAdaptationSet *adaptSet,
const AttributesTag *tag,
const std::list<Tag *> &tagslist)
{
Representation *rep = createRepresentation(adaptSet, tag);
if(rep)
{
parseSegments(p_obj, rep, tagslist);
adaptSet->addRepresentation(rep); adaptSet->addRepresentation(rep);
} }
} }
void Parser::parseSegments(Representation *rep, const std::list<Tag *> &tagslist) bool M3U8Parser::loadSegmentsFromPlaylistURI(vlc_object_t *p_obj, Representation *rep)
{
void *p_data;
const size_t i_data = Retrieve::HTTP(p_obj, rep->getPlaylistUrl().toString(), &p_data);
if(p_data)
{
stream_t *substream = stream_MemoryNew(p_obj, (uint8_t *)p_data, i_data, false);
if(substream)
{
std::list<Tag *> tagslist = parseEntries(substream);
stream_Delete(substream);
parseSegments(p_obj, rep, tagslist);
releaseTagsList(tagslist);
return true;
}
}
return false;
}
void M3U8Parser::parseSegments(vlc_object_t *p_obj, Representation *rep, const std::list<Tag *> &tagslist)
{ {
SegmentList *segmentList = new (std::nothrow) SegmentList(rep); SegmentList *segmentList = new (std::nothrow) SegmentList(rep);
rep->setSegmentList(segmentList); rep->setSegmentList(segmentList);
...@@ -276,8 +266,7 @@ void Parser::parseSegments(Representation *rep, const std::list<Tag *> &tagslist ...@@ -276,8 +266,7 @@ void Parser::parseSegments(Representation *rep, const std::list<Tag *> &tagslist
encryption.method = SegmentEncryption::AES_128; encryption.method = SegmentEncryption::AES_128;
encryption.key.clear(); encryption.key.clear();
uint8_t *p_data; uint8_t *p_data;
const uint64_t read = Retrieve::HTTP(VLC_OBJECT(p_stream), const uint64_t read = Retrieve::HTTP(p_obj, keytag->getAttributeByName("URI")->quotedString(),
keytag->getAttributeByName("URI")->quotedString(),
(void **) &p_data); (void **) &p_data);
if(p_data) if(p_data)
{ {
...@@ -321,7 +310,7 @@ void Parser::parseSegments(Representation *rep, const std::list<Tag *> &tagslist ...@@ -321,7 +310,7 @@ void Parser::parseSegments(Representation *rep, const std::list<Tag *> &tagslist
} }
} }
M3U8 * Parser::parse(const std::string &playlisturl) M3U8 * M3U8Parser::parse(stream_t *p_stream, const std::string &playlisturl)
{ {
char *psz_line = stream_ReadLine(p_stream); char *psz_line = stream_ReadLine(p_stream);
if(!psz_line || strcmp(psz_line, "#EXTM3U")) if(!psz_line || strcmp(psz_line, "#EXTM3U"))
...@@ -375,7 +364,12 @@ M3U8 * Parser::parse(const std::string &playlisturl) ...@@ -375,7 +364,12 @@ M3U8 * Parser::parse(const std::string &playlisturl)
if(groupsmap.find(tag->getAttributeByName("URI")->value) == groupsmap.end()) if(groupsmap.find(tag->getAttributeByName("URI")->value) == groupsmap.end())
{ {
/* not a group, belong to default adaptation set */ /* not a group, belong to default adaptation set */
parseRepresentation(adaptSet, tag); Representation *rep = createRepresentation(adaptSet, tag);
if(rep)
{
adaptSet->addRepresentation(rep);
loadSegmentsFromPlaylistURI(VLC_OBJECT(p_stream), rep);
}
} }
} }
} }
...@@ -393,7 +387,12 @@ M3U8 * Parser::parse(const std::string &playlisturl) ...@@ -393,7 +387,12 @@ M3U8 * Parser::parse(const std::string &playlisturl)
if(altAdaptSet) if(altAdaptSet)
{ {
std::pair<std::string, AttributesTag *> pair = *groupsit; std::pair<std::string, AttributesTag *> pair = *groupsit;
parseRepresentation(altAdaptSet, pair.second); Representation *rep = createRepresentation(altAdaptSet, pair.second);
if(rep)
{
altAdaptSet->addRepresentation(rep);
loadSegmentsFromPlaylistURI(VLC_OBJECT(p_stream), rep);
}
if(pair.second->getAttributeByName("NAME")) if(pair.second->getAttributeByName("NAME"))
altAdaptSet->description.Set(pair.second->getAttributeByName("NAME")->quotedString()); altAdaptSet->description.Set(pair.second->getAttributeByName("NAME")->quotedString());
...@@ -416,14 +415,15 @@ M3U8 * Parser::parse(const std::string &playlisturl) ...@@ -416,14 +415,15 @@ M3U8 * Parser::parse(const std::string &playlisturl)
} }
} }
else else /* Non master playlist (opened directly subplaylist or HLS v1) */
{ {
BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period); BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
if(adaptSet) if(adaptSet)
{ {
period->addAdaptationSet(adaptSet); period->addAdaptationSet(adaptSet);
AttributesTag *tag = new AttributesTag(AttributesTag::EXTXSTREAMINF, ""); AttributesTag *tag = new AttributesTag(AttributesTag::EXTXSTREAMINF, "");
parseRepresentation(adaptSet, tag, tagslist); tag->addAttribute(new Attribute("URI", playlisturl));
createAndFillRepresentation(VLC_OBJECT(p_stream), adaptSet, tag, tagslist);
delete tag; delete tag;
} }
} }
...@@ -436,7 +436,7 @@ M3U8 * Parser::parse(const std::string &playlisturl) ...@@ -436,7 +436,7 @@ M3U8 * Parser::parse(const std::string &playlisturl)
return playlist; return playlist;
} }
std::list<Tag *> Parser::parseEntries(stream_t *stream) std::list<Tag *> M3U8Parser::parseEntries(stream_t *stream)
{ {
std::list<Tag *> entrieslist; std::list<Tag *> entrieslist;
Tag *lastTag = NULL; Tag *lastTag = NULL;
......
...@@ -53,23 +53,21 @@ namespace hls ...@@ -53,23 +53,21 @@ namespace hls
class Tag; class Tag;
class Representation; class Representation;
class Parser class M3U8Parser
{ {
public: public:
Parser (stream_t *p_stream); M3U8Parser ();
virtual ~Parser (); virtual ~M3U8Parser ();
M3U8 * parse (const std::string &); M3U8 * parse (stream_t *p_stream, const std::string &);
bool loadSegmentsFromPlaylistURI(vlc_object_t *, Representation *);
private: private:
void parseAdaptationSet(BasePeriod *, const AttributesTag *); Representation * createRepresentation(BaseAdaptationSet *, const AttributesTag *);
void parseRepresentation(BaseAdaptationSet *, const AttributesTag *); void createAndFillRepresentation(vlc_object_t *, BaseAdaptationSet *,
void parseRepresentation(BaseAdaptationSet *, const AttributesTag *, const AttributesTag *, const std::list<Tag *>&);
const std::list<Tag *>&); void parseSegments(vlc_object_t *, Representation *, const std::list<Tag *>&);
void parseSegments(Representation *, const std::list<Tag *>&);
std::list<Tag *> parseEntries(stream_t *); std::list<Tag *> parseEntries(stream_t *);
stream_t *p_stream;
}; };
} }
} }
......
...@@ -57,6 +57,26 @@ bool Representation::isLive() const ...@@ -57,6 +57,26 @@ bool Representation::isLive() const
return b_live; return b_live;
} }
void Representation::setPlaylistUrl(const std::string &uri)
{
playlistUrl = Url(uri);
}
Url Representation::getPlaylistUrl() const
{
if(playlistUrl.hasScheme())
{
return playlistUrl;
}
else
{
Url ret = getParentUrlSegment();
if(!playlistUrl.empty())
ret.append(playlistUrl);
return ret;
}
}
void Representation::localMergeWithPlaylist(M3U8 *updated, mtime_t prunebarrier) void Representation::localMergeWithPlaylist(M3U8 *updated, mtime_t prunebarrier)
{ {
BasePeriod *period = updated->getFirstPeriod(); BasePeriod *period = updated->getFirstPeriod();
......
...@@ -35,20 +35,22 @@ namespace hls ...@@ -35,20 +35,22 @@ namespace hls
class Representation : public BaseRepresentation class Representation : public BaseRepresentation
{ {
friend class Parser; friend class M3U8Parser;
public: public:
Representation( BaseAdaptationSet * ); Representation( BaseAdaptationSet * );
virtual ~Representation (); virtual ~Representation ();
virtual StreamFormat getStreamFormat() const; /* reimpl */ virtual StreamFormat getStreamFormat() const; /* reimpl */
void setPlaylistUrl(const std::string &);
Url getPlaylistUrl() const;
void localMergeWithPlaylist(M3U8 *, mtime_t); void localMergeWithPlaylist(M3U8 *, mtime_t);
bool isLive() const; bool isLive() const;
virtual void mergeWith(SegmentInformation *, mtime_t); /* reimpl */ virtual void mergeWith(SegmentInformation *, mtime_t); /* reimpl */
private: private:
bool b_live; bool b_live;
Property<std::string> playlistUrl; Url playlistUrl;
Property<std::string> audio; Property<std::string> audio;
Property<std::string> video; Property<std::string> video;
Property<std::string> subtitles; Property<std::string> subtitles;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment