Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  IsoffMainParser.cpp   Sprache: C

 

/*
 * IsoffMainParser.cpp
 *****************************************************************************
 * Copyright (C) 2010 - 2012 Klagenfurt University
 *
 * Created on: Jan 27, 2012
 * Authors: Christopher Mueller <christopher.mueller@itec.uni-klu.ac.at>
 *          Christian Timmerer  <christian.timmerer@itec.uni-klu.ac.at>
 *
 * 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 the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "IsoffMainParser.h"
#include "../../adaptive/playlist/SegmentTemplate.h"
#include "../../adaptive/playlist/Segment.h"
#include "../../adaptive/playlist/SegmentBase.h"
#include "../../adaptive/playlist/SegmentList.h"
#include "../../adaptive/playlist/SegmentTimeline.h"
#include "../../adaptive/playlist/SegmentInformation.hpp"
#include "../../adaptive/playlist/BasePeriod.h"
#include "MPD.h"
#include "Representation.h"
#include "AdaptationSet.h"
#include "ProgramInformation.h"
#include "DASHSegment.h"
#include "../../adaptive/xml/DOMHelper.h"
#include "../../adaptive/tools/Helper.h"
#include "../../adaptive/tools/Debug.hpp"
#include "../../adaptive/tools/Conversions.hpp"
#include <vlc_stream.h>
#include <cstdio>
#include <limits>

using namespace dash::mpd;
using namespace adaptive::xml;
using namespace adaptive::playlist;

IsoffMainParser::IsoffMainParser    (Node *root_, vlc_object_t *p_object_,
                                     stream_t *stream, const std::string & streambaseurl_)
{
    root = root_;
    p_stream = stream;
    p_object = p_object_;
    playlisturl = streambaseurl_;
}

IsoffMainParser::~IsoffMainParser   ()
{
}

template <class T>
static void parseAvailability(MPD *mpd, Node *node, T *s)
{
    if(node->hasAttribute("availabilityTimeOffset"))
    {
        double val = Integer<double>(node->getAttributeValue("availabilityTimeOffset"));
        s->addAttribute(new AvailabilityTimeOffsetAttr(vlc_tick_from_sec(val)));
    }
    if(node->hasAttribute("availabilityTimeComplete"))
    {
        bool b = (node->getAttributeValue("availabilityTimeComplete") == "false");
        s->addAttribute(new AvailabilityTimeCompleteAttr(!b));
        if(b)
            mpd->setLowLatency(b);
    }
}

void IsoffMainParser::parseMPDBaseUrl(MPD *mpd, Node *root)
{
    std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(root, "BaseURL", getDASHNamespace());

    for(size_t i = 0; i < baseUrls.size(); i++)
        mpd->addBaseUrl(baseUrls.at(i)->getText());

    mpd->setPlaylistUrl( Helper::getDirectoryPath(playlisturl).append("/") );
}

MPD * IsoffMainParser::parse()
{
    MPD *mpd = new (std::nothrow) MPD(p_object, getProfile());
    if(mpd)
    {
        parseMPDAttributes(mpd, root);
        parseProgramInformation(DOMHelper::getFirstChildElementByName(root, "ProgramInformation", getDASHNamespace()), mpd);
        parseMPDBaseUrl(mpd, root);
        parsePeriods(mpd, root);
        mpd->addAttribute(new StartnumberAttr(1));
        mpd->debug();
    }
    return mpd;
}

void    IsoffMainParser::parseMPDAttributes   (MPD *mpd, xml::Node *node)
{
    const Node::Attributes& attributes = node->getAttributes();

    mpd->b_needsUpdates = false;

    for(auto & attr: attributes)
    {
        if(attr.name == "mediaPresentationDuration")
        {
            mpd->duration = IsoTime(attr.value);
        }
        else if(attr.name == "minBufferTime")
        {
            mpd->setMinBuffering(IsoTime(attr.value));
        }
        else if(attr.name == "minimumUpdatePeriod")
        {
            mpd->b_needsUpdates = true;
            vlc_tick_t minupdate = IsoTime(attr.value);
            if(minupdate > 0)
                mpd->minUpdatePeriod = minupdate;
        }
        else if(attr.name == "maxSegmentDuration")
        {
            mpd->maxSegmentDuration = IsoTime(attr.value);
        }
        else if(attr.name == "type")
        {
            mpd->setType(attr.value);
        }
        else if(attr.name == "availabilityStartTime")
        {
            mpd->availabilityStartTime = UTCTime(attr.value);
        }
        else if(attr.name == "availabilityEndTime")
        {
            mpd->availabilityEndTime = UTCTime(attr.value);
        }
        else if(attr.name == "timeShiftBufferDepth")
        {
            mpd->timeShiftBufferDepth = IsoTime(attr.value);
        }
        else if(attr.name == "suggestedPresentationDelay")
        {
            mpd->suggestedPresentationDelay = IsoTime(attr.value);
        }
    }
}

void IsoffMainParser::parsePeriods(MPD *mpd, Node *root)
{
    std::vector<Node *> periods = DOMHelper::getElementByTagName(root, "Period", getDASHNamespace(), false);
    std::vector<Node *>::const_iterator it;
    uint64_t nextid = 0;

    for(it = periods.begin(); it != periods.end(); ++it)
    {
        BasePeriod *period = new (std::nothrow) BasePeriod(mpd);
        if (!period)
            continue;
        parseSegmentInformation(mpd, *it, period, &nextid);
        if((*it)->hasAttribute("start"))
            period->startTime = IsoTime((*it)->getAttributeValue("start"));
        if((*it)->hasAttribute("duration"))
            period->duration = IsoTime((*it)->getAttributeValue("duration"));
        std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(*it, "BaseURL", getDASHNamespace());
        if(!baseUrls.empty())
        {
            period->baseUrl = new Url( baseUrls.front()->getText() );
            parseAvailability<BasePeriod>(mpd, baseUrls.front(), period);
        }

        parseAdaptationSets(mpd, *it, period);
        mpd->addPeriod(period);
    }
}

void IsoffMainParser::parseSegmentBaseType(MPD *, Node *node,
                                           AbstractSegmentBaseType *base,
                                           SegmentInformation *parent)
{
    parseInitSegment(DOMHelper::getFirstChildElementByName(node, "Initialization", getDASHNamespace()), base, parent);

    if(node->hasAttribute("indexRange"))
    {
        size_t start = 0, end = 0;
        if (std::sscanf(node->getAttributeValue("indexRange").c_str(), "%zu-%zu", &start, &end) == 2)
        {
            IndexSegment *index = new (std::nothrow) DashIndexSegment(parent);
            if(index)
            {
                index->setByteRange(start, end);
                base->indexSegment = index;
                /* index must be before data, so data starts at index end */
                if(dynamic_cast<SegmentBase *>(base))
                    dynamic_cast<SegmentBase *>(base)->setByteRange(end + 1, 0);
            }
        }
    }

    if(node->hasAttribute("timescale"))
    {
        TimescaleAttr *prop = new TimescaleAttr(Timescale(Integer<uint64_t>(node->getAttributeValue("timescale"))));
        base->addAttribute(prop);
    }
}

void IsoffMainParser::parseMultipleSegmentBaseType(MPD *mpd, Node *node,
                                                   AbstractMultipleSegmentBaseType *base,
                                                   SegmentInformation *parent)
{
    parseSegmentBaseType(mpd, node, base, parent);

    if(node->hasAttribute("duration"))
        base->addAttribute(new DurationAttr(Integer<stime_t>(node->getAttributeValue("duration"))));

    if(node->hasAttribute("startNumber"))
        base->addAttribute(new StartnumberAttr(Integer<uint64_t>(node->getAttributeValue("startNumber"))));

    parseTimeline(DOMHelper::getFirstChildElementByName(node, "SegmentTimeline", getDASHNamespace()), base);
}

size_t IsoffMainParser::parseSegmentTemplate(MPD *mpd, Node *templateNode, SegmentInformation *info)
{
    size_t total = 0;
    if (templateNode == nullptr)
        return total;

    std::string mediaurl;
    if(templateNode->hasAttribute("media"))
        mediaurl = templateNode->getAttributeValue("media");

    SegmentTemplate *mediaTemplate = new (std::nothrow) SegmentTemplate(new SegmentTemplateSegment(), info);
    if(!mediaTemplate)
        return total;
    mediaTemplate->setSourceUrl(mediaurl);

    parseMultipleSegmentBaseType(mpd, templateNode, mediaTemplate, info);

    parseAvailability<SegmentInformation>(mpd, templateNode, info);

    if(templateNode->hasAttribute("initialization")) /* /!\ != Initialization */
    {
        SegmentTemplateInit *initTemplate;
        const std::string &initurl = templateNode->getAttributeValue("initialization");
        if(!initurl.empty() && (initTemplate = new (std::nothrow) SegmentTemplateInit(mediaTemplate, info)))
        {
            initTemplate->setSourceUrl(initurl);
            delete mediaTemplate->initialisationSegment;
            mediaTemplate->initialisationSegment = initTemplate;
        }
    }

    info->setSegmentTemplate(mediaTemplate);

    return mediaurl.empty() ? ++total : 0;
}

size_t IsoffMainParser::parseSegmentInformation(MPD *mpd, Node *node,
                                                SegmentInformation *info, uint64_t *nextid)
{
    size_t total = 0;
    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")))));

    parseAvailability<SegmentInformation>(mpd, node, info);

    if(node->hasAttribute("id"))
        info->setID(ID(node->getAttributeValue("id")));
    else
        info->setID(ID((*nextid)++));

    return total;
}

void    IsoffMainParser::parseAdaptationSets  (MPD *mpd, Node *periodNode, BasePeriod *period)
{
    std::vector<Node *> adaptationSets = DOMHelper::getElementByTagName(periodNode, "AdaptationSet", getDASHNamespace(), false);
    std::vector<Node *>::const_iterator it;
    uint64_t nextid = 0;

    for(it = adaptationSets.begin(); it != adaptationSets.end(); ++it)
    {
        AdaptationSet *adaptationSet = new (std::nothrow) AdaptationSet(period);
        if(!adaptationSet)
            continue;

        parseCommonAttributesElements(*it, adaptationSet);

        if((*it)->hasAttribute("lang"))
            adaptationSet->setLang((*it)->getAttributeValue("lang"));

        if((*it)->hasAttribute("bitstreamSwitching"))
            adaptationSet->setBitswitchAble((*it)->getAttributeValue("bitstreamSwitching") == "true");

        if((*it)->hasAttribute("segmentAlignment"))
            adaptationSet->setSegmentAligned((*it)->getAttributeValue("segmentAlignment") == "true");

        Node *baseUrl = DOMHelper::getFirstChildElementByName((*it), "BaseURL", getDASHNamespace());
        if(baseUrl)
        {
            parseAvailability<AdaptationSet>(mpd, baseUrl, adaptationSet);
            adaptationSet->baseUrl = new Url(baseUrl->getText());
        }

        Node *role = DOMHelper::getFirstChildElementByName((*it), "Role", getDASHNamespace());
        if(role && role->hasAttribute("schemeIdUri") && role->hasAttribute("value"))
        {
            const std::string &uri = role->getAttributeValue("schemeIdUri");
            if(uri == "urn:mpeg:dash:role:2011")
            {
                const std::string &rolevalue = role->getAttributeValue("value");
                adaptationSet->description = rolevalue;
                if(rolevalue == "main")
                    adaptationSet->setRole(Role::Value::Main);
                else if(rolevalue == "alternate")
                    adaptationSet->setRole(Role::Value::Alternate);
                else if(rolevalue == "supplementary")
                    adaptationSet->setRole(Role::Value::Supplementary);
                else if(rolevalue == "commentary")
                    adaptationSet->setRole(Role::Value::Commentary);
                else if(rolevalue == "dub")
                    adaptationSet->setRole(Role::Value::Dub);
                else if(rolevalue == "caption")
                    adaptationSet->setRole(Role::Value::Caption);
                else if(rolevalue == "subtitle")
                    adaptationSet->setRole(Role::Value::Subtitle);
            }
        }

        parseSegmentInformation(mpd, *it, adaptationSet, &nextid);

        parseRepresentations(mpd, (*it), adaptationSet);

#ifdef ADAPTATIVE_ADVANCED_DEBUG
        if(adaptationSet->description.empty())
            adaptationSet->description = adaptationSet->getID().str();
#endif

        if(!adaptationSet->getRepresentations().empty())
            period->addAdaptationSet(adaptationSet);
        else
            delete adaptationSet;
    }
}

void IsoffMainParser::parseCommonAttributesElements(Node *node,
                                                    CommonAttributesElements *commonAttrElements)
{
    if(node->hasAttribute("width"))
        commonAttrElements->setWidth(atoi(node->getAttributeValue("width").c_str()));

    if(node->hasAttribute("height"))
        commonAttrElements->setHeight(atoi(node->getAttributeValue("height").c_str()));

    if(node->hasAttribute("mimeType"))
        commonAttrElements->setMimeType(node->getAttributeValue("mimeType"));
}

void    IsoffMainParser::parseRepresentations (MPD *mpd, Node *adaptationSetNode, AdaptationSet *adaptationSet)
{
    std::vector<Node *> representations = DOMHelper::getElementByTagName(adaptationSetNode, "Representation", getDASHNamespace(), false);
    uint64_t nextid = 0;

    for(size_t i = 0; i < representations.size(); i++)
    {
        Representation *currentRepresentation = new Representation(adaptationSet);
        Node *repNode = representations.at(i);

        std::vector<Node *> baseUrls = DOMHelper::getChildElementByTagName(repNode, "BaseURL", getDASHNamespace());
        if(!baseUrls.empty())
        {
            currentRepresentation->baseUrl = new Url(baseUrls.front()->getText());
            parseAvailability<Representation>(mpd, baseUrls.front(), currentRepresentation);
        }

        if(repNode->hasAttribute("id"))
            currentRepresentation->setID(ID(repNode->getAttributeValue("id")));

        parseCommonAttributesElements(repNode, currentRepresentation);

        if(repNode->hasAttribute("bandwidth"))
            currentRepresentation->setBandwidth(atoi(repNode->getAttributeValue("bandwidth").c_str()));

        if(repNode->hasAttribute("codecs"))
            currentRepresentation->addCodecs(repNode->getAttributeValue("codecs"));

        size_t i_total = parseSegmentInformation(mpd, repNode, currentRepresentation, &nextid);
        /* Empty Representation with just baseurl (ex: subtitles) */
        if(i_total == 0 &&
           (currentRepresentation->baseUrl && !currentRepresentation->baseUrl->empty()) &&
            adaptationSet->getMediaSegment(0) == nullptr)
        {
            SegmentBase *base = new (std::nothrow) SegmentBase(currentRepresentation);
            if(base)
                currentRepresentation->addAttribute(base);
        }

        adaptationSet->addRepresentation(currentRepresentation);
    }
}
size_t IsoffMainParser::parseSegmentBase(MPD *mpd, Node * segmentBaseNode, SegmentInformation *info)
{
    SegmentBase *base;

    if(!segmentBaseNode || !(base = new (std::nothrow) SegmentBase(info)))
        return 0;

    parseSegmentBaseType(mpd, segmentBaseNode, base, info);

    parseAvailability<SegmentInformation>(mpd, segmentBaseNode, info);

    if(!base->initialisationSegment && base->indexSegment && base->indexSegment->getOffset())
    {
        InitSegment *initSeg = new InitSegment( info );
        initSeg->setSourceUrl(base->getUrlSegment().toString());
        initSeg->setByteRange(0, base->indexSegment->getOffset() - 1);
        base->initialisationSegment = initSeg;
    }

    info->addAttribute(base);

    return 1;
}

size_t IsoffMainParser::parseSegmentList(MPD *mpd, Node * segListNode, SegmentInformation *info)
{
    size_t total = 0;
    if(segListNode)
    {
        std::vector<Node *> segments = DOMHelper::getElementByTagName(segListNode, "SegmentURL", getDASHNamespace(), false);
        SegmentList *list;
        if((list = new (std::nothrow) SegmentList(info)))
        {
            parseMultipleSegmentBaseType(mpd, segListNode, list, info);

            parseAvailability<SegmentInformation>(mpd, segListNode, info);

            uint64_t sequenceNumber = info->inheritStartNumber();
            if(sequenceNumber == std::numeric_limits<uint64_t>::max())
                sequenceNumber = 0;

            const stime_t duration = list->inheritDuration();
            stime_t nzStartTime = sequenceNumber * duration;
            std::vector<Node *>::const_iterator it;
            for(it = segments.begin(); it != segments.end(); ++it)
            {
                Node *segmentURL = *it;

                Segment *seg = new (std::nothrow) Segment(info);
                if(!seg)
                    continue;

                const std::string &mediaUrl = segmentURL->getAttributeValue("media");
                if(!mediaUrl.empty())
                    seg->setSourceUrl(mediaUrl);

                if(segmentURL->hasAttribute("mediaRange"))
                {
                    const std::string &range = segmentURL->getAttributeValue("mediaRange");
                    size_t pos = range.find("-");
                    seg->setByteRange(atoi(range.substr(0, pos).c_str()), atoi(range.substr(pos + 1, range.size()).c_str()));
                }

                seg->startTime = nzStartTime;
                seg->duration = duration;
                nzStartTime += duration;

                seg->setSequenceNumber(sequenceNumber++);

                list->addSegment(seg);
            }

            total = list->getSegments().size();
            info->updateSegmentList(list, true);
        }
    }
    return total;
}

void IsoffMainParser::parseInitSegment(Node *initNode, Initializable<InitSegment> *init, SegmentInformation *parent)
{
    if(!initNode)
        return;

    InitSegment *seg = new InitSegment( parent );
    seg->setSourceUrl(initNode->getAttributeValue("sourceURL"));

    if(initNode->hasAttribute("range"))
    {
        const std::string &range = initNode->getAttributeValue("range");
        size_t pos = range.find("-");
        seg->setByteRange(atoi(range.substr(0, pos).c_str()), atoi(range.substr(pos + 1, range.size()).c_str()));
    }

    init->initialisationSegment = seg;
}

void IsoffMainParser::parseTimeline(Node *node, AbstractMultipleSegmentBaseType *base)
{
    if(!node)
        return;

    uint64_t number = 0;
    if(node->hasAttribute("startNumber"))
        number = Integer<uint64_t>(node->getAttributeValue("startNumber"));
    else if(base->inheritStartNumber())
        number = base->inheritStartNumber();
    if(number == std::numeric_limits<uint64_t>::max())
        number = 1;

    SegmentTimeline *timeline = new (std::nothrow) SegmentTimeline(base);
    if(timeline)
    {
        std::vector<Node *> elements = DOMHelper::getElementByTagName(node, "S", getDASHNamespace(), false);
        std::vector<Node *>::const_iterator it;
        for(it = elements.begin(); it != elements.end(); ++it)
        {
            const Node *s = *it;
            if(!s->hasAttribute("d")) /* Mandatory */
                continue;
            stime_t d = Integer<stime_t>(s->getAttributeValue("d"));
            int64_t r = 0; // never repeats by default
            if(s->hasAttribute("r"))
            {
                r = Integer<int64_t>(s->getAttributeValue("r"));
                if(r < 0)
                    r = std::numeric_limits<unsigned>::max();
            }

            if(s->hasAttribute("t"))
            {
                stime_t t = Integer<stime_t>(s->getAttributeValue("t"));
                timeline->addElement(number, d, r, t);
            }
            else timeline->addElement(number, d, r);

            number += (1 + r);
        }
        //base->setSegmentTimeline(timeline);
        base->addAttribute(timeline);
    }
}

void IsoffMainParser::parseProgramInformation(Node * node, MPD *mpd)
{
    if(!node)
        return;

    ProgramInformation *info = new (std::nothrow) ProgramInformation();
    if (info)
    {
        Node *child = DOMHelper::getFirstChildElementByName(node, "Title", getDASHNamespace());
        if(child)
            info->setTitle(child->getText());

        child = DOMHelper::getFirstChildElementByName(node, "Source", getDASHNamespace());
        if(child)
            info->setSource(child->getText());

        child = DOMHelper::getFirstChildElementByName(node, "Copyright", getDASHNamespace());
        if(child)
            info->setCopyright(child->getText());

        if(node->hasAttribute("moreInformationURL"))
            info->setMoreInformationUrl(node->getAttributeValue("moreInformationURL"));

        mpd->programInfo = info;
    }
}

Profile IsoffMainParser::getProfile() const
{
    Profile res(Profile::Name::Unknown);
    if(this->root == nullptr)
        return res;

    std::string urn = root->getAttributeValue("profiles");
    if ( urn.length() == 0 )
        urn = root->getAttributeValue("profile"); //The standard spells it the both ways...

    size_t pos;
    size_t nextpos = std::string::npos;
    do
    {
        pos = nextpos + 1;
        nextpos = urn.find_first_of(",", pos);
        res = Profile(urn.substr(pos, nextpos - pos));
    }
    while (nextpos != std::string::npos && res == Profile::Name::Unknown);

    return res;
}

const std::string & IsoffMainParser::getDASHNamespace() const
{
    return root->getNamespace();
}

Messung
CHZG
83979993

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104857
#Domains=418073