Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  SegmentTracker.cpp   Sprache: C

 

/*****************************************************************************
 *
 *****************************************************************************
 * Copyright (C) 2022 VideoLabs, 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 "../SegmentTracker.hpp"
#include "../SharedResources.hpp"
#include "../logic/AbstractAdaptationLogic.h"
#include "../logic/BufferingLogic.hpp"
#include "../Time.hpp"
#include "../playlist/BasePlaylist.hpp"
#include "../playlist/BasePeriod.h"
#include "../playlist/BaseAdaptationSet.h"
#include "../playlist/BaseRepresentation.h"
#include "../../hls/playlist/HLSRepresentation.hpp"
#include "../playlist/SegmentList.h"
#include "../playlist/Segment.h"
#include "../http/HTTPConnectionManager.h"

#include "test.hpp"

#include <vlc_block.h>

#include <limits>
#include <vector>
#include <map>
#include <set>
#include <cassert>
#include <cstring>

using namespace adaptive;
using namespace adaptive::http;
using namespace hls::playlist;

class DummyLogic : public AbstractAdaptationLogic
{
    public:
        DummyLogic() : AbstractAdaptationLogic(nullptr), repindex(0) {}
        virtual ~DummyLogic() = default;
        BaseRepresentation* getNextRepresentation(BaseAdaptationSet *set,
                                                  BaseRepresentation *) override
        {
            if(set->getRepresentations().size() <= repindex)
                return nullptr;
            return set->getRepresentations().at(repindex);
        }
        unsigned repindex;
};

class DummyChunkSource : public AbstractChunkSource
{
    public:
        DummyChunkSource(ChunkType t, const BytesRange &range, const std::vector<uint8_t> &v,
                         const std::string &content)
            : AbstractChunkSource(t, range), data(v), offset(0), contentType(content) {}
        virtual ~DummyChunkSource() = default;
        void recycle() override { delete this; }
        const std::string & getContentType  () const override
        {
            return contentType;
        }
        RequestStatus getRequestStatus() const override
        {
            return data.size() ? RequestStatus::Success : RequestStatus::GenericError;
        }
        block_t *   readBlock       ()  override
        {
            std::size_t remain = data.size() - offset;
            block_t *b = block_Alloc(remain);
            if(b)
                std::memcpy(b->p_buffer, &data[offset], remain);
            offset += remain;
            return b;
        }
        block_t *   read            (size_t sz)  override
        {
            std::size_t remain = data.size() - offset;
            if(remain < sz)
                sz = remain;
            block_t *b = block_Alloc(sz);
            if(b)
                std::memcpy(b->p_buffer, &data[offset], sz);
            offset += sz;
            return b;
        }

        bool        hasMoreData     () const  override { return offset < data.size(); }
        size_t      getBytesRead    () const  override { return offset; }

    private:
        std::vector<uint8_t> data;
        std::size_t offset;
        std::string contentType;
};

class DummyConnectionManager : public AbstractConnectionManager
{
    public:
        DummyConnectionManager() : AbstractConnectionManager(nullptr) {}
        virtual ~DummyConnectionManager() = default;
        void closeAllConnections () override {}
        AbstractConnection * getConnection(ConnectionParams &) override { return nullptr; }
        AbstractChunkSource *makeSource(const std::string &uri,
                                        const ID &, ChunkType t,
                                        const BytesRange &br) override
        {
            DummyChunkSource *d;
            auto it = data.find(uri);
            if(it == data.end())
                d = new DummyChunkSource(t, br, std::vector<uint8_t>(), uri);
            else
                d = new DummyChunkSource(t, br, it->second, uri);
            return d;
        }
        void recycleSource(AbstractChunkSource *) override {}
        void start(AbstractChunkSource *) override {}
        void cancel(AbstractChunkSource *) override {}

        std::map<std::string, std::vector<uint8_t>> data;
};

using mapentry = std::pair<std::string, std::vector<uint8_t>>;

class SegmentTrackerListener : public SegmentTrackerListenerInterface
{
    public:
        SegmentTrackerListener() : SegmentTrackerListenerInterface()
        {
            reset();
        }
        virtual ~SegmentTrackerListener() = default;
        void trackerEvent(const TrackerEvent &event) override
        {
            switch(event.getType())
            {
                case TrackerEvent::Type::SegmentChange:
                {
                    const SegmentChangedEvent *e =
                            static_cast<const SegmentChangedEvent *>(&event);
                    segmentchanged.displaytime = e->displaytime;
                    segmentchanged.duration = e->duration;
                    segmentchanged.sequence = e->sequence;
                    segmentchanged.starttime = e->starttime;
                }
                    break;
                case TrackerEvent::Type::FormatChange:
                {
                    const FormatChangedEvent *e =
                            static_cast<const FormatChangedEvent *>(&event);
                    formatchanged.format = *e->format;
                }
                    break;
                case TrackerEvent::Type::RepresentationSwitch:
                {
                    const RepresentationSwitchEvent *e =
                            static_cast<const RepresentationSwitchEvent *>(&event);
                    representationchanged.prev = e->prev;
                    representationchanged.next = e->next;
                }
                    break;
                case TrackerEvent::Type::Discontinuity:
                {
                    discontinuity = true;
                }
                    break;
                case TrackerEvent::Type::PositionChange:
                {
                    const PositionChangedEvent *e =
                            static_cast<const PositionChangedEvent *>(&event);
                    positionchanged.resumeTime = e->resumeTime;
                }
                    break;
                default:
                    return;
            }
            events.insert(event.getType());
        }

        bool occured(TrackerEvent::Type t) const
        {
            return events.find(t) != events.end();
        }

        void reset()
        {
            events.clear();
            segmentchanged.sequence = std::numeric_limits<uint64_t>::max() - 1;
            segmentchanged.displaytime = -1;
            segmentchanged.starttime = -1;
            segmentchanged.duration = -1;
            formatchanged.format = StreamFormat();
            representationchanged.prev = (BaseRepresentation *) 0xdeadbeef;
            representationchanged.next = (BaseRepresentation *) 0xdeadbeef;
            discontinuity = false;
            positionchanged.resumeTime = -1;
        }

        std::set<TrackerEvent::Type> events;
        struct
        {
            uint64_t sequence;
            vlc_tick_t displaytime;
            vlc_tick_t starttime;
            vlc_tick_t duration;
        } segmentchanged;
        struct
        {
            StreamFormat format;
        } formatchanged;
        struct
        {
            const BaseRepresentation *prev;
            const BaseRepresentation *next;
        } representationchanged;
        bool discontinuity;
        struct
        {
             vlc_tick_t resumeTime;
        } positionchanged;
};

class DummyRepresentation : public BaseRepresentation
{
    public:
        DummyRepresentation(BaseAdaptationSet *set) : BaseRepresentation(set) {}
        virtual ~DummyRepresentation() = default;
        StreamFormat getStreamFormat() const override { return StreamFormat::Type::Unknown; }
};

class DummyHLSRepresentation : public HLSRepresentation
{
    public:
        DummyHLSRepresentation(BaseAdaptationSet *set, time_t duration) :
            HLSRepresentation(set) { targetDuration = duration; }
        virtual ~DummyHLSRepresentation() = default;
        StreamFormat getStreamFormat() const override { return StreamFormat::Type::Unknown; }
        bool needsUpdate(uint64_t) const override { return false; }
        bool runLocalUpdates(SharedResources *) override { return false; }
};

static BaseAdaptationSet *CreatePlaylistPeriodAdaptationSet()
{
    BaseAdaptationSet *set = nullptr;
    BasePlaylist *pl= nullptr;
    try
    {
        pl = new BasePlaylist(nullptr);
        BasePeriod *period = new BasePeriod(pl);
        pl->addPeriod(period);
        set = new BaseAdaptationSet(period);
        period->addAdaptationSet(set);
    } catch( ... ) {
        delete pl;
    }
    return set;
}

static int SegmentTracker_check_formats(BaseAdaptationSet *adaptSet,
                                        DummyLogic *,
                                        SegmentTracker *tracker,
                                        SegmentTrackerListener &events)
{
    const stime_t START = 1337;
    Timescale timescale(100);

    ChunkInterface *currentChunk = nullptr;
    try
    {
        DummyRepresentation *rep0 = new DummyRepresentation(adaptSet);
        adaptSet->addRepresentation(rep0);
        rep0->setID(ID("0"));

        SegmentList *segmentList = nullptr;
        try
        {
            segmentList = new SegmentList(rep0);
            segmentList->addAttribute(new TimescaleAttr(timescale));
            for(int i=0; i<3; i++)
            {
                Segment *seg = new Segment(rep0);
                seg->setSequenceNumber(123 + i);
                seg->setDiscontinuitySequenceNumber(456);
                seg->startTime = START + 100 * i;
                seg->duration = 100;
                seg->setSourceUrl(i < 2 ? "sample/aac" : "sample/ac3");
                segmentList->addSegment(seg);
            }
        } catch (...) {
            delete segmentList;
            std::rethrow_exception(std::current_exception());
        }
        rep0->addAttribute(segmentList);

        /* No start pos */
        SegmentTracker::Position pos = tracker->getStartPosition();
        Expect(pos.isValid());
        Expect(pos.number == 123);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk == nullptr);

        /* Start pos ok */
        events.reset();
        Expect(tracker->setStartPosition() == true);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::SegmentChange) == true);
        Expect(events.occured(TrackerEvent::Type::FormatChange) == true);
        Expect(events.segmentchanged.starttime == timescale.ToTime(START) + VLC_TICK_0);
        Expect(events.segmentchanged.duration == timescale.ToTime(100));
        Expect(events.segmentchanged.sequence == 456);
        Expect(events.formatchanged.format == StreamFormat::Type::PackedAAC);
        delete currentChunk;
        currentChunk = nullptr;

        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.segmentchanged.starttime == timescale.ToTime(START + 100 * 1) + VLC_TICK_0);
        Expect(events.segmentchanged.duration == timescale.ToTime(100));
        Expect(events.occured(TrackerEvent::Type::FormatChange) == false);
        Expect(events.occured(TrackerEvent::Type::SegmentChange) == true);
        delete currentChunk;
        currentChunk = nullptr;

        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.segmentchanged.starttime == timescale.ToTime(START + 100 * 2) + VLC_TICK_0);
        Expect(events.segmentchanged.duration == timescale.ToTime(100));
        Expect(events.occured(TrackerEvent::Type::FormatChange) == true);
        Expect(events.occured(TrackerEvent::Type::SegmentChange) == true);
        Expect(events.formatchanged.format == StreamFormat::Type::PackedAC3);
        delete currentChunk;
        currentChunk = nullptr;

        /* Should fail */
        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk == nullptr);
        Expect(events.occured(TrackerEvent::Type::SegmentChange) == false);

    } catch( ... ) {
        delete currentChunk;
        return 1;
    }

    return 0;
}

/****** check position/alignment ******/
static int SegmentTracker_check_seeks(BaseAdaptationSet *adaptSet,
                                      DummyLogic *,
                                      SegmentTracker *tracker,
                                      SegmentTrackerListener &events)
{
    const stime_t START = 1337;
    Timescale timescale(100);

    ChunkInterface *currentChunk = nullptr;
    try
    {
        DummyRepresentation *rep0 = new DummyRepresentation(adaptSet);
        adaptSet->addRepresentation(rep0);
        rep0->setID(ID("0"));

        SegmentList *segmentList = nullptr;
        try
        {
            segmentList = new SegmentList(rep0);
            segmentList->addAttribute(new TimescaleAttr(timescale));
            for(int i=0; i<10; i++)
            {
                Segment *seg = new Segment(rep0);
                seg->setSequenceNumber(123 + i);
                seg->setDiscontinuitySequenceNumber(456);
                seg->startTime = START + 100 * i;
                seg->duration = 100;
                seg->setSourceUrl("sample/aac");
                segmentList->addSegment(seg);
            }
        } catch (...) {
            delete segmentList;
            std::rethrow_exception(std::current_exception());
        }
        rep0->addAttribute(segmentList);

        events.reset();
        Expect(tracker->setPositionByTime(VLC_TICK_0 + timescale.ToTime(START + 250), false, true) == true);
        Expect(events.occured(TrackerEvent::Type::PositionChange) == false);
        Expect(tracker->getPlaybackTime() == 0);

        events.reset();
        Expect(tracker->setPositionByTime(VLC_TICK_0 + timescale.ToTime(START + 250), false, false) == true);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::PositionChange) == true);
        Expect(events.positionchanged.resumeTime == timescale.ToTime(START + 200));
        Expect(tracker->getPlaybackTime() == timescale.ToTime(START + 200));
        delete currentChunk;
        currentChunk = nullptr;

        /* past playlist, align to end */
        events.reset();
        Expect(tracker->setPositionByTime(VLC_TICK_0 + timescale.ToTime(START + 9999), false, false) == true);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::PositionChange) == true);
        delete currentChunk;
        currentChunk = nullptr;

        /* out of playlist, we need to fail */
        Expect(tracker->setPositionByTime(VLC_TICK_0 + timescale.ToTime(START / 2), false, true) == false);
        Expect(tracker->setPositionByTime(VLC_TICK_0 + timescale.ToTime(START / 2), false, false) == false);

        /* restart playlist from startpos */
        events.reset();
        SegmentTracker::Position startpos = tracker->getStartPosition();
        Expect(startpos.isValid());
        tracker->setPosition(startpos, false);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::PositionChange) == true);
        Expect(events.positionchanged.resumeTime == timescale.ToTime(START));
        Expect(tracker->getPlaybackTime() == timescale.ToTime(START));
        delete currentChunk;
        currentChunk = nullptr;

        /* go to unaligned pos */
        events.reset();
        Expect(tracker->setPositionByTime(VLC_TICK_0 + timescale.ToTime(START + 250), false, false) == true);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::PositionChange) == true);
        Expect(events.positionchanged.resumeTime == timescale.ToTime(START + 2*100));
        Expect(tracker->getPlaybackTime() == timescale.ToTime(START + 2*100));
        delete currentChunk;
        currentChunk = nullptr;

    } catch( ... ) {
        delete currentChunk;
        return 1;
    }

    return 0;
}

/****** test with variants ******/
static int SegmentTracker_check_switches(BaseAdaptationSet *adaptSet,
                                         DummyLogic *logic,
                                         SegmentTracker *tracker,
                                         SegmentTrackerListener &events)
{
    const stime_t START = 1337;
    Timescale timescale(100);

    ChunkInterface *currentChunk = nullptr;
    try
    {
        DummyRepresentation *rep0 = new DummyRepresentation(adaptSet);
        adaptSet->addRepresentation(rep0);
        rep0->setID(ID("0"));

        SegmentList *segmentList = nullptr;
        try
        {
            segmentList = new SegmentList(rep0);
            segmentList->addAttribute(new TimescaleAttr(timescale));
            for(int i=0; i<5; i++)
            {
                Segment *seg = new Segment(rep0);
                seg->setSequenceNumber(123 + i);
                seg->setDiscontinuitySequenceNumber(456);
                seg->startTime = START + 100 * i;
                seg->duration = 100;
                seg->setSourceUrl("sample/aac");
                segmentList->addSegment(seg);
            }
        } catch (...) {
            delete segmentList;
            std::rethrow_exception(std::current_exception());
        }
        rep0->addAttribute(segmentList);
        segmentList->getSegments().at(4)->discontinuity = true;
        segmentList->getSegments().at(4)->setDiscontinuitySequenceNumber(457);

        DummyRepresentation *rep1 = new DummyRepresentation(adaptSet);
        adaptSet->addRepresentation(rep1);
        rep1->setID(ID("1"));

        try
        {
            segmentList = new SegmentList(rep1);
            segmentList->addAttribute(new TimescaleAttr(timescale));
            for(int i=0; i<5; i++)
            {
                Segment *seg = new Segment(rep1);
                seg->setSequenceNumber(123 + i);
                seg->setDiscontinuitySequenceNumber(456);
                seg->startTime = START + 100 * i;
                seg->duration = 100;
                seg->setSourceUrl("sample/aac");
                segmentList->addSegment(seg);
            }
        } catch (...) {
            delete segmentList;
            std::rethrow_exception(std::current_exception());
        }
        rep1->addAttribute(segmentList);

        /* have some init segment on rep1 */
        InitSegment *initSegment = new InitSegment(rep1);
        initSegment->setSourceUrl("sample/aacinit");
        segmentList->initialisationSegment = initSegment;

        Expect(adaptSet->isSegmentAligned());
        Expect(adaptSet->getRepresentations().size() == 2);

        /* initial switch notification */
        events.reset();
        Expect(tracker->setStartPosition() == true);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == true);
        Expect(events.representationchanged.prev == nullptr);
        Expect(events.representationchanged.next == rep0);
        delete currentChunk;
        currentChunk = nullptr;

        /* ask logic to switch */
        logic->repindex = 1;
        /* switch event should not trigger here */
        events.reset();
        currentChunk = tracker->getNextChunk(false);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == false);
        delete currentChunk;
        currentChunk = nullptr;

        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == true);
        Expect(events.representationchanged.prev == rep0);
        Expect(events.representationchanged.next == rep1);
        /* check returned init */
        Expect(currentChunk->getContentType() == "sample/aacinit");
        Expect(events.segmentchanged.starttime == timescale.ToTime(START + 100 * 2) + VLC_TICK_0);
        Expect(events.segmentchanged.duration == timescale.ToTime(100));
        Expect(events.segmentchanged.sequence == 456);
        delete currentChunk;
        currentChunk = nullptr;

        /* check segment */
        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == false);
        Expect(currentChunk->getContentType() == "sample/aac");
        /* time should remain the same */
        Expect(events.segmentchanged.starttime == timescale.ToTime(START + 100 * 2) + VLC_TICK_0);
        Expect(events.segmentchanged.duration == timescale.ToTime(100));
        Expect(events.segmentchanged.sequence == 456);
        delete currentChunk;
        currentChunk = nullptr;

        /* ask logic to switch back */
        logic->repindex = 0;
        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == true);
        Expect(events.representationchanged.prev == rep1);
        Expect(events.representationchanged.next == rep0);
        delete currentChunk;
        currentChunk = nullptr;

        /* check continuity & sequence handling */
        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::Discontinuity) == true);
        Expect(events.segmentchanged.sequence == 457);
        Expect(events.discontinuity == true);
        delete currentChunk;
        currentChunk = nullptr;

        /* reset playlist to rep1 */
        logic->repindex = 1;
        events.reset();
        SegmentTracker::Position startpos = tracker->getStartPosition();
        Expect(startpos.isValid());
        tracker->setPosition(startpos, false);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == true);
        Expect(events.representationchanged.prev == nullptr);
        Expect(events.representationchanged.next == rep1);
        Expect(currentChunk->getContentType() == "sample/aacinit");
        delete currentChunk;
        currentChunk = nullptr;

        /* We must not allow repA init to unmatched repB X */
        logic->repindex = 0;
        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == false);
        Expect(currentChunk->getContentType() == "sample/aac");
        delete currentChunk;
        currentChunk = nullptr;

        /* should now allow switch on next segment */
        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == true);
        delete currentChunk;
        currentChunk = nullptr;

    } catch( ... ) {
        delete currentChunk;
        return 1;
    }

    return 0;
}

/****** check position/alignment with segment translation ******/
static int SegmentTracker_check_HLSseeks(BaseAdaptationSet *adaptSet,
                                         DummyLogic *logic,
                                         SegmentTracker *tracker,
                                         SegmentTrackerListener &events)
{
    const stime_t START = 1337;
    Timescale timescale(100);

    ChunkInterface *currentChunk = nullptr;
    try
    {
        DummyHLSRepresentation *rep0 = new DummyHLSRepresentation(adaptSet, 1);
        adaptSet->addRepresentation(rep0);
        rep0->setID(ID("0"));

        SegmentList *segmentList = nullptr;
        try
        {
            segmentList = new SegmentList(rep0);
            segmentList->addAttribute(new TimescaleAttr(timescale));
            for(int i=0; i<10; i++)
            {
                Segment *seg = new Segment(rep0);
                seg->setSequenceNumber(123 + i);
                seg->startTime = START + 100 * i;
                seg->duration = 100;
                seg->setSourceUrl("sample/aac");
                segmentList->addSegment(seg);
            }
        } catch (...) {
            delete segmentList;
            std::rethrow_exception(std::current_exception());
        }
        rep0->addAttribute(segmentList);

        DummyHLSRepresentation *rep1 = new DummyHLSRepresentation(adaptSet, 3);
        adaptSet->addRepresentation(rep1);
        rep1->setID(ID("1"));

        segmentList = nullptr;
        try
        {
            segmentList = new SegmentList(rep1);
            segmentList->addAttribute(new TimescaleAttr(timescale));
            for(int i=0; i<4; i++)
            {
                Segment *seg = new Segment(rep1);
                seg->setSequenceNumber(123 + i);
                seg->startTime = START + 250 * i;
                seg->duration = 250;
                seg->setSourceUrl("sample/aac");
                segmentList->addSegment(seg);
            }
        } catch (...) {
            delete segmentList;
            std::rethrow_exception(std::current_exception());
        }
        rep1->addAttribute(segmentList);

        /* on rep0 */
        Expect(tracker->setPositionByTime(VLC_TICK_0 + timescale.ToTime(START + 300), false, false) == true);
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::PositionChange) == true);
        Expect(events.positionchanged.resumeTime == timescale.ToTime(START + 300));
        Expect(tracker->getPlaybackTime() == timescale.ToTime(START + 300));
        delete currentChunk;
        currentChunk = nullptr;

        /* on rep1 */
        logic->repindex = 1;
        events.reset();
        currentChunk = tracker->getNextChunk(true);
        Expect(currentChunk);
        Expect(events.occured(TrackerEvent::Type::RepresentationSwitch) == true);
        Expect(tracker->getPlaybackTime() == timescale.ToTime(START + 250)); // FIXME
        delete currentChunk;
        currentChunk = nullptr;

    } catch( ... ) {
        delete currentChunk;
        return 1;
    }

    return 0;
}

typedef decltype(SegmentTracker_check_formats) testfunc;

static int Prepare_test(testfunc func)
{
    DummyConnectionManager *connManager = nullptr;
    try
    {
        connManager = new DummyConnectionManager;
    } catch( ... ) { return 1; }

    connManager->data.insert(mapentry("sample/aac", std::vector<uint8_t>({ 0xFF, 0xF1, 0, 0 })));
    connManager->data.insert(mapentry("sample/ac3", std::vector<uint8_t>({ 0x0b, 0x77, 0, 0, 0, 0 })));
    connManager->data.insert(mapentry("sample/aacinit", std::vector<uint8_t>({ 0xFF, 0xF1, 0, 0 })));

    SharedResources sharedRes(nullptr, nullptr, connManager);
    DefaultBufferingLogic bufLogic;
    SynchronizationReferences syncRefs;

    BaseAdaptationSet *adaptSet = CreatePlaylistPeriodAdaptationSet();
    if(!adaptSet)
        return 1;

    BasePlaylist *playlist = adaptSet->getPlaylist();

    SegmentTracker *tracker;
    DummyLogic *logic = nullptr;
    try
    {
        logic = new DummyLogic();
        tracker = new SegmentTracker(&sharedRes, logic, &bufLogic, adaptSet, &syncRefs);
    } catch(...) {
        delete playlist;
        delete logic;
        return 1;
    }

    SegmentTrackerListener events;
    tracker->registerListener(&events);

    int ret = func(adaptSet, logic, tracker, events);

    delete tracker;
    delete logic;
    delete playlist;

    return ret;
}

int SegmentTracker_test()
{
    return
        Prepare_test(SegmentTracker_check_formats) ||
        Prepare_test(SegmentTracker_check_seeks) ||
        Prepare_test(SegmentTracker_check_switches) ||
        Prepare_test(SegmentTracker_check_HLSseeks) ||
        0;
}

Messung
CHZG
819910093

¤ Dauer der Verarbeitung: 0.10 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=418202