<commit_before>/*
 * Parser.cpp
 *****************************************************************************
 * Copyright © 2015 - VideoLAN and VLC Authors
 *
 * 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 "Parser.hpp"
#include "HLSSegment.hpp"
#include "Representation.hpp"
#include "../adaptative/playlist/BasePeriod.h"
#include "../adaptative/playlist/BaseAdaptationSet.h"
#include "../adaptative/playlist/SegmentList.h"
#include "../adaptative/tools/Retrieve.hpp"
#include "../adaptative/tools/Helper.h"
#include "M3U8.hpp"
#include "Tags.hpp"

#include <vlc_strings.h>
#include <vlc_stream.h>
#include <cstdio>
#include <sstream>
#include <map>

using namespace adaptative;
using namespace adaptative::playlist;
using namespace hls::playlist;

Parser::Parser(stream_t *stream)
{
    p_stream = stream;
}

Parser::~Parser   ()
{
}

static std::list<Tag *> getTagsFromList(std::list<Tag *> &list, int tag)
{
    std::list<Tag *> ret;
    std::list<Tag *>::const_iterator it;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if( (*it)->getType() == tag )
            ret.push_back(*it);
    }
    return ret;
}

static void releaseTagsList(std::list<Tag *> &list)
{
    std::list<Tag *>::const_iterator it;
    for(it = list.begin(); it != list.end(); ++it)
        delete *it;
    list.clear();
}

void Parser::parseAdaptationSet(BasePeriod *period, const AttributesTag *)
{
    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 *bwAttr = tag->getAttributeByName("BANDWIDTH");
    const Attribute *codecsAttr = tag->getAttributeByName("CODECS");
    const Attribute *resAttr = tag->getAttributeByName("RESOLUTION");

    Representation *rep = new (std::nothrow) Representation(adaptSet);
    if(rep)
    {
        if(uriAttr)
        {
            std::string uri;
            if(tag->getType() == AttributesTag::EXTXMEDIA)
            {
                uri = uriAttr->quotedString();
            }
            else
            {
                uri = uriAttr->value;
            }
            size_t pos = uri.find_last_of('/');
            if(pos != std::string::npos)
                rep->baseUrl.Set(new Url(uri.substr(0, pos+1)));
        }

        if(bwAttr)
            rep->setBandwidth(bwAttr->decimal());

        if(codecsAttr)
        {
            std::list<std::string> list = Helper::tokenize(codecsAttr->quotedString(), ',');
            std::list<std::string>::const_iterator it;
            for(it=list.begin(); it!=list.end(); ++it)
            {
                std::size_t pos = (*it).find_first_of('.', 0);
                if(pos != std::string::npos)
                    rep->addCodec((*it).substr(0, pos));
                else
                    rep->addCodec(*it);
            }
        }

        /* if more than 1 codec, don't probe, can't be packed audio */
        if(rep->getCodecs().size() > 1)
            rep->setMimeType("video/mp2t");

        if(resAttr)
        {
            std::pair<int, int> res = resAttr->getResolution();
            if(res.first * res.second)
            {
                rep->setWidth(res.first);
                rep->setHeight(res.second);
            }
        }

        parseSegments(rep, tagslist);

        adaptSet->addRepresentation(rep);
    }
}

void Parser::parseSegments(Representation *rep, const std::list<Tag *> &tagslist)
{
    SegmentList *segmentList = new (std::nothrow) SegmentList(rep);
    rep->setSegmentList(segmentList);

    rep->timescale.Set(100);

    int64_t totalduration = 0;
    int64_t nzStartTime = 0;
    uint64_t sequenceNumber = 0;
    std::size_t prevbyterangeoffset = 0;
    const SingleValueTag *ctx_byterange = NULL;
    SegmentEncryption encryption;

    std::list<Tag *>::const_iterator it;
    for(it = tagslist.begin(); it != tagslist.end(); ++it)
    {
        const Tag *tag = *it;
        switch(tag->getType())
        {
            /* using static cast as attribute type permits avoiding class check */
            case SingleValueTag::EXTXMEDIASEQUENCE:
            {
                sequenceNumber = (static_cast<const SingleValueTag*>(tag))->getValue().decimal();
            }
            break;

            case URITag::EXTINF:
            {
                const URITag *uritag = static_cast<const URITag *>(tag);
                HLSSegment *segment = new (std::nothrow) HLSSegment(rep, sequenceNumber++);
                if(!segment)
                    break;

                if(uritag->getAttributeByName("URI"))
                    segment->setSourceUrl(uritag->getAttributeByName("URI")->value);

                if(uritag->getAttributeByName("DURATION"))
                {
                    segment->duration.Set(uritag->getAttributeByName("DURATION")->floatingPoint() * rep->timescale.Get());
                    segment->startTime.Set(nzStartTime);
                    nzStartTime += segment->duration.Get();
                    totalduration += segment->duration.Get();
                }

                segmentList->addSegment(segment);

                if(ctx_byterange)
                {
                    std::pair<std::size_t,std::size_t> range = ctx_byterange->getValue().getByteRange();
                    if(range.first == 0)
                        range.first = prevbyterangeoffset;
                    prevbyterangeoffset = range.first + range.second;
                    segment->setByteRange(range.first, prevbyterangeoffset);
                    ctx_byterange = NULL;
                }

                if(encryption.method != SegmentEncryption::NONE)
                    segment->setEncryption(encryption);
            }
            break;

            case SingleValueTag::EXTXPLAYLISTTYPE:
                rep->b_live = (static_cast<const SingleValueTag *>(tag)->getValue().value != "VOD");
                break;

            case SingleValueTag::EXTXBYTERANGE:
                ctx_byterange = static_cast<const SingleValueTag *>(tag);
                break;

            case AttributesTag::EXTXKEY:
            {
                const AttributesTag *keytag = static_cast<const AttributesTag *>(tag);
                if( keytag->getAttributeByName("METHOD") &&
                    keytag->getAttributeByName("METHOD")->value == "AES-128" &&
                    keytag->getAttributeByName("URI") )
                {
                    encryption.method = SegmentEncryption::AES_128;
                    encryption.key.clear();
                    uint8_t *p_data;
                    const uint64_t read = Retrieve::HTTP(VLC_OBJECT(p_stream),
                                                         keytag->getAttributeByName("URI")->quotedString(),
                                                         (void **) &p_data);
                    if(p_data)
                    {
                        if(read == 16)
                        {
                            encryption.key.resize(16);
                            memcpy(&encryption.key[0], p_data, 16);
                        }
                        free(p_data);
                    }

                    if(keytag->getAttributeByName("IV"))
                    {
                        encryption.iv.clear();
                        encryption.iv = keytag->getAttributeByName("IV")->hexSequence();
                    }
                }
                else
                {
                    /* unsupported or invalid */
                    encryption.method = SegmentEncryption::NONE;
                    encryption.key.clear();
                    encryption.iv.clear();
                }
            }
            break;

            case Tag::EXTXENDLIST:
                rep->b_live = false;
                break;
        }
    }

    if(rep->isLive())
    {
        rep->getPlaylist()->duration.Set(0);
    }
    else if(totalduration > rep->getPlaylist()->duration.Get())
    {
        rep->getPlaylist()->duration.Set(CLOCK_FREQ * totalduration / rep->timescale.Get());
    }
}

M3U8 * Parser::parse(const std::string &playlisturl)
{
    char *psz_line = stream_ReadLine(p_stream);
    if(!psz_line || strcmp(psz_line, "#EXTM3U"))
    {
        free(psz_line);
        return NULL;
    }
    free(psz_line);

    M3U8 *playlist = new (std::nothrow) M3U8(p_stream);
    if(!playlist)
        return NULL;

    if(!playlisturl.empty())
    {
        size_t pos = playlisturl.find_last_of('/');
        if(pos != std::string::npos)
            playlist->addBaseUrl(playlisturl.substr(0, pos + 1));
    }

    BasePeriod *period = new (std::nothrow) BasePeriod( playlist );
    if(!period)
        return playlist;

    std::list<Tag *> tagslist = parseEntries(p_stream);
    bool b_masterplaylist = !getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF).empty();
    if(b_masterplaylist)
    {
        std::list<Tag *>::const_iterator it;
        std::map<std::string, AttributesTag *> groupsmap;

        /* We'll need to create an adaptation set for each media group / alternative rendering
         * we create a list of playlist being and alternative/group */
        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);
            }
        }

        /* Then we parse all playlists uri and add them, except when alternative */
        BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
        if(adaptSet)
        {
            std::list<Tag *> streaminfotags = getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF);
            for(it = streaminfotags.begin(); it != streaminfotags.end(); ++it)
            {
                AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
                if(tag && tag->getAttributeByName("URI"))
                {
                    if(groupsmap.find(tag->getAttributeByName("URI")->value) == groupsmap.end())
                    {
                        /* not a group, belong to default adaptation set */
                        parseRepresentation(adaptSet, tag);
                    }
                }
            }
            if(!adaptSet->getRepresentations().empty())
                period->addAdaptationSet(adaptSet);
            else
                delete adaptSet;
        }

        /* Finally add all groups */
        std::map<std::string, AttributesTag *>::const_iterator groupsit;
        for(groupsit = groupsmap.begin(); groupsit != groupsmap.end(); ++groupsit)
        {
            BaseAdaptationSet *altAdaptSet = new (std::nothrow) BaseAdaptationSet(period);
            if(altAdaptSet)
            {
                std::pair<std::string, AttributesTag *> pair = *groupsit;
                parseRepresentation(altAdaptSet, pair.second);

                if(pair.second->getAttributeByName("NAME"))
                   altAdaptSet->description.Set(pair.second->getAttributeByName("NAME")->quotedString());

                if(pair.second->getAttributeByName("LANGUAGE"))
                {
                    std::string lang = pair.second->getAttributeByName("LANGUAGE")->quotedString();
                    std::size_t pos = lang.find_first_of('-');
                    if(pos != std::string::npos && pos > 0)
                        altAdaptSet->addLang(lang.substr(0, pos));
                    else if (lang.size() < 4)
                        altAdaptSet->addLang(lang);
                }

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

    }
    else
    {
        BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
        if(adaptSet)
        {
            period->addAdaptationSet(adaptSet);
            AttributesTag *tag = new AttributesTag(AttributesTag::EXTXSTREAMINF, "");
            parseRepresentation(adaptSet, tag, tagslist);
            delete tag;
        }
    }

    playlist->addPeriod(period);

    releaseTagsList(tagslist);

    playlist->debug();
    return playlist;
}

std::list<Tag *> Parser::parseEntries(stream_t *stream)
{
    std::list<Tag *> entrieslist;
    Tag *lastTag = NULL;
    char *psz_line;

    while((psz_line = stream_ReadLine(stream)))
    {
        if(*psz_line == '#')
        {
            if(!strncmp(psz_line, "#EXT", 4)) //tag
            {
                std::string key;
                std::string attributes;
                const char *split = strchr(psz_line, ':');
                if(split)
                {
                    key = std::string(psz_line + 1, split - psz_line - 1);
                    attributes = std::string(split + 1);
                }
                else
                {
                    key = std::string(psz_line);
                }

                if(!key.empty())
                {
                    Tag *tag = TagFactory::createTagByName(key, attributes);
                    if(tag)
                        entrieslist.push_back(tag);
                    lastTag = tag;
                }
            }
        }
        else if(*psz_line && lastTag)
        {
            AttributesTag *attrTag = dynamic_cast<AttributesTag *>(lastTag);
            if(attrTag)
            {
                Attribute *uriAttr = new (std::nothrow) Attribute("URI", std::string(psz_line));
                if(uriAttr)
                    attrTag->addAttribute(uriAttr);
            }
            lastTag = NULL;
        }
        else // drop
        {
            lastTag = NULL;
        }

        free(psz_line);
    }

    return entrieslist;
}
<commit_msg>demux: hls: fix single tag parsing (fix #15137)<commit_after>/*
 * Parser.cpp
 *****************************************************************************
 * Copyright © 2015 - VideoLAN and VLC Authors
 *
 * 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 "Parser.hpp"
#include "HLSSegment.hpp"
#include "Representation.hpp"
#include "../adaptative/playlist/BasePeriod.h"
#include "../adaptative/playlist/BaseAdaptationSet.h"
#include "../adaptative/playlist/SegmentList.h"
#include "../adaptative/tools/Retrieve.hpp"
#include "../adaptative/tools/Helper.h"
#include "M3U8.hpp"
#include "Tags.hpp"

#include <vlc_strings.h>
#include <vlc_stream.h>
#include <cstdio>
#include <sstream>
#include <map>

using namespace adaptative;
using namespace adaptative::playlist;
using namespace hls::playlist;

Parser::Parser(stream_t *stream)
{
    p_stream = stream;
}

Parser::~Parser   ()
{
}

static std::list<Tag *> getTagsFromList(std::list<Tag *> &list, int tag)
{
    std::list<Tag *> ret;
    std::list<Tag *>::const_iterator it;
    for(it = list.begin(); it != list.end(); ++it)
    {
        if( (*it)->getType() == tag )
            ret.push_back(*it);
    }
    return ret;
}

static void releaseTagsList(std::list<Tag *> &list)
{
    std::list<Tag *>::const_iterator it;
    for(it = list.begin(); it != list.end(); ++it)
        delete *it;
    list.clear();
}

void Parser::parseAdaptationSet(BasePeriod *period, const AttributesTag *)
{
    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 *bwAttr = tag->getAttributeByName("BANDWIDTH");
    const Attribute *codecsAttr = tag->getAttributeByName("CODECS");
    const Attribute *resAttr = tag->getAttributeByName("RESOLUTION");

    Representation *rep = new (std::nothrow) Representation(adaptSet);
    if(rep)
    {
        if(uriAttr)
        {
            std::string uri;
            if(tag->getType() == AttributesTag::EXTXMEDIA)
            {
                uri = uriAttr->quotedString();
            }
            else
            {
                uri = uriAttr->value;
            }
            size_t pos = uri.find_last_of('/');
            if(pos != std::string::npos)
                rep->baseUrl.Set(new Url(uri.substr(0, pos+1)));
        }

        if(bwAttr)
            rep->setBandwidth(bwAttr->decimal());

        if(codecsAttr)
        {
            std::list<std::string> list = Helper::tokenize(codecsAttr->quotedString(), ',');
            std::list<std::string>::const_iterator it;
            for(it=list.begin(); it!=list.end(); ++it)
            {
                std::size_t pos = (*it).find_first_of('.', 0);
                if(pos != std::string::npos)
                    rep->addCodec((*it).substr(0, pos));
                else
                    rep->addCodec(*it);
            }
        }

        /* if more than 1 codec, don't probe, can't be packed audio */
        if(rep->getCodecs().size() > 1)
            rep->setMimeType("video/mp2t");

        if(resAttr)
        {
            std::pair<int, int> res = resAttr->getResolution();
            if(res.first * res.second)
            {
                rep->setWidth(res.first);
                rep->setHeight(res.second);
            }
        }

        parseSegments(rep, tagslist);

        adaptSet->addRepresentation(rep);
    }
}

void Parser::parseSegments(Representation *rep, const std::list<Tag *> &tagslist)
{
    SegmentList *segmentList = new (std::nothrow) SegmentList(rep);
    rep->setSegmentList(segmentList);

    rep->timescale.Set(100);

    int64_t totalduration = 0;
    int64_t nzStartTime = 0;
    uint64_t sequenceNumber = 0;
    std::size_t prevbyterangeoffset = 0;
    const SingleValueTag *ctx_byterange = NULL;
    SegmentEncryption encryption;

    std::list<Tag *>::const_iterator it;
    for(it = tagslist.begin(); it != tagslist.end(); ++it)
    {
        const Tag *tag = *it;
        switch(tag->getType())
        {
            /* using static cast as attribute type permits avoiding class check */
            case SingleValueTag::EXTXMEDIASEQUENCE:
            {
                sequenceNumber = (static_cast<const SingleValueTag*>(tag))->getValue().decimal();
            }
            break;

            case URITag::EXTINF:
            {
                const URITag *uritag = static_cast<const URITag *>(tag);
                HLSSegment *segment = new (std::nothrow) HLSSegment(rep, sequenceNumber++);
                if(!segment)
                    break;

                if(uritag->getAttributeByName("URI"))
                    segment->setSourceUrl(uritag->getAttributeByName("URI")->value);

                if(uritag->getAttributeByName("DURATION"))
                {
                    segment->duration.Set(uritag->getAttributeByName("DURATION")->floatingPoint() * rep->timescale.Get());
                    segment->startTime.Set(nzStartTime);
                    nzStartTime += segment->duration.Get();
                    totalduration += segment->duration.Get();
                }

                segmentList->addSegment(segment);

                if(ctx_byterange)
                {
                    std::pair<std::size_t,std::size_t> range = ctx_byterange->getValue().getByteRange();
                    if(range.first == 0)
                        range.first = prevbyterangeoffset;
                    prevbyterangeoffset = range.first + range.second;
                    segment->setByteRange(range.first, prevbyterangeoffset);
                    ctx_byterange = NULL;
                }

                if(encryption.method != SegmentEncryption::NONE)
                    segment->setEncryption(encryption);
            }
            break;

            case SingleValueTag::EXTXPLAYLISTTYPE:
                rep->b_live = (static_cast<const SingleValueTag *>(tag)->getValue().value != "VOD");
                break;

            case SingleValueTag::EXTXBYTERANGE:
                ctx_byterange = static_cast<const SingleValueTag *>(tag);
                break;

            case AttributesTag::EXTXKEY:
            {
                const AttributesTag *keytag = static_cast<const AttributesTag *>(tag);
                if( keytag->getAttributeByName("METHOD") &&
                    keytag->getAttributeByName("METHOD")->value == "AES-128" &&
                    keytag->getAttributeByName("URI") )
                {
                    encryption.method = SegmentEncryption::AES_128;
                    encryption.key.clear();
                    uint8_t *p_data;
                    const uint64_t read = Retrieve::HTTP(VLC_OBJECT(p_stream),
                                                         keytag->getAttributeByName("URI")->quotedString(),
                                                         (void **) &p_data);
                    if(p_data)
                    {
                        if(read == 16)
                        {
                            encryption.key.resize(16);
                            memcpy(&encryption.key[0], p_data, 16);
                        }
                        free(p_data);
                    }

                    if(keytag->getAttributeByName("IV"))
                    {
                        encryption.iv.clear();
                        encryption.iv = keytag->getAttributeByName("IV")->hexSequence();
                    }
                }
                else
                {
                    /* unsupported or invalid */
                    encryption.method = SegmentEncryption::NONE;
                    encryption.key.clear();
                    encryption.iv.clear();
                }
            }
            break;

            case Tag::EXTXENDLIST:
                rep->b_live = false;
                break;
        }
    }

    if(rep->isLive())
    {
        rep->getPlaylist()->duration.Set(0);
    }
    else if(totalduration > rep->getPlaylist()->duration.Get())
    {
        rep->getPlaylist()->duration.Set(CLOCK_FREQ * totalduration / rep->timescale.Get());
    }
}

M3U8 * Parser::parse(const std::string &playlisturl)
{
    char *psz_line = stream_ReadLine(p_stream);
    if(!psz_line || strcmp(psz_line, "#EXTM3U"))
    {
        free(psz_line);
        return NULL;
    }
    free(psz_line);

    M3U8 *playlist = new (std::nothrow) M3U8(p_stream);
    if(!playlist)
        return NULL;

    if(!playlisturl.empty())
    {
        size_t pos = playlisturl.find_last_of('/');
        if(pos != std::string::npos)
            playlist->addBaseUrl(playlisturl.substr(0, pos + 1));
    }

    BasePeriod *period = new (std::nothrow) BasePeriod( playlist );
    if(!period)
        return playlist;

    std::list<Tag *> tagslist = parseEntries(p_stream);
    bool b_masterplaylist = !getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF).empty();
    if(b_masterplaylist)
    {
        std::list<Tag *>::const_iterator it;
        std::map<std::string, AttributesTag *> groupsmap;

        /* We'll need to create an adaptation set for each media group / alternative rendering
         * we create a list of playlist being and alternative/group */
        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);
            }
        }

        /* Then we parse all playlists uri and add them, except when alternative */
        BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
        if(adaptSet)
        {
            std::list<Tag *> streaminfotags = getTagsFromList(tagslist, AttributesTag::EXTXSTREAMINF);
            for(it = streaminfotags.begin(); it != streaminfotags.end(); ++it)
            {
                AttributesTag *tag = dynamic_cast<AttributesTag *>(*it);
                if(tag && tag->getAttributeByName("URI"))
                {
                    if(groupsmap.find(tag->getAttributeByName("URI")->value) == groupsmap.end())
                    {
                        /* not a group, belong to default adaptation set */
                        parseRepresentation(adaptSet, tag);
                    }
                }
            }
            if(!adaptSet->getRepresentations().empty())
                period->addAdaptationSet(adaptSet);
            else
                delete adaptSet;
        }

        /* Finally add all groups */
        std::map<std::string, AttributesTag *>::const_iterator groupsit;
        for(groupsit = groupsmap.begin(); groupsit != groupsmap.end(); ++groupsit)
        {
            BaseAdaptationSet *altAdaptSet = new (std::nothrow) BaseAdaptationSet(period);
            if(altAdaptSet)
            {
                std::pair<std::string, AttributesTag *> pair = *groupsit;
                parseRepresentation(altAdaptSet, pair.second);

                if(pair.second->getAttributeByName("NAME"))
                   altAdaptSet->description.Set(pair.second->getAttributeByName("NAME")->quotedString());

                if(pair.second->getAttributeByName("LANGUAGE"))
                {
                    std::string lang = pair.second->getAttributeByName("LANGUAGE")->quotedString();
                    std::size_t pos = lang.find_first_of('-');
                    if(pos != std::string::npos && pos > 0)
                        altAdaptSet->addLang(lang.substr(0, pos));
                    else if (lang.size() < 4)
                        altAdaptSet->addLang(lang);
                }

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

    }
    else
    {
        BaseAdaptationSet *adaptSet = new (std::nothrow) BaseAdaptationSet(period);
        if(adaptSet)
        {
            period->addAdaptationSet(adaptSet);
            AttributesTag *tag = new AttributesTag(AttributesTag::EXTXSTREAMINF, "");
            parseRepresentation(adaptSet, tag, tagslist);
            delete tag;
        }
    }

    playlist->addPeriod(period);

    releaseTagsList(tagslist);

    playlist->debug();
    return playlist;
}

std::list<Tag *> Parser::parseEntries(stream_t *stream)
{
    std::list<Tag *> entrieslist;
    Tag *lastTag = NULL;
    char *psz_line;

    while((psz_line = stream_ReadLine(stream)))
    {
        if(*psz_line == '#')
        {
            if(!strncmp(psz_line, "#EXT", 4)) //tag
            {
                std::string key;
                std::string attributes;
                const char *split = strchr(psz_line, ':');
                if(split)
                {
                    key = std::string(psz_line + 1, split - psz_line - 1);
                    attributes = std::string(split + 1);
                }
                else
                {
                    key = std::string(psz_line + 1);
                }

                if(!key.empty())
                {
                    Tag *tag = TagFactory::createTagByName(key, attributes);
                    if(tag)
                        entrieslist.push_back(tag);
                    lastTag = tag;
                }
            }
        }
        else if(*psz_line && lastTag)
        {
            AttributesTag *attrTag = dynamic_cast<AttributesTag *>(lastTag);
            if(attrTag)
            {
                Attribute *uriAttr = new (std::nothrow) Attribute("URI", std::string(psz_line));
                if(uriAttr)
                    attrTag->addAttribute(uriAttr);
            }
            lastTag = NULL;
        }
        else // drop
        {
            lastTag = NULL;
        }

        free(psz_line);
    }

    return entrieslist;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * input_manager.cpp : Manage an input and interact with its GUI elements
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU 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 "util/input_slider.hpp"

#include <QPaintEvent>
#include <QPainter>
#include <QBitmap>

InputSlider::InputSlider( QWidget *_parent ) : QSlider( _parent )
{
    InputSlider::InputSlider( Qt::Horizontal, _parent );
}

InputSlider::InputSlider( Qt::Orientation q, QWidget *_parent ) :
                                 QSlider( q, _parent )
{
    b_isSliding = false;
    setMinimum( 0 );
    setMouseTracking(true);
    setMaximum( 1000 );
    setSingleStep( 2 );
    setPageStep( 10 );
    setTracking( true );
    setPosition( -1.0, 0, 0 );
    secstotimestr( psz_length, 0 );
    setFocusPolicy( Qt::NoFocus );
    CONNECT( this, valueChanged(int), this, userDrag( int ) );
}

void InputSlider::setPosition( float pos, int a, int b )
{
    if( pos == -1.0 )
        setEnabled( false );
    else
        setEnabled( true );

    if( !b_isSliding )
        setValue( (int)(pos * 1000.0 ) );

    inputLength = b;
}

void InputSlider::userDrag( int new_value )
{
    if( b_isSliding )
    {
        float f_pos = (float)(new_value)/1000.0;
        emit sliderDragged( f_pos );
    }
}

void InputSlider::mouseReleaseEvent( QMouseEvent *event )
{
    b_isSliding = false;
    event->accept();
}

void InputSlider::mousePressEvent(QMouseEvent* event)
{
    b_isSliding = true ;
    if( event->button() != Qt::LeftButton &&
        event->button() != Qt::MidButton )
    {
        QSlider::mousePressEvent( event );
        return;
    }

    QMouseEvent newEvent( event->type(), event->pos(), event->globalPos(),
        Qt::MouseButton( event->button() ^ Qt::LeftButton ^ Qt::MidButton ),
        Qt::MouseButtons( event->buttons() ^ Qt::LeftButton ^ Qt::MidButton ),
        event->modifiers() );
    QSlider::mousePressEvent( &newEvent );
}

void InputSlider::mouseMoveEvent(QMouseEvent *event)
{
    if( b_isSliding )
    {
        QSlider::mouseMoveEvent( event );
    }

    secstotimestr( psz_length, ( event->x() * inputLength) / size().width() );
    setToolTip( psz_length );
    event->accept();
}

void InputSlider::wheelEvent( QWheelEvent *event)
{
    /* Don't do anything if we are for somehow reason sliding */
    if( !b_isSliding )
    {
        setValue( value() + event->delta()/12 ); /* 12 = 8 * 15 / 10
         Since delta is in 1/8 of ° and mouse have steps of 15 °
         and that our slider is in 0.1% and we want one step to be a 1%
         increment of position */
        emit sliderDragged( value()/1000.0 );
    }
    /* We do accept because for we don't want the parent to change the sound
       vol */
    event->accept();
}

/* This work is derived from Amarok's work under GPLv2+
    - Mark Kretschmann
    - Gábor Lehel
   */
#define WLENGTH   80 // px
#define WHEIGHT   22  // px
#define SOUNDMIN  0   // %
#define SOUNDMAX  200 // % OR 400 ?

SoundSlider::SoundSlider( QWidget *_parent, int _i_step, bool b_hard,
                          char *psz_colors )
                        : QAbstractSlider( _parent )
{
    f_step = ( _i_step * 100 ) / AOUT_VOLUME_MAX ;
    setRange( SOUNDMIN, b_hard ? (2 * SOUNDMAX) : SOUNDMAX  );
    setMouseTracking( true );
    b_isSliding = false;
    b_mouseOutside = true;

    pixOutside = QPixmap( ":/volslide-outside" );

    const QPixmap temp( ":/volslide-inside" );
    const QBitmap mask( temp.createHeuristicMask() );

    setMinimumSize( pixOutside.size() );

    pixGradient = QPixmap( mask.size() );

    /* Gradient building from the preferences */
    QLinearGradient gradient( paddingL, 2, WLENGTH + paddingL , 2 );

    QStringList colorList = qfu( psz_colors ).split( ";" );
    free( psz_colors );

    /* Fill with 255 if the list is too short */
    if( colorList.size() < 12 )
        for( int i = colorList.size(); i < 12; i++)
            colorList.append( "255" );

#define c(i) colorList.at(i).toInt()
    gradient.setColorAt( 0.0, QColor( c(0), c(1), c(2) ) );
    gradient.setColorAt( 0.2, QColor( c(3), c(4), c(5) ) );
    gradient.setColorAt( 0.5, QColor( c(6), c(7), c(8) ) );
    gradient.setColorAt( 1.0, QColor( c(9), c(10), c(11) ) );

    QPainter painter( &pixGradient );
    painter.setPen( Qt::NoPen );
    painter.setBrush( gradient );
    painter.drawRect( pixGradient.rect() );
    painter.end();

    pixGradient.setMask( mask );
}

void SoundSlider::wheelEvent( QWheelEvent *event )
{
    int newvalue = value() + event->delta() / ( 8 * 15 ) * f_step;
    setValue( __MIN( __MAX( minimum(), newvalue ), maximum() ) );

    emit sliderReleased();
}

void SoundSlider::mousePressEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        /* We enter the sliding mode */
        b_isSliding = true;
        i_oldvalue = value();
        emit sliderPressed();
        changeValue( event->x() - paddingL );
    }
}

void SoundSlider::mouseReleaseEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        if( !b_mouseOutside && value() != i_oldvalue )
        {
            emit sliderReleased();
            setValue( value() );
        }
        b_isSliding = false;
        b_mouseOutside = false;
    }
}

void SoundSlider::mouseMoveEvent( QMouseEvent *event )
{
    if( b_isSliding )
    {
        QRect rect( paddingL - 15,    -1,
                    WLENGTH + 15 * 2 , WHEIGHT + 5 );
        if( !rect.contains( event->pos() ) )
        { /* We are outside */
            if ( !b_mouseOutside )
                setValue( i_oldvalue );
            b_mouseOutside = true;
        }
        else
        { /* We are inside */
            b_mouseOutside = false;
            changeValue( event->x() - paddingL );
            emit sliderMoved( value() );
        }
    }
    else
    {
        int i = ( ( event->x() - paddingL ) * maximum() + 40 ) / WLENGTH;
        i = __MIN( __MAX( 0, i ), maximum() );
        setToolTip( QString("%1  \%" ).arg( i ) );
    }
}

void SoundSlider::changeValue( int x )
{
    setValue( (x * maximum() + 40 ) / WLENGTH );
}

void SoundSlider::paintEvent( QPaintEvent *e )
{
    QPainter painter( this );
    const int offset = int( ( WLENGTH * value() + 100 ) / maximum() ) + paddingL;

    const QRectF boundsG( 0, 0, offset , pixGradient.height() );
    painter.drawPixmap( boundsG, pixGradient, boundsG );

    const QRectF boundsO( 0, 0, pixOutside.width(), pixOutside.height() );
    painter.drawPixmap( boundsO, pixOutside, boundsO );

    painter.setPen( palette().color( QPalette::Active, QPalette::Mid ) );
    QFont font; font.setPixelSize( 9 );
    painter.setFont( font );
    const QRect rect( 0, 0, 34, 15 );
    painter.drawText( rect, Qt::AlignRight | Qt::AlignVCenter,
                      QString::number( value() ) + '%' );

    painter.end();
    e->accept();
}

<commit_msg>Qt4: Middle mouse click on the InputSlider cause a wrong behaviour<commit_after>/*****************************************************************************
 * input_manager.cpp : Manage an input and interact with its GUI elements
 ****************************************************************************
 * Copyright (C) 2006 the VideoLAN team
 * $Id$
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
 *          Jean-Baptiste Kempf <jb@videolan.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 * You should have received a copy of the GNU 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 "util/input_slider.hpp"

#include <QPaintEvent>
#include <QPainter>
#include <QBitmap>

InputSlider::InputSlider( QWidget *_parent ) : QSlider( _parent )
{
    InputSlider::InputSlider( Qt::Horizontal, _parent );
}

InputSlider::InputSlider( Qt::Orientation q, QWidget *_parent ) :
                                 QSlider( q, _parent )
{
    b_isSliding = false;
    setMinimum( 0 );
    setMouseTracking(true);
    setMaximum( 1000 );
    setSingleStep( 2 );
    setPageStep( 10 );
    setTracking( true );
    setPosition( -1.0, 0, 0 );
    secstotimestr( psz_length, 0 );
    setFocusPolicy( Qt::NoFocus );
    CONNECT( this, valueChanged(int), this, userDrag( int ) );
}

void InputSlider::setPosition( float pos, int a, int b )
{
    if( pos == -1.0 )
        setEnabled( false );
    else
        setEnabled( true );

    if( !b_isSliding )
        setValue( (int)(pos * 1000.0 ) );

    inputLength = b;
}

void InputSlider::userDrag( int new_value )
{
    if( b_isSliding )
    {
        float f_pos = (float)(new_value)/1000.0;
        emit sliderDragged( f_pos );
    }
}

void InputSlider::mouseReleaseEvent( QMouseEvent *event )
{
    b_isSliding = false;
    event->accept();
    QSlider::mouseReleaseEvent( event );
}

void InputSlider::mousePressEvent(QMouseEvent* event)
{
    b_isSliding = true ;
    if( event->button() != Qt::LeftButton &&
        event->button() != Qt::MidButton )
    {
        QSlider::mousePressEvent( event );
        return;
    }

    QMouseEvent newEvent( event->type(), event->pos(), event->globalPos(),
        Qt::MouseButton( event->button() ^ Qt::LeftButton ^ Qt::MidButton ),
        Qt::MouseButtons( event->buttons() ^ Qt::LeftButton ^ Qt::MidButton ),
        event->modifiers() );
    QSlider::mousePressEvent( &newEvent );
}

void InputSlider::mouseMoveEvent(QMouseEvent *event)
{
    if( b_isSliding )
    {
        QSlider::mouseMoveEvent( event );
    }

    secstotimestr( psz_length, ( event->x() * inputLength) / size().width() );
    setToolTip( psz_length );
    event->accept();
}

void InputSlider::wheelEvent( QWheelEvent *event)
{
    /* Don't do anything if we are for somehow reason sliding */
    if( !b_isSliding )
    {
        setValue( value() + event->delta()/12 ); /* 12 = 8 * 15 / 10
         Since delta is in 1/8 of ° and mouse have steps of 15 °
         and that our slider is in 0.1% and we want one step to be a 1%
         increment of position */
        emit sliderDragged( value()/1000.0 );
    }
    /* We do accept because for we don't want the parent to change the sound
       vol */
    event->accept();
}

/* This work is derived from Amarok's work under GPLv2+
    - Mark Kretschmann
    - Gábor Lehel
   */
#define WLENGTH   80 // px
#define WHEIGHT   22  // px
#define SOUNDMIN  0   // %
#define SOUNDMAX  200 // % OR 400 ?

SoundSlider::SoundSlider( QWidget *_parent, int _i_step, bool b_hard,
                          char *psz_colors )
                        : QAbstractSlider( _parent )
{
    f_step = ( _i_step * 100 ) / AOUT_VOLUME_MAX ;
    setRange( SOUNDMIN, b_hard ? (2 * SOUNDMAX) : SOUNDMAX  );
    setMouseTracking( true );
    b_isSliding = false;
    b_mouseOutside = true;

    pixOutside = QPixmap( ":/volslide-outside" );

    const QPixmap temp( ":/volslide-inside" );
    const QBitmap mask( temp.createHeuristicMask() );

    setMinimumSize( pixOutside.size() );

    pixGradient = QPixmap( mask.size() );

    /* Gradient building from the preferences */
    QLinearGradient gradient( paddingL, 2, WLENGTH + paddingL , 2 );

    QStringList colorList = qfu( psz_colors ).split( ";" );
    free( psz_colors );

    /* Fill with 255 if the list is too short */
    if( colorList.size() < 12 )
        for( int i = colorList.size(); i < 12; i++)
            colorList.append( "255" );

#define c(i) colorList.at(i).toInt()
    gradient.setColorAt( 0.0, QColor( c(0), c(1), c(2) ) );
    gradient.setColorAt( 0.2, QColor( c(3), c(4), c(5) ) );
    gradient.setColorAt( 0.5, QColor( c(6), c(7), c(8) ) );
    gradient.setColorAt( 1.0, QColor( c(9), c(10), c(11) ) );

    QPainter painter( &pixGradient );
    painter.setPen( Qt::NoPen );
    painter.setBrush( gradient );
    painter.drawRect( pixGradient.rect() );
    painter.end();

    pixGradient.setMask( mask );
}

void SoundSlider::wheelEvent( QWheelEvent *event )
{
    int newvalue = value() + event->delta() / ( 8 * 15 ) * f_step;
    setValue( __MIN( __MAX( minimum(), newvalue ), maximum() ) );

    emit sliderReleased();
}

void SoundSlider::mousePressEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        /* We enter the sliding mode */
        b_isSliding = true;
        i_oldvalue = value();
        emit sliderPressed();
        changeValue( event->x() - paddingL );
    }
}

void SoundSlider::mouseReleaseEvent( QMouseEvent *event )
{
    if( event->button() != Qt::RightButton )
    {
        if( !b_mouseOutside && value() != i_oldvalue )
        {
            emit sliderReleased();
            setValue( value() );
        }
        b_isSliding = false;
        b_mouseOutside = false;
    }
}

void SoundSlider::mouseMoveEvent( QMouseEvent *event )
{
    if( b_isSliding )
    {
        QRect rect( paddingL - 15,    -1,
                    WLENGTH + 15 * 2 , WHEIGHT + 5 );
        if( !rect.contains( event->pos() ) )
        { /* We are outside */
            if ( !b_mouseOutside )
                setValue( i_oldvalue );
            b_mouseOutside = true;
        }
        else
        { /* We are inside */
            b_mouseOutside = false;
            changeValue( event->x() - paddingL );
            emit sliderMoved( value() );
        }
    }
    else
    {
        int i = ( ( event->x() - paddingL ) * maximum() + 40 ) / WLENGTH;
        i = __MIN( __MAX( 0, i ), maximum() );
        setToolTip( QString("%1  \%" ).arg( i ) );
    }
}

void SoundSlider::changeValue( int x )
{
    setValue( (x * maximum() + 40 ) / WLENGTH );
}

void SoundSlider::paintEvent( QPaintEvent *e )
{
    QPainter painter( this );
    const int offset = int( ( WLENGTH * value() + 100 ) / maximum() ) + paddingL;

    const QRectF boundsG( 0, 0, offset , pixGradient.height() );
    painter.drawPixmap( boundsG, pixGradient, boundsG );

    const QRectF boundsO( 0, 0, pixOutside.width(), pixOutside.height() );
    painter.drawPixmap( boundsO, pixOutside, boundsO );

    painter.setPen( palette().color( QPalette::Active, QPalette::Mid ) );
    QFont font; font.setPixelSize( 9 );
    painter.setFont( font );
    const QRect rect( 0, 0, 34, 15 );
    painter.drawText( rect, Qt::AlignRight | Qt::AlignVCenter,
                      QString::number( value() ) + '%' );

    painter.end();
    e->accept();
}

<|endoftext|>


<commit_before>// window.cpp

#ifndef SAMPLES_DIR
#define SAMPLES_DIR ""
#endif

#include <QComboBox>
#include <QDialog>
#include <QFileDialog>
#include <QLabel>
#include <QLineEdit>
#include <QList>
#include <QtMultimedia/QCameraInfo>

#include "window.h"

Window::Window (QWidget* parent)
: QWidget (parent)
, _acquisition ()
, _frame_timer ()
, _holder_layout_img (this)
, _holder_layout_btn (this)
, _layout_app (QBoxLayout::TopToBottom, this)
, _layout_img (&_holder_layout_img)
, _layout_btn (QBoxLayout::LeftToRight, &_holder_layout_btn)
, _btn_pause ("Pause", this)
, _btn_reference ("Set Reference", this)
, _btn_input ("Select Input", this)
, _statusbar (this)
, _augmentation (this) {
    _layout_app.addWidget (&_holder_layout_img);
    _layout_app.addWidget (&_holder_layout_btn);
    _layout_app.addWidget (&_statusbar);

    _layout_img.addWidget (&_augmentation, 0, 0);
    _layout_btn.addWidget (&_btn_pause);
    _layout_btn.addWidget (&_btn_reference);
    _layout_btn.addWidget (&_btn_input);
    _statusbar.setSizeGripEnabled (false);

    connect (&_frame_timer, SIGNAL (timeout ()), this, SLOT (timeout ()));
    connect (&_btn_pause, SIGNAL (clicked ()), this, SLOT (btn_pause_clicked ()));
    connect (&_btn_reference, SIGNAL (clicked ()), this, SLOT (btn_reference_clicked ()));
    connect (&_btn_input, SIGNAL (clicked ()), this, SLOT (btn_input_clicked ()));

    _frame_timer.setInterval (1000 / _framerate);
    _frame_timer.start ();
}

Window::~Window () {
}

QSize Window::minimumSizeHint () const {
    return _layout_app.minimumSize ();
}

QSize Window::sizeHint () const {
    return _layout_app.sizeHint ();
}

void Window::keyPressEvent (QKeyEvent* e) {
    if (e->key () == Qt::Key_Escape)
        close ();
    else
        QWidget::keyPressEvent (e);
}

void Window::timeout () {
    cv::Mat frame, preprocessed, segmented;
    std::map<unsigned int, cv::Point2f> marker_points;
    movement3d movement;
    try {
        frame        = _acquisition.capture ();
        preprocessed = _vision_methods.preprocessing (frame);
        segmented    = _vision_methods.segmentation (preprocessed);
        _vision_methods.extraction (segmented, marker_points);
        movement = _vision_methods.classification (marker_points);
    } catch (const std::length_error& e) {
        _statusbar.showMessage (std::string (e.what ()).c_str (), 100);
    } catch (const std::runtime_error& e) {
        _statusbar.showMessage ("Select Input");
        frame = cv::Mat (1000, 1000, CV_8UC3, cv::Scalar (0, 0, 0));
    } catch (...) {
    }
    _augmentation.setBackground (frame.ptr (), frame.cols, frame.rows);
    _augmentation.update ();
}

void Window::btn_pause_clicked () {
    if (_frame_timer.isActive ()) {
        _frame_timer.stop ();
        _btn_pause.setText ("Resume");
    } else {
        _frame_timer.start ();
        _btn_pause.setText ("Pause");
    }
}

void Window::btn_reference_clicked () {
    try {
        _vision_methods.set_reference (_acquisition.capture ());
    } catch (const std::length_error& e) {
        _statusbar.showMessage (std::string (e.what ()).c_str (), 1000);
    } catch (const std::runtime_error& e) {
        _statusbar.showMessage ("Error while setting reference");
    }
}

void Window::btn_input_clicked () {
    // create dialog ui elements
    QDialog dialog (this);
    QBoxLayout layout_dialog (QBoxLayout::TopToBottom, &dialog);
    QPushButton btn_open_filebrowser ("Open File Browser");
    QComboBox box_camid;
    QLabel label1 ("Select camera:");
    QLabel label2 ("Or choose a file:");

    // order the ui elements
    dialog.setWindowTitle ("Select Input");
    layout_dialog.addWidget (&label1);
    layout_dialog.addWidget (&box_camid);
    layout_dialog.addWidget (&label2);
    layout_dialog.addWidget (&btn_open_filebrowser);

    // fill list of cameras
    QList<QCameraInfo> cameras = QCameraInfo::availableCameras ();
    if (cameras.size () > 0) {
        box_camid.addItem ("Select Camera");
        foreach (const QCameraInfo& cameraInfo, cameras) {
            box_camid.addItem (cameraInfo.description ());
        }
    } else {
        box_camid.setEnabled (false);
        box_camid.addItem ("No Cameras Found");
    }

    connect (&box_camid, SIGNAL (currentIndexChanged (int)), &dialog, SLOT (close ()));
    connect (&box_camid, SIGNAL (currentIndexChanged (int)), this,
    SLOT (dialog_box_camid_indexchanged (int)));
    connect (&btn_open_filebrowser, SIGNAL (clicked ()), &dialog, SLOT (close ()));
    connect (&btn_open_filebrowser, SIGNAL (clicked ()), this,
    SLOT (dialog_btn_filebrowser_clicked ()));

    dialog.exec ();
}

void Window::dialog_btn_filebrowser_clicked () {
    // test file
    QString file_name = QFileDialog::getOpenFileName (
    this, tr ("Open Video"), SAMPLES_DIR, tr ("Videos (*.webm)"));

    if (!file_name.isEmpty ()) {
        _acquisition.source (file_name.toStdString ());
        _statusbar.showMessage (QString ("Set source: ") + file_name, 2000);
    }
}

void Window::dialog_box_camid_indexchanged (int idx) {
    _acquisition.source (idx - 1);
    _statusbar.showMessage (QString ("Selected camera #") + QString::number (idx), 2000);
}
<commit_msg>implement augmentation transformations<commit_after>// window.cpp

#ifndef SAMPLES_DIR
#define SAMPLES_DIR ""
#endif

#include <QComboBox>
#include <QDialog>
#include <QFileDialog>
#include <QLabel>
#include <QLineEdit>
#include <QList>
#include <QtMultimedia/QCameraInfo>

#include "window.h"

Window::Window (QWidget* parent)
: QWidget (parent)
, _acquisition ()
, _frame_timer ()
, _holder_layout_img (this)
, _holder_layout_btn (this)
, _layout_app (QBoxLayout::TopToBottom, this)
, _layout_img (&_holder_layout_img)
, _layout_btn (QBoxLayout::LeftToRight, &_holder_layout_btn)
, _btn_pause ("Pause", this)
, _btn_reference ("Set Reference", this)
, _btn_input ("Select Input", this)
, _statusbar (this)
, _augmentation (this) {
    _layout_app.addWidget (&_holder_layout_img);
    _layout_app.addWidget (&_holder_layout_btn);
    _layout_app.addWidget (&_statusbar);

    _layout_img.addWidget (&_augmentation, 0, 0);
    _layout_btn.addWidget (&_btn_pause);
    _layout_btn.addWidget (&_btn_reference);
    _layout_btn.addWidget (&_btn_input);
    _statusbar.setSizeGripEnabled (false);

    connect (&_frame_timer, SIGNAL (timeout ()), this, SLOT (timeout ()));
    connect (&_btn_pause, SIGNAL (clicked ()), this, SLOT (btn_pause_clicked ()));
    connect (&_btn_reference, SIGNAL (clicked ()), this, SLOT (btn_reference_clicked ()));
    connect (&_btn_input, SIGNAL (clicked ()), this, SLOT (btn_input_clicked ()));

    _frame_timer.setInterval (1000 / _framerate);
    _frame_timer.start ();
}

Window::~Window () {
}

QSize Window::minimumSizeHint () const {
    return _layout_app.minimumSize ();
}

QSize Window::sizeHint () const {
    return _layout_app.sizeHint ();
}

void Window::keyPressEvent (QKeyEvent* e) {
    if (e->key () == Qt::Key_Escape)
        close ();
    else
        QWidget::keyPressEvent (e);
}

void Window::timeout () {
    cv::Mat frame, preprocessed, segmented;
    std::map<unsigned int, cv::Point2f> marker_points;
    movement3d movement;
    GLfloat persp_mat[16];
    try {
        frame        = _acquisition.capture ();
        preprocessed = _vision_methods.preprocessing (frame);
        segmented    = _vision_methods.segmentation (preprocessed);
        _vision_methods.extraction (segmented, marker_points);
        movement = _vision_methods.classification (marker_points);

        movement.rot_x_gl (persp_mat);
        _augmentation.setXRotation (persp_mat);
        movement.rot_y_gl (persp_mat);
        _augmentation.setYRotation (persp_mat);
        movement.rot_z_gl (persp_mat);
        _augmentation.setZRotation (persp_mat);

        float xpos =
        movement.translation_delta_to_absolute (movement.trans_x (), frame.cols);
        float ypos =
        movement.translation_delta_to_absolute (movement.trans_y (), frame.rows);
        _augmentation.setXPosition (xpos);
        _augmentation.setYPosition (ypos);
        _augmentation.setScale (movement.scale ());
    } catch (const std::length_error& e) {
        _statusbar.showMessage (std::string (e.what ()).c_str (), 100);
    } catch (const std::runtime_error& e) {
        _statusbar.showMessage ("Select Input");
        frame = cv::Mat (1000, 1000, CV_8UC3, cv::Scalar (0, 0, 0));
    } catch (...) {
    }
    _augmentation.setBackground (frame.ptr (), frame.cols, frame.rows);
    _augmentation.update ();
}

void Window::btn_pause_clicked () {
    if (_frame_timer.isActive ()) {
        _frame_timer.stop ();
        _btn_pause.setText ("Resume");
    } else {
        _frame_timer.start ();
        _btn_pause.setText ("Pause");
    }
}

void Window::btn_reference_clicked () {
    try {
        _vision_methods.set_reference (_acquisition.capture ());
    } catch (const std::length_error& e) {
        _statusbar.showMessage (std::string (e.what ()).c_str (), 1000);
    } catch (const std::runtime_error& e) {
        _statusbar.showMessage ("Error while setting reference");
    }
}

void Window::btn_input_clicked () {
    // create dialog ui elements
    QDialog dialog (this);
    QBoxLayout layout_dialog (QBoxLayout::TopToBottom, &dialog);
    QPushButton btn_open_filebrowser ("Open File Browser");
    QComboBox box_camid;
    QLabel label1 ("Select camera:");
    QLabel label2 ("Or choose a file:");

    // order the ui elements
    dialog.setWindowTitle ("Select Input");
    layout_dialog.addWidget (&label1);
    layout_dialog.addWidget (&box_camid);
    layout_dialog.addWidget (&label2);
    layout_dialog.addWidget (&btn_open_filebrowser);

    // fill list of cameras
    QList<QCameraInfo> cameras = QCameraInfo::availableCameras ();
    if (cameras.size () > 0) {
        box_camid.addItem ("Select Camera");
        foreach (const QCameraInfo& cameraInfo, cameras) {
            box_camid.addItem (cameraInfo.description ());
        }
    } else {
        box_camid.setEnabled (false);
        box_camid.addItem ("No Cameras Found");
    }

    connect (&box_camid, SIGNAL (currentIndexChanged (int)), &dialog, SLOT (close ()));
    connect (&box_camid, SIGNAL (currentIndexChanged (int)), this,
    SLOT (dialog_box_camid_indexchanged (int)));
    connect (&btn_open_filebrowser, SIGNAL (clicked ()), &dialog, SLOT (close ()));
    connect (&btn_open_filebrowser, SIGNAL (clicked ()), this,
    SLOT (dialog_btn_filebrowser_clicked ()));

    dialog.exec ();
}

void Window::dialog_btn_filebrowser_clicked () {
    // test file
    QString file_name = QFileDialog::getOpenFileName (
    this, tr ("Open Video"), SAMPLES_DIR, tr ("Videos (*.webm)"));

    if (!file_name.isEmpty ()) {
        _acquisition.source (file_name.toStdString ());
        _statusbar.showMessage (QString ("Set source: ") + file_name, 2000);
    }
}

void Window::dialog_box_camid_indexchanged (int idx) {
    _acquisition.source (idx - 1);
    _statusbar.showMessage (QString ("Selected camera #") + QString::number (idx), 2000);
}
<|endoftext|>


<commit_before>/*
 * BirdsEyeTranslationReader.cpp
 *
 *  Created on: Feb 21, 2013
 *      Author: link
 */

#include "BirdsEyeTranslationReader.hpp"
#include "ImageEdgeFilter.hpp"
#include <opencv2/imgproc/imgproc.hpp>

#include "DrawingFunctions.hpp"
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>

bool horizontalPoint2Compare(cv::Point2f p1, cv::Point2f p2) {
    return p1.x < p2.x;
}

bool verticalPoint2Compare(cv::Point2f p1, cv::Point2f p2) {
    return p1.y < p2.y;
}

BirdsEyeTranslationReader::BirdsEyeTranslationReader(
        const cv::Mat &homography, const FeatureExtractor &extractor,
        const FeatureTracker &tracker,
        const unsigned int& maxFeatures,
        const std::list<FeatureFilter*>& filters,
        cv::Point2f rotationCentre, const cv::Size& imageSize,
        const double &margin, const cv::Size &viewSize,
        const std::vector<std::list<cv::Point2f> > &trackedFeatures) :
        TranslationReader(tracker, extractor, filters, maxFeatures,
                trackedFeatures), _rotationCenter(rotationCentre), _viewSize(
                viewSize), _homography(homography.clone()) {
    _filters.push_front(
            new ImageEdgeFilter(homography, imageSize, margin));
    temp.clear();

}

BirdsEyeTranslationReader::BirdsEyeTranslationReader(
        const BirdsEyeTranslationReader &toCopy) :
        TranslationReader(toCopy), _translations(
                toCopy._translations), _rotationCenter(
                toCopy._rotationCenter), _viewSize(toCopy._viewSize), _homography(
                toCopy._homography) {
    temp.clear();
}

BirdsEyeTranslationReader::~BirdsEyeTranslationReader() {
}

TranslationReader *BirdsEyeTranslationReader::constructCopy() const {
    return new BirdsEyeTranslationReader(*this);
}

static int bla = 0;

cv::Point3f BirdsEyeTranslationReader::readTranslation(
        const cv::Mat &newFrame, const double& rotationAngle) {
    cv::Mat newTransformed;
    cv::Point3f result(0, 0, rotationAngle);
    cv::Mat rotationMatrix = cv::getRotationMatrix2D(_rotationCenter,
            rotationAngle, 1);
    int vectorHalf = 0;
    cv::warpPerspective(newFrame, newTransformed, _homography,
            newFrame.size(), cv::INTER_LINEAR | cv::WARP_INVERSE_MAP);
    // imshow("c2", newTransformed);
    //cv::waitKey(1);
    if (!_oldFrame.empty()) {
        _extractor->refillFeatures(_oldFrame, _trackedFeatures,
                _maxFeatures);
        _tracker->trackFeatures(_oldFrame, newTransformed,
                _trackedFeatures);
//        std::vector<cv::Point2f> corners;
//        cv::Mat show = newTransformed.clone();
//        ++bla;
//        if (bla > 10) {
//            bla = 0;
//            bool found = cv::findChessboardCorners(newTransformed,
//                    cv::Size(9, 6), corners,
//                    CV_CALIB_CB_FAST_CHECK
//                            | CV_CALIB_CB_ADAPTIVE_THRESH
//                    /*| CV_CALIB_CB_NORMALIZE_IMAGE*/);
//            drawChessboardCorners(show, cv::Size(9, 6), corners,
//                    found);
//            if (found) {
//                std::cerr << "found" << std::endl;
//                temp.push_front(corners);
//                if (3 < temp.size()) {
//                    temp.pop_back();
//                }
//
//                if (3 == temp.size()) {
//                    std::list<std::vector<cv::Point2f> >::iterator iter1 =
//                            temp.begin();
//                    std::list<std::vector<cv::Point2f> >::iterator iter2 =
//                            temp.begin();
//                    std::list<std::vector<cv::Point2f> >::iterator iter3 =
//                            temp.begin();
//                    iter2++;
//                    iter3++;
//                    iter3++;
//
//                    double sumX = 0;
//                    double sumY = 0;
//                    unsigned int counter = 0;
//
//                    std::vector<double> xs, ys;
//                    xs.resize(temp.front().size());
//                    ys.resize(temp.front().size());
//                    for (unsigned int i = 0;
//                            i < temp.front().size() - 1; ++i) {
//
//                        double x0, x1, x2, x3, y0, y1, y2, y3;
//
//                        x1 = iter1->at(i).x;
//                        x2 = iter2->at(i).x;
//                        x3 = iter3->at(i).x;
//                        y1 = iter1->at(i).y;
//                        y2 = iter2->at(i).y;
//                        y3 = iter3->at(i).y;
//
////                    x1=8;x2=7;x3=6;
////                    y1=4;y2=7;y3=8;
//                        if (x2 == x1 || x2 == x3 || y1 == y2
//                                || y2 == y3) {
//                            continue;
//                        }
//                        double a1 = -(x2 - x1) / (y2 - y1);
//                        double a2 = -(x3 - x2) / (y3 - y2);
//                        double b1 = (y2 + y1) / 2
//                                - a1 * (x2 + x1) / 2;
//                        double b2 = (y3 + y2) / 2
//                                - a2 * (x3 + x2) / 2;
//
//                        if (a1 == a2) {
//                            continue;
//                        }
//
//                        x0 = (b2 - b1) / (a1 - a2);
//                        y0 = a1 * x0 + b1;
//
////                    std::cerr<<y0<<" "<<a2*x0+b2<<std::endl;
//
//                        sumX += x0;
//                        sumY += y0;
//                        ++counter;
//                        xs[i] = x0;
//                        ys[i] = y0;
//                        std::cerr << i << std::endl;
//                        std::cerr << cv::Point2f(x1, y1) << std::endl;
//                        std::cerr << cv::Point2f(x2, y2) << std::endl;
//                        std::cerr << cv::Point2f(x3, y3) << std::endl;
//                        std::cerr << std::endl;
//                        std::cerr << cv::Point2f(x0, y0) << std::endl;
//                        std::cerr << std::endl;
//                        cv::circle(show, cv::Point2d(x0, y0), 4,
//                                cv::Scalar::all(255), 3, 8);
//
//                    }
//                    unsigned int xH = xs.size() / 2;
//                    unsigned int yH = ys.size() / 2;
//                    std::nth_element(xs.begin(), xs.begin() + xH,
//                            xs.end());
//                    std::nth_element(ys.begin(), ys.begin() + yH,
//                            ys.end());
//                    std::cerr << cv::Point2d(xs[xH], ys[yH])
//                            << std::endl;
//                    std::cerr
//                            << cv::Point2d(sumX / counter,
//                                    sumY / counter) << std::endl;
//                    std::cerr << _rotationCenter << std::endl;
////                cv::circle(show,cv::Point2d(xs[xH], ys[yH]),8,cv::Scalar::all(255),3,8);
////                cv::circle(show,cv::Point2d(sumX/counter, sumY/counter),4,cv::Scalar::all(255),3,8);
//                    double medx = sumX / counter;
//                    double medy = sumX / counter;
//                    double varx = 0;
//                    double vary = 0;
//                    for (unsigned k = 0; k < xs.size(); ++k) {
//                        varx += (medx - xs[k]) * (medx - xs[k]);
//                        vary += (medy - ys[k]) * (medy - ys[k]);
//                    }
//
//                    std::cerr << varx / xs.size() << std::endl;
//                    std::cerr << vary / ys.size() << std::endl;
//
//                }
//            }
//            cv::imshow("c3", show);
//        }
        if (!_trackedFeatures.empty()) {
//			cv::Mat pre = drawFeatureHistory(newTransformed, _trackedFeatures);
//			imshow("c1", pre);
//			imshow("ol", _oldFrame);
            for (std::list<FeatureFilter*>::iterator it =
                    _filters.begin(); it != _filters.end(); ++it) {
                _trackedFeatures = (*it)->filterFeatures(
                        _trackedFeatures);
            }
//			cv::Mat post = newTransformed.clone();
//			drawFeatureHistory(post, _trackedFeatures,3);
//            cv::imshow("c1", post);
            if (!_trackedFeatures.empty()) {
                std::vector<cv::Point2f> translations =
                        computeTranslationVectors(rotationMatrix);
                vectorHalf = translations.size() / 2;
                std::nth_element(translations.begin(),
                        translations.begin() + vectorHalf,
                        translations.end(), horizontalPoint2Compare);
                result.x = translations[vectorHalf].x;
                std::nth_element(translations.begin(),
                        translations.begin() + vectorHalf,
                        translations.end(), verticalPoint2Compare);
                result.y = translations[vectorHalf].y;
            }
        }
//
//    cv::Mat newRot;
//        cv::warpAffine(newTransformed, newRot, rotationMatrix,
//                newTransformed.size());
//        imshow("c2", _oldFrame - newRot);
//      imshow("c3", newRot);
// cv::waitKey(1);

    }
    _oldFrame = newTransformed.clone();
    // std::cerr << "bird out" << std::endl;
    return result;
}

std::vector<cv::Point2f> BirdsEyeTranslationReader::computeTranslationVectors(
        const cv::Mat& rotationMatrix) {
    std::vector<cv::Point2f> result(_trackedFeatures.size());
    std::vector<cv::Point2f> oldFeatures(_trackedFeatures.size()),
            newFeatures(_trackedFeatures.size());
    std::vector<cv::Point2f> newTransformed(newFeatures.size());

    for (unsigned int i = 0; i < result.size(); ++i) { //Highly susceptible to bugs
        oldFeatures[i] = _trackedFeatures[i].front();
        newFeatures[i] = *(++_trackedFeatures[i].begin());
    }

    cv::transform(newFeatures, newTransformed, rotationMatrix);
    for (unsigned int i = 0; i < result.size(); ++i) {
        result[i] = newTransformed[i] - oldFeatures[i];
    }

    return result;
}

<commit_msg>Fixed missing angle transformation to degrees in BirdsEye<commit_after>/*
 * BirdsEyeTranslationReader.cpp
 *
 *  Created on: Feb 21, 2013
 *      Author: link
 */

#include "BirdsEyeTranslationReader.hpp"
#include "ImageEdgeFilter.hpp"
#include <opencv2/imgproc/imgproc.hpp>

#include "DrawingFunctions.hpp"
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>

bool horizontalPoint2Compare(cv::Point2f p1, cv::Point2f p2) {
    return p1.x < p2.x;
}

bool verticalPoint2Compare(cv::Point2f p1, cv::Point2f p2) {
    return p1.y < p2.y;
}

BirdsEyeTranslationReader::BirdsEyeTranslationReader(
        const cv::Mat &homography, const FeatureExtractor &extractor,
        const FeatureTracker &tracker,
        const unsigned int& maxFeatures,
        const std::list<FeatureFilter*>& filters,
        cv::Point2f rotationCentre, const cv::Size& imageSize,
        const double &margin, const cv::Size &viewSize,
        const std::vector<std::list<cv::Point2f> > &trackedFeatures) :
        TranslationReader(tracker, extractor, filters, maxFeatures,
                trackedFeatures), _rotationCenter(rotationCentre), _viewSize(
                viewSize), _homography(homography.clone()) {
    _filters.push_front(
            new ImageEdgeFilter(homography, imageSize, margin));
    temp.clear();

}

BirdsEyeTranslationReader::BirdsEyeTranslationReader(
        const BirdsEyeTranslationReader &toCopy) :
        TranslationReader(toCopy), _translations(
                toCopy._translations), _rotationCenter(
                toCopy._rotationCenter), _viewSize(toCopy._viewSize), _homography(
                toCopy._homography) {
    temp.clear();
}

BirdsEyeTranslationReader::~BirdsEyeTranslationReader() {
}

TranslationReader *BirdsEyeTranslationReader::constructCopy() const {
    return new BirdsEyeTranslationReader(*this);
}

static int bla = 0;

cv::Point3f BirdsEyeTranslationReader::readTranslation(
        const cv::Mat &newFrame, const double& rotationAngle) {
    cv::Mat newTransformed;
    cv::Point3f result(0, 0, rotationAngle);
    cv::Mat rotationMatrix = cv::getRotationMatrix2D(_rotationCenter,
            -rotationAngle * 180 / CV_PI, 1);
    int vectorHalf = 0;
    cv::warpPerspective(newFrame, newTransformed, _homography,
            newFrame.size(), cv::INTER_LINEAR | cv::WARP_INVERSE_MAP);
    // imshow("c2", newTransformed);
    //cv::waitKey(1);
    if (!_oldFrame.empty()) {
        _extractor->refillFeatures(_oldFrame, _trackedFeatures,
                _maxFeatures);
        _tracker->trackFeatures(_oldFrame, newTransformed,
                _trackedFeatures);
//        std::vector<cv::Point2f> corners;
//        cv::Mat show = newTransformed.clone();
//        ++bla;
//        if (bla > 10) {
//            bla = 0;
//            bool found = cv::findChessboardCorners(newTransformed,
//                    cv::Size(9, 6), corners,
//                    CV_CALIB_CB_FAST_CHECK
//                            | CV_CALIB_CB_ADAPTIVE_THRESH
//                    /*| CV_CALIB_CB_NORMALIZE_IMAGE*/);
//            drawChessboardCorners(show, cv::Size(9, 6), corners,
//                    found);
//            if (found) {
//                std::cerr << "found" << std::endl;
//                temp.push_front(corners);
//                if (3 < temp.size()) {
//                    temp.pop_back();
//                }
//
//                if (3 == temp.size()) {
//                    std::list<std::vector<cv::Point2f> >::iterator iter1 =
//                            temp.begin();
//                    std::list<std::vector<cv::Point2f> >::iterator iter2 =
//                            temp.begin();
//                    std::list<std::vector<cv::Point2f> >::iterator iter3 =
//                            temp.begin();
//                    iter2++;
//                    iter3++;
//                    iter3++;
//
//                    double sumX = 0;
//                    double sumY = 0;
//                    unsigned int counter = 0;
//
//                    std::vector<double> xs, ys;
//                    xs.resize(temp.front().size());
//                    ys.resize(temp.front().size());
//                    for (unsigned int i = 0;
//                            i < temp.front().size() - 1; ++i) {
//
//                        double x0, x1, x2, x3, y0, y1, y2, y3;
//
//                        x1 = iter1->at(i).x;
//                        x2 = iter2->at(i).x;
//                        x3 = iter3->at(i).x;
//                        y1 = iter1->at(i).y;
//                        y2 = iter2->at(i).y;
//                        y3 = iter3->at(i).y;
//
////                    x1=8;x2=7;x3=6;
////                    y1=4;y2=7;y3=8;
//                        if (x2 == x1 || x2 == x3 || y1 == y2
//                                || y2 == y3) {
//                            continue;
//                        }
//                        double a1 = -(x2 - x1) / (y2 - y1);
//                        double a2 = -(x3 - x2) / (y3 - y2);
//                        double b1 = (y2 + y1) / 2
//                                - a1 * (x2 + x1) / 2;
//                        double b2 = (y3 + y2) / 2
//                                - a2 * (x3 + x2) / 2;
//
//                        if (a1 == a2) {
//                            continue;
//                        }
//
//                        x0 = (b2 - b1) / (a1 - a2);
//                        y0 = a1 * x0 + b1;
//
////                    std::cerr<<y0<<" "<<a2*x0+b2<<std::endl;
//
//                        sumX += x0;
//                        sumY += y0;
//                        ++counter;
//                        xs[i] = x0;
//                        ys[i] = y0;
//                        std::cerr << i << std::endl;
//                        std::cerr << cv::Point2f(x1, y1) << std::endl;
//                        std::cerr << cv::Point2f(x2, y2) << std::endl;
//                        std::cerr << cv::Point2f(x3, y3) << std::endl;
//                        std::cerr << std::endl;
//                        std::cerr << cv::Point2f(x0, y0) << std::endl;
//                        std::cerr << std::endl;
//                        cv::circle(show, cv::Point2d(x0, y0), 4,
//                                cv::Scalar::all(255), 3, 8);
//
//                    }
//                    unsigned int xH = xs.size() / 2;
//                    unsigned int yH = ys.size() / 2;
//                    std::nth_element(xs.begin(), xs.begin() + xH,
//                            xs.end());
//                    std::nth_element(ys.begin(), ys.begin() + yH,
//                            ys.end());
//                    std::cerr << cv::Point2d(xs[xH], ys[yH])
//                            << std::endl;
//                    std::cerr
//                            << cv::Point2d(sumX / counter,
//                                    sumY / counter) << std::endl;
//                    std::cerr << _rotationCenter << std::endl;
////                cv::circle(show,cv::Point2d(xs[xH], ys[yH]),8,cv::Scalar::all(255),3,8);
////                cv::circle(show,cv::Point2d(sumX/counter, sumY/counter),4,cv::Scalar::all(255),3,8);
//                    double medx = sumX / counter;
//                    double medy = sumX / counter;
//                    double varx = 0;
//                    double vary = 0;
//                    for (unsigned k = 0; k < xs.size(); ++k) {
//                        varx += (medx - xs[k]) * (medx - xs[k]);
//                        vary += (medy - ys[k]) * (medy - ys[k]);
//                    }
//
//                    std::cerr << varx / xs.size() << std::endl;
//                    std::cerr << vary / ys.size() << std::endl;
//
//                }
//            }
//            cv::imshow("c3", show);
//        }
        if (!_trackedFeatures.empty()) {
//			cv::Mat pre = drawFeatureHistory(newTransformed, _trackedFeatures);
//			imshow("c1", pre);
//			imshow("ol", _oldFrame);
            for (std::list<FeatureFilter*>::iterator it =
                    _filters.begin(); it != _filters.end(); ++it) {
                _trackedFeatures = (*it)->filterFeatures(
                        _trackedFeatures);
            }
//			cv::Mat post = newTransformed.clone();
//			drawFeatureHistory(post, _trackedFeatures,3);
//            cv::imshow("c1", post);
            if (!_trackedFeatures.empty()) {
                std::vector<cv::Point2f> translations =
                        computeTranslationVectors(rotationMatrix);
                vectorHalf = translations.size() / 2;
                std::nth_element(translations.begin(),
                        translations.begin() + vectorHalf,
                        translations.end(), horizontalPoint2Compare);
                result.x = translations[vectorHalf].x;
                std::nth_element(translations.begin(),
                        translations.begin() + vectorHalf,
                        translations.end(), verticalPoint2Compare);
                result.y = translations[vectorHalf].y;
            }
        }
//
//    cv::Mat newRot;
//        cv::warpAffine(newTransformed, newRot, rotationMatrix,
//                newTransformed.size());
//        imshow("c2", _oldFrame - newRot);
//      imshow("c3", newRot);
// cv::waitKey(1);

    }
    _oldFrame = newTransformed.clone();
    // std::cerr << "bird out" << std::endl;
    return result;
}

std::vector<cv::Point2f> BirdsEyeTranslationReader::computeTranslationVectors(
        const cv::Mat& rotationMatrix) {
    std::vector<cv::Point2f> result(_trackedFeatures.size());
    std::vector<cv::Point2f> oldFeatures(_trackedFeatures.size()),
            newFeatures(_trackedFeatures.size());
    std::vector<cv::Point2f> newTransformed(newFeatures.size());

    for (unsigned int i = 0; i < result.size(); ++i) { //Highly susceptible to bugs
        oldFeatures[i] = _trackedFeatures[i].front();
        newFeatures[i] = *(++_trackedFeatures[i].begin());
    }

    cv::transform(newFeatures, newTransformed, rotationMatrix);
    for (unsigned int i = 0; i < result.size(); ++i) {
        result[i] = newTransformed[i] - oldFeatures[i];
    }

    return result;
}

<|endoftext|>


<commit_before>/*
 * opencog/persist/PersistModule.cc
 *
 * Copyright (C) 2008 by OpenCog Foundation
 * All Rights Reserved
 *
 * Written by Gustavo Gama <gama@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "PersistModule.h"
#include "AtomStorage.h"

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atomspace/BackingStore.h>
#include <opencog/guile/SchemePrimitive.h>

using namespace opencog;

namespace opencog {
class SQLBackingStore : public BackingStore
{
	private:
		AtomStorage *store;
	public:
		SQLBackingStore();
		void set_store(AtomStorage *);

		virtual NodePtr getNode(Type, const char *) const;
		virtual LinkPtr getLink(Type, const HandleSeq&) const;
		virtual AtomPtr getAtom(Handle) const;
		virtual HandleSeq getIncomingSet(Handle) const;
		virtual void storeAtom(Handle);
};
};

SQLBackingStore::SQLBackingStore()
{
	store = NULL;
}

void SQLBackingStore::set_store(AtomStorage *as)
{
	store = as;
}

NodePtr SQLBackingStore::getNode(Type t, const char *name) const
{
	return store->getNode(t, name);
}

LinkPtr SQLBackingStore::getLink(Type t, const std::vector<Handle>& oset) const
{
	return store->getLink(t, oset);
}

AtomPtr SQLBackingStore::getAtom(Handle h) const
{
	return store->getAtom(h);
}

HandleSeq SQLBackingStore::getIncomingSet(Handle h) const
{
	return store->getIncomingSet(h);
}

void SQLBackingStore::storeAtom(Handle h)
{
	store->storeAtom(h);
}

DECLARE_MODULE(PersistModule);

PersistModule::PersistModule(CogServer& cs) : Module(cs), store(NULL)
{
	backing = new SQLBackingStore();
	do_close_register();
	do_load_register();
	do_open_register();
	do_store_register();

#ifdef HAVE_GUILE
	// XXX These probably should be declared by the atom-space directly,
	// instead of being declared here ... but I guess this is an OK
	// home for now.
	define_scheme_primitive("fetch-atom", &PersistModule::fetch_atom, this);
	define_scheme_primitive("fetch-incoming-set", &PersistModule::fetch_incoming_set, this);
	define_scheme_primitive("store-atom", &PersistModule::store_atom, this);
#endif
}

PersistModule::~PersistModule()
{
	do_close_unregister();
	do_load_unregister();
	do_open_unregister();
	do_store_unregister();
	delete backing;
}

void PersistModule::init(void)
{
}

std::string PersistModule::do_close(Request *dummy, std::list<std::string> args)
{
	if (!args.empty())
		return "sql-close: Error: Unexpected argument";

	if (store == NULL)
		return "sql-close: Error: Database not open";

	_cogserver.getAtomSpace().getImpl().unregisterBackingStore(backing);

	backing->set_store(NULL);
	delete store;
	store = NULL;
	return "Database closed";
}

std::string PersistModule::do_load(Request *dummy, std::list<std::string> args)
{
	if (!args.empty())
		return "sql-load: Error: Unexpected argument";

	if (store == NULL)
		return "sql-load: Error: Database not open";

	// XXX TODO: this should probably be done in a separate thread.
	store->load(const_cast<AtomTable&>(_cogserver.getAtomSpace().getAtomTable()));

	return "Database load completed";
}

std::string PersistModule::do_open(Request *dummy, std::list<std::string> args)
{
	if (args.size() != 3)
		return "sql-open: Error: invalid command syntax\n"
		       "Usage: sql-open <dbname> <username> <auth>";

	std::string dbname   = args.front(); args.pop_front();
	std::string username = args.front(); args.pop_front();
	std::string auth	   = args.front(); args.pop_front();

	store = new AtomStorage(dbname, username, auth);
	if (!store)
		return "sql-open: Error: Unable to open the database";

	if (!store->connected())
	{
		delete store;
		store = NULL;
		return "sql-open: Error: Unable to connect to the database";
	}

	// reserve() is critical here, to reserve UUID range.
	store->reserve();
	backing->set_store(store);
	_cogserver.getAtomSpace().getImpl().registerBackingStore(backing);

	std::string rc = "Opened \"" + dbname + "\" as user \"" + username + "\"";
	return rc;
}

std::string PersistModule::do_store(Request *dummy, std::list<std::string> args)
{
	if (!args.empty())
		return "sql-store: Error: Unexpected argument";

	if (store == NULL)
		return "sql-store: Error: Database not open";

	// XXX TODO This should really be started in a new thread ...
	store->store(const_cast<AtomTable&>(_cogserver.getAtomSpace().getAtomTable()));

	return "Database store completed";
}

Handle PersistModule::fetch_atom(Handle h)
{
	AtomSpace *as = &_cogserver.getAtomSpace();
	h = as->getImpl().fetchAtom(h);
	return h;
}

Handle PersistModule::fetch_incoming_set(Handle h)
{
	AtomSpace *as = &_cogserver.getAtomSpace();
	// The "true" flag here means "fetch recursive".
	h = as->getImpl().fetchIncomingSet(h, true);
	return h;
}

/**
 * Store the single atom to the backing store hanging off the atom-space
 */
Handle PersistModule::store_atom(Handle h)
{
	AtomSpace *as = &_cogserver.getAtomSpace();
	as->getImpl().storeAtom(h);
	return h;
}

<commit_msg>Add missing carriage returns<commit_after>/*
 * opencog/persist/PersistModule.cc
 *
 * Copyright (C) 2008 by OpenCog Foundation
 * All Rights Reserved
 *
 * Written by Gustavo Gama <gama@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "PersistModule.h"
#include "AtomStorage.h"

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atomspace/BackingStore.h>
#include <opencog/guile/SchemePrimitive.h>

using namespace opencog;

namespace opencog {
class SQLBackingStore : public BackingStore
{
	private:
		AtomStorage *store;
	public:
		SQLBackingStore();
		void set_store(AtomStorage *);

		virtual NodePtr getNode(Type, const char *) const;
		virtual LinkPtr getLink(Type, const HandleSeq&) const;
		virtual AtomPtr getAtom(Handle) const;
		virtual HandleSeq getIncomingSet(Handle) const;
		virtual void storeAtom(Handle);
};
};

SQLBackingStore::SQLBackingStore()
{
	store = NULL;
}

void SQLBackingStore::set_store(AtomStorage *as)
{
	store = as;
}

NodePtr SQLBackingStore::getNode(Type t, const char *name) const
{
	return store->getNode(t, name);
}

LinkPtr SQLBackingStore::getLink(Type t, const std::vector<Handle>& oset) const
{
	return store->getLink(t, oset);
}

AtomPtr SQLBackingStore::getAtom(Handle h) const
{
	return store->getAtom(h);
}

HandleSeq SQLBackingStore::getIncomingSet(Handle h) const
{
	return store->getIncomingSet(h);
}

void SQLBackingStore::storeAtom(Handle h)
{
	store->storeAtom(h);
}

DECLARE_MODULE(PersistModule);

PersistModule::PersistModule(CogServer& cs) : Module(cs), store(NULL)
{
	backing = new SQLBackingStore();
	do_close_register();
	do_load_register();
	do_open_register();
	do_store_register();

#ifdef HAVE_GUILE
	// XXX These probably should be declared by the atom-space directly,
	// instead of being declared here ... but I guess this is an OK
	// home for now.
	define_scheme_primitive("fetch-atom", &PersistModule::fetch_atom, this);
	define_scheme_primitive("fetch-incoming-set", &PersistModule::fetch_incoming_set, this);
	define_scheme_primitive("store-atom", &PersistModule::store_atom, this);
#endif
}

PersistModule::~PersistModule()
{
	do_close_unregister();
	do_load_unregister();
	do_open_unregister();
	do_store_unregister();
	delete backing;
}

void PersistModule::init(void)
{
}

std::string PersistModule::do_close(Request *dummy, std::list<std::string> args)
{
	if (!args.empty())
		return "sql-close: Error: Unexpected argument\n";

	if (store == NULL)
		return "sql-close: Error: Database not open\n";

	_cogserver.getAtomSpace().getImpl().unregisterBackingStore(backing);

	backing->set_store(NULL);
	delete store;
	store = NULL;
	return "Database closed\n";
}

std::string PersistModule::do_load(Request *dummy, std::list<std::string> args)
{
	if (!args.empty())
		return "sql-load: Error: Unexpected argument\n";

	if (store == NULL)
		return "sql-load: Error: Database not open\n";

	// XXX TODO: this should probably be done in a separate thread.
	store->load(const_cast<AtomTable&>(_cogserver.getAtomSpace().getAtomTable()));

	return "Database load completed\n";
}

std::string PersistModule::do_open(Request *dummy, std::list<std::string> args)
{
	if (args.size() != 3)
		return "sql-open: Error: invalid command syntax\n"
		       "Usage: sql-open <dbname> <username> <auth>\n";

	std::string dbname   = args.front(); args.pop_front();
	std::string username = args.front(); args.pop_front();
	std::string auth	   = args.front(); args.pop_front();

	store = new AtomStorage(dbname, username, auth);
	if (!store)
		return "sql-open: Error: Unable to open the database\n";

	if (!store->connected())
	{
		delete store;
		store = NULL;
		return "sql-open: Error: Unable to connect to the database\n";
	}

	// reserve() is critical here, to reserve UUID range.
	store->reserve();
	backing->set_store(store);
	_cogserver.getAtomSpace().getImpl().registerBackingStore(backing);

	std::string rc = "Opened \"" + dbname + "\" as user \"" + username + "\"\n";
	return rc;
}

std::string PersistModule::do_store(Request *dummy, std::list<std::string> args)
{
	if (!args.empty())
		return "sql-store: Error: Unexpected argument\n";

	if (store == NULL)
		return "sql-store: Error: Database not open\n";

	// XXX TODO This should really be started in a new thread ...
	store->store(const_cast<AtomTable&>(_cogserver.getAtomSpace().getAtomTable()));

	return "Database store completed\n";
}

Handle PersistModule::fetch_atom(Handle h)
{
	AtomSpace *as = &_cogserver.getAtomSpace();
	h = as->getImpl().fetchAtom(h);
	return h;
}

Handle PersistModule::fetch_incoming_set(Handle h)
{
	AtomSpace *as = &_cogserver.getAtomSpace();
	// The "true" flag here means "fetch recursive".
	h = as->getImpl().fetchIncomingSet(h, true);
	return h;
}

/**
 * Store the single atom to the backing store hanging off the atom-space
 */
Handle PersistModule::store_atom(Handle h)
{
	AtomSpace *as = &_cogserver.getAtomSpace();
	as->getImpl().storeAtom(h);
	return h;
}

<|endoftext|>