demux: adaptive: match namespaces

This commit is contained in:
François Cartegnie 2024-03-21 14:10:33 +01:00 committed by Steve Lhomme
parent a65d6118ec
commit f8b95a0383
11 changed files with 114 additions and 70 deletions

View File

@ -29,53 +29,56 @@
using namespace adaptive::xml;
std::vector<Node *> DOMHelper::getElementByTagName (Node *root, const std::string& name, bool selfContain)
std::vector<Node *> DOMHelper::getElementByTagName(Node *root, const std::string& name,
const std::string& ns, bool selfContain)
{
std::vector<Node *> elements;
for(size_t i = 0; i < root->getSubNodes().size(); i++)
{
getElementsByTagName(root->getSubNodes().at(i), name, &elements, selfContain);
getElementsByTagName(root->getSubNodes().at(i), name, ns, &elements, selfContain);
}
return elements;
}
std::vector<Node *> DOMHelper::getChildElementByTagName (Node *root, const std::string& name)
std::vector<Node *> DOMHelper::getChildElementByTagName(Node *root, const std::string& name,
const std::string& ns)
{
std::vector<Node *> elements;
for(size_t i = 0; i < root->getSubNodes().size(); i++)
{
if( root->getSubNodes().at(i)->getName() == name )
if(root->getSubNodes().at(i)->matches(name, ns))
elements.push_back(root->getSubNodes().at(i));
}
return elements;
}
void DOMHelper::getElementsByTagName (Node *root, const std::string& name, std::vector<Node*> *elements, bool selfContain)
void DOMHelper::getElementsByTagName(Node *root, const std::string& name, const std::string &ns,
std::vector<Node*> *elements, bool selfContain)
{
if(!selfContain && !root->getName().compare(name))
if(!selfContain && root->matches(name, ns))
{
elements->push_back(root);
return;
}
if(!root->getName().compare(name))
if(root->matches(name, ns))
elements->push_back(root);
for(size_t i = 0; i < root->getSubNodes().size(); i++)
{
getElementsByTagName(root->getSubNodes().at(i), name, elements, selfContain);
getElementsByTagName(root->getSubNodes().at(i), name, ns, elements, selfContain);
}
}
Node* DOMHelper::getFirstChildElementByName( Node *root, const std::string &name )
Node* DOMHelper::getFirstChildElementByName(Node *root, const std::string &name, const std::string& ns)
{
for(size_t i = 0; i < root->getSubNodes().size(); i++)
{
if( root->getSubNodes().at( i )->getName() == name )
if(root->getSubNodes().at(i)->matches(name, ns))
return root->getSubNodes().at( i );
}
return nullptr;

View File

@ -37,12 +37,16 @@ namespace adaptive
class DOMHelper
{
public:
static std::vector<Node *> getElementByTagName (Node *root, const std::string& name, bool selfContain);
static std::vector<Node *> getChildElementByTagName (Node *root, const std::string& name);
static Node* getFirstChildElementByName( Node *root, const std::string& name );
static std::vector<Node *> getElementByTagName (Node *root, const std::string& name,
const std::string& ns, bool selfContain);
static std::vector<Node *> getChildElementByTagName (Node *root, const std::string& name,
const std::string& ns);
static Node* getFirstChildElementByName(Node *root, const std::string& name,
const std::string& ns);
private:
static void getElementsByTagName(Node *root, const std::string& name, std::vector<Node *> *elements, bool selfContain);
static void getElementsByTagName(Node *root, const std::string& name, const std::string &ns,
std::vector<Node *> *elements, bool selfContain);
};
}
}

View File

@ -29,6 +29,7 @@
#include <vector>
#include <stack>
#include <cstring>
#include <vlc_xml.h>
using namespace adaptive::xml;
@ -92,18 +93,22 @@ bool DOMParser::reset(stream_t *s)
Node* DOMParser::processNode(bool b_strict)
{
const char *data;
const char *data, *ns;
int type;
std::stack<Node *> lifo;
while( (type = xml_ReaderNextNode(vlc_reader, &data)) > 0 )
while( (type = xml_ReaderNextNodeNS(vlc_reader, &data, &ns)) > 0 )
{
switch(type)
{
case XML_READER_STARTELEM:
{
Namespaces::Ptr ptr = nss.registerNamespace(ns);
bool empty = xml_ReaderIsEmptyElement(vlc_reader);
Node *node = new (std::nothrow) Node(std::make_unique<std::string>(data));
const char *unprefixed = std::strchr(data, ':');
data = unprefixed ? unprefixed + 1 : data;
auto name = std::make_unique<std::string>(data);
Node *node = new (std::nothrow) Node(std::move(name), ptr);
if(node)
{
if(!lifo.empty())
@ -159,12 +164,14 @@ void DOMParser::addAttributesToNode (Node *node)
{
const char *attrValue;
const char *attrName;
const char *ns;
while((attrName = xml_ReaderNextAttr(this->vlc_reader, &attrValue)) != nullptr)
while((attrName = xml_ReaderNextAttrNS(this->vlc_reader, &attrValue, &ns)) != nullptr)
{
Namespaces::Ptr ptr = nss.registerNamespace(ns ? ns : "");
std::string key = attrName;
std::string value = attrValue;
node->addAttribute(key, value);
node->addAttribute(key, ptr, value);
}
}
void DOMParser::print (Node *node, int offset)

View File

@ -47,6 +47,7 @@ namespace adaptive
void print ();
private:
Namespaces nss;
Node *root;
stream_t *stream;

View File

@ -36,17 +36,17 @@ using namespace adaptive::xml;
const std::string Node::EmptyString = "";
bool Node::Attribute::matches(const std::string &name) const
bool Node::Attribute::matches(const std::string &name, const std::string &ns) const
{
return this->name == name;
return *this->ns == ns && this->name == name;
}
Node::Node(std::unique_ptr<std::string> name)
Node::Node(std::unique_ptr<std::string> name, Namespaces::Ptr ns)
{
this->name = std::move(name);
this->ns = ns;
}
Node::~Node ()
{
for(size_t i = 0; i < this->subNodes.size(); i++)
@ -63,31 +63,49 @@ void Node::addSubNode (Node *node)
}
const std::string& Node::getName () const
{
return *this->name;
return *name;
}
const std::string & Node::getNamespace() const
{
if(ns != nullptr)
return *ns;
return EmptyString;
}
bool Node::hasAttribute(const std::string& name) const
{
return hasAttribute(name, EmptyString);
}
bool Node::hasAttribute(const std::string& name, const std::string &ns) const
{
auto it = std::find_if(attributes.cbegin(),attributes.cend(),
[name](const struct Attribute &a)
{return a.name == name;});
[name, ns](const struct Attribute &a)
{return a.name == name && ns == *a.ns;});
return it != attributes.cend();
}
const std::string& Node::getAttributeValue(const std::string& key) const
{
return getAttributeValue(key, EmptyString);
}
const std::string& Node::getAttributeValue(const std::string& key, const std::string &ns) const
{
auto it = std::find_if(attributes.cbegin(),attributes.cend(),
[key](const struct Attribute &a)
{return a.name == key;});
[key, ns](const struct Attribute &a)
{return a.name == key && ns == *a.ns;});
if (it != attributes.cend())
return (*it).value;
return EmptyString;
}
void Node::addAttribute(const std::string& key, const std::string& value)
void Node::addAttribute(const std::string& key, Namespaces::Ptr ns, const std::string& value)
{
struct Attribute attr;
attr.name = key;
attr.ns = ns;
attr.value = value;
attributes.push_back(std::move(attr));
}
@ -107,7 +125,7 @@ const Node::Attributes& Node::getAttributes() const
return this->attributes;
}
bool Node::matches(const std::string &name) const
bool Node::matches(const std::string &name, const std::string &ns) const
{
return *this->name == name;
return *this->ns == ns && *this->name == name;
}

View File

@ -25,9 +25,10 @@
#ifndef NODE_H_
#define NODE_H_
#include "Namespaces.hpp"
#include <vector>
#include <string>
#include <memory>
namespace adaptive
{
@ -41,33 +42,37 @@ namespace adaptive
public:
std::string name;
std::string value;
bool matches(const std::string &name) const;
Namespaces::Ptr ns;
bool matches(const std::string &name, const std::string &ns) const;
};
using Attributes = std::vector<struct Attribute>;
Node () = delete;
Node(std::unique_ptr<std::string>);
Node(std::unique_ptr<std::string>, Namespaces::Ptr);
~Node ();
const std::vector<Node *>& getSubNodes () const;
void addSubNode (Node *node);
const std::string& getName () const;
const std::string& getNamespace () const;
bool hasAttribute (const std::string& key) const;
void addAttribute (const std::string& key, const std::string& value);
bool hasAttribute (const std::string& key, const std::string &ns) const;
void addAttribute (const std::string& key, Namespaces::Ptr, const std::string& value);
const std::string& getAttributeValue (const std::string& key) const;
const std::string& getAttributeValue (const std::string& key, const std::string &ns) const;
const std::string& getText () const;
void setText( const std::string &text );
const Attributes& getAttributes () const;
bool matches(const std::string &name) const;
bool matches(const std::string &name, const std::string &ns) const;
private:
static const std::string EmptyString;
std::vector<Node *> subNodes;
Attributes attributes;
std::unique_ptr<std::string> name;
Namespaces::Ptr ns;
std::string text;
};
}
}

View File

@ -168,23 +168,16 @@ int DASHManager::doControl(int i_query, va_list args)
bool DASHManager::isDASH(xml::Node *root)
{
static const std::string namespaces[] = {
"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011",
"urn:mpeg:schema:dash:mpd:2011",
"urn:mpeg:dash:schema:mpd:2011",
"urn:mpeg:DASH:schema:MPD:2011",
"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011",
"urn:mpeg:schema:dash:mpd:2011",
"urn:mpeg:DASH:schema:MPD:2011",
"urn:mpeg:mpegB:schema:DASH:MPD:DIS2011",
};
if(root->getName() != "MPD")
return false;
const std::string &ns = root->getAttributeValue("xmlns");
for( size_t i=0; i<ARRAY_SIZE(namespaces); i++ )
{
if ( adaptive::Helper::ifind(ns, namespaces[i]) )
if(root->matches("MPD", namespaces[i]))
return true;
}
return false;
}

View File

@ -83,7 +83,7 @@ static void parseAvailability(MPD *mpd, Node *node, T *s)
void IsoffMainParser::parseMPDBaseUrl(MPD *mpd, Node *root)
{
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(root, "BaseURL");
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(root, "BaseURL", getDASHNamespace());
for(size_t i = 0; i < baseUrls.size(); i++)
mpd->addBaseUrl(baseUrls.at(i)->getText());
@ -97,7 +97,7 @@ MPD * IsoffMainParser::parse()
if(mpd)
{
parseMPDAttributes(mpd, root);
parseProgramInformation(DOMHelper::getFirstChildElementByName(root, "ProgramInformation"), mpd);
parseProgramInformation(DOMHelper::getFirstChildElementByName(root, "ProgramInformation", getDASHNamespace()), mpd);
parseMPDBaseUrl(mpd, root);
parsePeriods(mpd, root);
mpd->addAttribute(new StartnumberAttr(1));
@ -114,6 +114,9 @@ void IsoffMainParser::parseMPDAttributes (MPD *mpd, xml::Node *node)
for(auto attr: attributes)
{
if(*attr.ns != NS_DASH)
continue;
if(attr.name == "mediaPresentationDuration")
{
mpd->duration.Set(IsoTime(attr.value));
@ -158,7 +161,7 @@ void IsoffMainParser::parseMPDAttributes (MPD *mpd, xml::Node *node)
void IsoffMainParser::parsePeriods(MPD *mpd, Node *root)
{
std::vector<Node *> periods = DOMHelper::getElementByTagName(root, "Period", false);
std::vector<Node *> periods = DOMHelper::getElementByTagName(root, "Period", getDASHNamespace(), false);
std::vector<Node *>::const_iterator it;
uint64_t nextid = 0;
@ -172,7 +175,7 @@ void IsoffMainParser::parsePeriods(MPD *mpd, Node *root)
period->startTime.Set(IsoTime((*it)->getAttributeValue("start")));
if((*it)->hasAttribute("duration"))
period->duration.Set(IsoTime((*it)->getAttributeValue("duration")));
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(*it, "BaseURL");
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(*it, "BaseURL", getDASHNamespace());
if(!baseUrls.empty())
{
period->baseUrl.Set( new Url( baseUrls.front()->getText() ) );
@ -188,7 +191,7 @@ void IsoffMainParser::parseSegmentBaseType(MPD *, Node *node,
AbstractSegmentBaseType *base,
SegmentInformation *parent)
{
parseInitSegment(DOMHelper::getFirstChildElementByName(node, "Initialization"), base, parent);
parseInitSegment(DOMHelper::getFirstChildElementByName(node, "Initialization", getDASHNamespace()), base, parent);
if(node->hasAttribute("indexRange"))
{
@ -226,7 +229,7 @@ void IsoffMainParser::parseMultipleSegmentBaseType(MPD *mpd, Node *node,
if(node->hasAttribute("startNumber"))
base->addAttribute(new StartnumberAttr(Integer<uint64_t>(node->getAttributeValue("startNumber"))));
parseTimeline(DOMHelper::getFirstChildElementByName(node, "SegmentTimeline"), base);
parseTimeline(DOMHelper::getFirstChildElementByName(node, "SegmentTimeline", getDASHNamespace()), base);
}
size_t IsoffMainParser::parseSegmentTemplate(MPD *mpd, Node *templateNode, SegmentInformation *info)
@ -269,9 +272,9 @@ size_t IsoffMainParser::parseSegmentInformation(MPD *mpd, Node *node,
SegmentInformation *info, uint64_t *nextid)
{
size_t total = 0;
total += parseSegmentBase(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentBase"), info);
total += parseSegmentList(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentList"), info);
total += parseSegmentTemplate(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentTemplate" ), info);
total += parseSegmentBase(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentBase", getDASHNamespace()), info);
total += parseSegmentList(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentList", getDASHNamespace()), info);
total += parseSegmentTemplate(mpd, DOMHelper::getFirstChildElementByName(node, "SegmentTemplate", getDASHNamespace()), info);
if(node->hasAttribute("timescale"))
info->addAttribute(new TimescaleAttr(Timescale(Integer<uint64_t>(node->getAttributeValue("timescale")))));
@ -287,7 +290,7 @@ size_t IsoffMainParser::parseSegmentInformation(MPD *mpd, Node *node,
void IsoffMainParser::parseAdaptationSets (MPD *mpd, Node *periodNode, BasePeriod *period)
{
std::vector<Node *> adaptationSets = DOMHelper::getElementByTagName(periodNode, "AdaptationSet", false);
std::vector<Node *> adaptationSets = DOMHelper::getElementByTagName(periodNode, "AdaptationSet", getDASHNamespace(), false);
std::vector<Node *>::const_iterator it;
uint64_t nextid = 0;
@ -308,14 +311,14 @@ void IsoffMainParser::parseAdaptationSets (MPD *mpd, Node *periodNode, BaseP
if((*it)->hasAttribute("segmentAlignment"))
adaptationSet->setSegmentAligned((*it)->getAttributeValue("segmentAlignment") == "true");
Node *baseUrl = DOMHelper::getFirstChildElementByName((*it), "BaseURL");
Node *baseUrl = DOMHelper::getFirstChildElementByName((*it), "BaseURL", getDASHNamespace());
if(baseUrl)
{
parseAvailability<AdaptationSet>(mpd, baseUrl, adaptationSet);
adaptationSet->baseUrl.Set(new Url(baseUrl->getText()));
}
Node *role = DOMHelper::getFirstChildElementByName((*it), "Role");
Node *role = DOMHelper::getFirstChildElementByName((*it), "Role", getDASHNamespace());
if(role && role->hasAttribute("schemeIdUri") && role->hasAttribute("value"))
{
const std::string &uri = role->getAttributeValue("schemeIdUri");
@ -371,7 +374,7 @@ void IsoffMainParser::parseCommonAttributesElements(Node *node,
void IsoffMainParser::parseRepresentations (MPD *mpd, Node *adaptationSetNode, AdaptationSet *adaptationSet)
{
std::vector<Node *> representations = DOMHelper::getElementByTagName(adaptationSetNode, "Representation", false);
std::vector<Node *> representations = DOMHelper::getElementByTagName(adaptationSetNode, "Representation", getDASHNamespace(), false);
uint64_t nextid = 0;
for(size_t i = 0; i < representations.size(); i++)
@ -379,7 +382,7 @@ void IsoffMainParser::parseRepresentations (MPD *mpd, Node *adaptationSetNode
Representation *currentRepresentation = new Representation(adaptationSet);
Node *repNode = representations.at(i);
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(repNode, "BaseURL");
std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(repNode, "BaseURL", getDASHNamespace());
if(!baseUrls.empty())
{
currentRepresentation->baseUrl.Set(new Url(baseUrls.front()->getText()));
@ -440,7 +443,7 @@ size_t IsoffMainParser::parseSegmentList(MPD *mpd, Node * segListNode, SegmentIn
size_t total = 0;
if(segListNode)
{
std::vector<Node *> segments = DOMHelper::getElementByTagName(segListNode, "SegmentURL", false);
std::vector<Node *> segments = DOMHelper::getElementByTagName(segListNode, "SegmentURL", getDASHNamespace(), false);
SegmentList *list;
if((list = new (std::nothrow) SegmentList(info)))
{
@ -524,7 +527,7 @@ void IsoffMainParser::parseTimeline(Node *node, AbstractMultipleSegmentBaseType
SegmentTimeline *timeline = new (std::nothrow) SegmentTimeline(base);
if(timeline)
{
std::vector<Node *> elements = DOMHelper::getElementByTagName(node, "S", false);
std::vector<Node *> elements = DOMHelper::getElementByTagName(node, "S", getDASHNamespace(), false);
std::vector<Node *>::const_iterator it;
for(it = elements.begin(); it != elements.end(); ++it)
{
@ -562,15 +565,15 @@ void IsoffMainParser::parseProgramInformation(Node * node, MPD *mpd)
ProgramInformation *info = new (std::nothrow) ProgramInformation();
if (info)
{
Node *child = DOMHelper::getFirstChildElementByName(node, "Title");
Node *child = DOMHelper::getFirstChildElementByName(node, "Title", getDASHNamespace());
if(child)
info->setTitle(child->getText());
child = DOMHelper::getFirstChildElementByName(node, "Source");
child = DOMHelper::getFirstChildElementByName(node, "Source", getDASHNamespace());
if(child)
info->setSource(child->getText());
child = DOMHelper::getFirstChildElementByName(node, "Copyright");
child = DOMHelper::getFirstChildElementByName(node, "Copyright", getDASHNamespace());
if(child)
info->setCopyright(child->getText());
@ -603,3 +606,8 @@ Profile IsoffMainParser::getProfile() const
return res;
}
const std::string & IsoffMainParser::getDASHNamespace() const
{
return root->getNamespace();
}

View File

@ -61,6 +61,8 @@ namespace dash
using namespace adaptive::playlist;
using namespace adaptive;
static const std::string NS_DASH("urn:mpeg:dash:schema:mpd:2011");
class IsoffMainParser
{
public:
@ -71,6 +73,7 @@ namespace dash
private:
mpd::Profile getProfile () const;
const std::string & getDASHNamespace() const;
void parseMPDBaseUrl (MPD *, xml::Node *);
void parseMPDAttributes (MPD *, xml::Node *);
void parseAdaptationSets (MPD *, xml::Node *periodNode, BasePeriod *period);

View File

@ -28,6 +28,8 @@ namespace smooth
{
using namespace adaptive::playlist;
static std::string NS_SMOOTH = "";
class Manifest : public BasePlaylist
{
friend class ManifestParser;

View File

@ -58,7 +58,7 @@ static SegmentTimeline *createTimeline(Node *streamIndexNode)
SegmentTimeline *timeline = new (std::nothrow) SegmentTimeline(nullptr);
if(timeline)
{
std::vector<Node *> chunks = DOMHelper::getElementByTagName(streamIndexNode, "c", true);
std::vector<Node *> chunks = DOMHelper::getElementByTagName(streamIndexNode, "c", NS_SMOOTH, true);
std::vector<Node *>::const_iterator it;
struct
@ -253,7 +253,7 @@ static void ParseStreamIndex(BasePeriod *period, Node *streamIndexNode, unsigned
unsigned nextid = 1;
const std::string &type = streamIndexNode->getAttributeValue("Type");
std::vector<Node *> qualLevels = DOMHelper::getElementByTagName(streamIndexNode, "QualityLevel", true);
std::vector<Node *> qualLevels = DOMHelper::getElementByTagName(streamIndexNode, "QualityLevel", NS_SMOOTH, true);
std::vector<Node *>::const_iterator it;
for(it = qualLevels.begin(); it != qualLevels.end(); ++it)
ParseQualityLevel(adaptSet, *it, type, nextid++, id, timescale);
@ -302,7 +302,7 @@ Manifest * ManifestParser::parse()
{
period->duration.Set(manifest->duration.Get());
unsigned nextid = 1;
std::vector<Node *> streamIndexes = DOMHelper::getElementByTagName(root, "StreamIndex", true);
std::vector<Node *> streamIndexes = DOMHelper::getElementByTagName(root, "StreamIndex", NS_SMOOTH, true);
std::vector<Node *>::const_iterator it;
for(it = streamIndexes.begin(); it != streamIndexes.end(); ++it)
ParseStreamIndex(period, *it, nextid++);