Eine aufbereitete Darstellung der Quelle

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

Benutzer

Quelle  M3U8.cpp   Sprache: C

 

/*****************************************************************************
 *
 *****************************************************************************
 * Copyright (C) 2020 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 "../../playlist/Segment.h"
#include "../../playlist/SegmentList.h"
#include "../../playlist/BasePeriod.h"
#include "../../playlist/BaseAdaptationSet.h"
#include "../../playlist/BaseRepresentation.h"
#include "../../logic/BufferingLogic.hpp"
#include "../../tools/FormatNamespace.hpp"
#include "../../SegmentTracker.hpp"
#include "../../../hls/playlist/Parser.hpp"
#include "../../../hls/playlist/M3U8.hpp"
#include "../../../hls/playlist/HLSSegment.hpp"
#include "../../../hls/playlist/HLSRepresentation.hpp"

#include "../test.hpp"

#include <vlc_stream.h>

#include <limits>
#include <algorithm>

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

static M3U8 * ParseM3U8(vlc_object_t *obj, const char *psz, size_t isz)
{
    M3U8Parser parser(nullptr);
    stream_t *substream = vlc_stream_MemoryNew(obj, ((uint8_t *)psz), isz, true);
    if(!substream)
        return nullptr;
    M3U8 *m3u = parser.parse(obj, substream, std::string("stdin://"));
    vlc_stream_Delete(substream);
    return m3u;
}

int M3U8MasterPlaylist_test()
{
    vlc_object_t *obj = static_cast<vlc_object_t*>(nullptr);

    const char manifest0[] =
    "#EXTM3U\n"
    "#EXT-X-STREAM-INF:BANDWIDTH=1280000\n"
    "http://example.com/low.m3u8\n"
    "#EXT-X-STREAM-INF:BANDWIDTH=2560000\n"
    "http://example.com/mid.m3u8\n"
    "#EXT-X-STREAM-INF:BANDWIDTH=7680000\n"
    "http://example.com/hi.m3u8\n"
    "#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\"\n"
    "http://example.com/audio-only.m3u8\n";

    M3U8 *m3u = ParseM3U8(obj, manifest0, sizeof(manifest0));
    try
    {
        Expect(m3u);
        Expect(m3u->getUrlSegment().toString() == "stdin://");
        Expect(m3u->getPeriods().size() == 1);
        Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 1);
        Expect(m3u->getFirstPeriod()->getAdaptationSets().front()->getRepresentations().size() == 4);
        BaseAdaptationSet *set = m3u->getFirstPeriod()->getAdaptationSets().front();
        const std::vector<BaseRepresentation *> &reps = set->getRepresentations();
        auto it = std::find_if(reps.cbegin(), reps.cend(),
                          [](BaseRepresentation *r) { return r->getBandwidth() == 1280000; });
        Expect(it != reps.end());
        Expect(static_cast<HLSRepresentation *>(*it)->getPlaylistUrl().toString() == "http://example.com/low.m3u8");
        it = std::find_if(reps.cbegin(), reps.cend(),
                      [](BaseRepresentation *r) { return r->getBandwidth() == 65000; });
        Expect(it != reps.end());
        Expect(static_cast<HLSRepresentation *>(*it)->getPlaylistUrl().toString() == "http://example.com/audio-only.m3u8");
        Expect((*it)->getUrlSegment().toString() == "http://example.com/");
        const std::list<std::string> &codecs = (*it)->getCodecs();
        Expect(!codecs.empty());
        Expect(codecs.front() == "mp4a.40.5");
        Expect((*it)->needsUpdate(1));
        delete m3u;
    }
    catch(...)
    {
        delete m3u;
        return 1;
    }

    const char manifest1[] =
    "#EXTM3U\n"
    "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"English\", "
    " DEFAULT=YES,AUTOSELECT=YES,LANGUAGE=\"en\", "
    " URI=\"main/english-audio.m3u8\"\n"
    "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Deutsch\", "
    " DEFAULT=NO,AUTOSELECT=YES,LANGUAGE=\"de\", "
    " URI=\"main/german-audio.m3u8\"\n"
    "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aac\",NAME=\"Commentary\", "
    " DEFAULT=NO,AUTOSELECT=NO,LANGUAGE=\"en\", "
    " URI=\"commentary/audio-only.m3u8\"\n"
    "#EXT-X-STREAM-INF:BANDWIDTH=7680000,CODECS=\"avc1, mp4a.40.5\",AUDIO=\"aac\"\n"
    "hi/video-only.m3u8\n"
    "#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS=\"mp4a.40.5\",AUDIO=\"aac\"\n"
    "main/english-audio.m3u8\n";

    m3u = ParseM3U8(obj, manifest1, sizeof(manifest1));
    try
    {
        Expect(m3u);
        Expect(m3u->getPeriods().size() == 1);
        Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 3);
        BaseAdaptationSet *set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("aac English"));
        Expect(set);
        Expect(set->getRepresentations().size() == 2);
        Expect(set->getLang() == "en");
        Expect(set->getRole().autoSelectable());
        Expect(set->getRole().isDefault());
        delete m3u;
    }
    catch(...)
    {
        delete m3u;
        return 1;
    }

    /* Empty MEDIA URI property group propagation test */
    {
        const char srcmanifest[] =
        "#EXTM3U\n"
        "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aach-64\",NAME=\"audio 64\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"2\"\n"
        "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"aacl-128\",NAME=\"audio 128\",AUTOSELECT=YES,DEFAULT=YES,CHANNELS=\"2\"\n"
        "#EXT-X-STREAM-INF:BANDWIDTH=75000,AVERAGE-BANDWIDTH=70000,CODECS=\"mp4a.40.5\",AUDIO=\"aach-64\"\n"
        "streaminf0.m3u8\n"
        "#EXT-X-STREAM-INF:BANDWIDTH=150000,AVERAGE-BANDWIDTH=125000,CODECS=\"mp4a.40.2\",AUDIO=\"aacl-128\"\n"
        "streaminf1.m3u8\n"
        ;

        m3u = ParseM3U8(obj, srcmanifest, sizeof(srcmanifest));
        try
        {
            Expect(m3u);
            Expect(m3u->getFirstPeriod());
            Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 1);
            BaseAdaptationSet *set = m3u->getFirstPeriod()->getAdaptationSets().front();
            Expect(set->getRole().autoSelectable());
            Expect(set->getRole().isDefault());
            auto reps = set->getRepresentations();
            Expect(reps.size() == 2);
            Expect(reps[0]->getBandwidth() == 70000);
            Expect(reps[1]->getBandwidth() == 125000);

            FormatNamespace fns("mp4a.40.5");
            CodecDescriptionList codecsdesclist;
            reps[0]->getCodecsDesc(&codecsdesclist);
            Expect(codecsdesclist.size() == 1);
            const es_format_t *fmt = codecsdesclist.front()->getFmt();
            Expect(fmt != nullptr);
            Expect(fmt->i_codec == fns.getFmt()->i_codec);
            Expect(fmt->i_profile == fns.getFmt()->i_profile);
            Expect(fmt->i_cat == AUDIO_ES);
            Expect(fmt->audio.i_channels == 2);

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

    /* check codec assignment per group */
    {
        const char srcmanifest[] =
        "#EXTM3U\n"
        "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"Audio\",NAME=\"en_aud\",DEFAULT=YES,AUTOSELECT=YES,"
        " LANGUAGE=\"en\",CHANNELS=\"2\",URI=\"a0.m3u8\"\n"
        "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\"Subtitles\",NAME=\"sub_fr\",DEFAULT=YES,FORCED=NO,LANGUAGE=\"fr\","
        " URI=\"cc0.m3u8\"\n"
        "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS,GROUP-ID=\"Closed Captions\",NAME=\"cc_en\",DEFAULT=YES,AUTOSELECT=YES,"
        " LANGUAGE=\"en\",INSTREAM-ID=\"CC1\"\n"
        "#EXT-X-STREAM-INF:BANDWIDTH=629758,AVERAGE-BANDWIDTH=572508,RESOLUTION=426x240,CODECS=\"avc1.42E015,mp4a.40.2,wvtt\","
        " FRAME-RATE=25,AUDIO=\"Audio\",SUBTITLES=\"Subtitles\",CLOSED-CAPTIONS=\"Closed Captions\"\n"
        "v0.m3u8\n"
        "#EXT-X-STREAM-INF:BANDWIDTH=1069758,AVERAGE-BANDWIDTH=972508,RESOLUTION=640x360,CODECS=\"avc1.4D401E,mp4a.40.2,wvtt\","
        " FRAME-RATE=29.970,AUDIO=\"Audio\",SUBTITLES=\"Subtitles\",CLOSED-CAPTIONS=\"Closed Captions\"\n"
        "v1.m3u8\n"
        ;

        m3u = ParseM3U8(obj, srcmanifest, sizeof(srcmanifest));
        try
        {
            Expect(m3u);
            Expect(m3u->getFirstPeriod());
            Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 3);

            {
                auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("Audio en_aud"));
                Expect(set != nullptr);
                auto reps = set->getRepresentations();
                Expect(reps.size() == 1);
                FormatNamespace fns("mp4a.40.2");
                CodecDescriptionList codecsdesclist;
                reps[0]->getCodecsDesc(&codecsdesclist);
                Expect(codecsdesclist.size() == 1);
                const es_format_t *fmt = codecsdesclist.front()->getFmt();
                Expect(fmt != nullptr);
                Expect(fmt->i_codec == fns.getFmt()->i_codec);
                Expect(fmt->i_cat == AUDIO_ES);
                Expect(fmt->audio.i_channels == 2);
            }

            {
                auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("Subtitles sub_fr"));
                Expect(set != nullptr);
                auto reps = set->getRepresentations();
                Expect(reps.size() == 1);
                FormatNamespace fns("wvtt");
                CodecDescriptionList codecsdesclist;
                reps[0]->getCodecsDesc(&codecsdesclist);
                Expect(codecsdesclist.size() == 1);
                const es_format_t *fmt = codecsdesclist.front()->getFmt();
                Expect(fmt != nullptr);
                Expect(fmt->i_codec == fns.getFmt()->i_codec);
                Expect(fmt->i_cat == SPU_ES);
            }

            {
                auto set = m3u->getFirstPeriod()->getAdaptationSetByID(ID("default_id#0"));
                Expect(set != nullptr);
                auto reps = set->getRepresentations();
                Expect(reps.size() == 2);
                FormatNamespace fns("avc1.42E015");
                CodecDescriptionList codecsdesclist;
                reps[0]->getCodecsDesc(&codecsdesclist);
                Expect(codecsdesclist.size() == 1);
                const es_format_t *fmt = codecsdesclist.front()->getFmt();
                Expect(fmt != nullptr);
                Expect(fmt->i_codec == fns.getFmt()->i_codec);
                Expect(fmt->i_cat == VIDEO_ES);
            }

            delete m3u;
        }
        catch (...)
        {
            delete m3u;
            return 1;
        }
    }
    return 0;
}

int M3U8Playlist_test()
{
    vlc_object_t *obj = static_cast<vlc_object_t*>(nullptr);
    DefaultBufferingLogic bufferingLogic;

    /* Manifest 0 */
    const char manifest0[] =
    "#EXTM3U\n"
    "#EXT-X-MEDIA-SEQUENCE:10\n"
    "#EXTINF:8,\n"
    "foobar.ts\n"
    "#EXT-X-ENDLIST\n";

    M3U8 *m3u = ParseM3U8(obj, manifest0, sizeof(manifest0));
    try
    {
        Expect(m3u);
        Expect(m3u->isLive() == false);
        Expect(m3u->isLowLatency() == false);
        Expect(m3u->getPeriods().size() == 1);
        Expect(m3u->getFirstPeriod()->getAdaptationSets().size() == 1);
        Expect(m3u->getFirstPeriod()->getAdaptationSets().front()->getRepresentations().size() == 1);
        BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->getRepresentations().front();
        Expect(rep->getProfile()->getStartSegmentNumber() == 10);

        uint64_t number = bufferingLogic.getStartSegmentNumber(rep);
        Expect(number == 10);
        vlc_tick_t mediatime, duration;
        Expect(rep->getPlaybackTimeDurationBySegmentNumber(std::numeric_limits<uint64_t>::max(),
                                                           &mediatime, &duration) == false);
        Expect(rep->getPlaybackTimeDurationBySegmentNumber(number + 1, &mediatime, &duration) == false);
        Expect(rep->getPlaybackTimeDurationBySegmentNumber(number - 1, &mediatime, &duration) == false);
        Expect(rep->getPlaybackTimeDurationBySegmentNumber(number, &mediatime, &duration) == true);
        Expect(mediatime == vlc_tick_from_sec(0));
        Expect(duration == vlc_tick_from_sec(8));
        Expect(rep->getSegmentNumberByTime(vlc_tick_from_sec(0), &number));
        Expect(number == 10);
        Segment *seg = rep->getMediaSegment(number);
        Expect(seg);
        Expect(seg->getSequenceNumber() == 10);
        Expect(seg->startTime == (stime_t) 0);

        vlc_tick_t begin, end;
        Expect(rep->getMediaPlaybackRange(&begin, &end, &duration));
        Expect(begin == vlc_tick_from_sec(0));
        Expect(end == vlc_tick_from_sec(8));
        Expect(duration == vlc_tick_from_sec(8));
        delete m3u;
    }
    catch(...)
    {
        delete m3u;
        return 1;
    }

    /* Manifest 1 */
    const char manifest1[] =
    "#EXTM3U\n"
    "#EXT-X-MEDIA-SEQUENCE:10\n"
    "#EXTINF:8,\n"
    "foobar.ts\n"
    "#EXTINF:12.0,\n" /* Broken format test: non integral notation */
    "foobar2.ts\n"
    "#EXTINF:10\n" /* Broken format test: no mandatory comma */
    "foobar3.ts\n"
    "#EXT-X-ENDLIST\n";

    m3u = ParseM3U8(obj, manifest1, sizeof(manifest1));
    try
    {
        Expect(m3u);
        BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->
                                  getRepresentations().front();
        Expect(rep->getProfile()->getStartSegmentNumber() == 10);
        Expect(m3u->duration);

        Timescale timescale = rep->inheritTimescale();
        Expect(timescale.isValid());

        uint64_t number;
        bool discont;
        Segment *seg = rep->getNextMediaSegment(12, &number, &discont);
        Expect(seg);
        Expect(number == 12);
        Expect(!discont);
        Expect(seg->getSequenceNumber() == 12);
        Expect(seg->startTime == timescale.ToScaled(vlc_tick_from_sec(20)));

        vlc_tick_t begin, end, duration;
        Expect(rep->getMediaPlaybackRange(&begin, &end, &duration));
        Expect(begin == vlc_tick_from_sec(0));
        Expect(end == vlc_tick_from_sec(30));
        Expect(duration == vlc_tick_from_sec(30));

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

    /* Manifest 2 */
    const char manifest2[] =
    "#EXTM3U\n"
    "#EXT-X-MEDIA-SEQUENCE:10\n"
    "#EXTINF:8\n"
    "foobar.ts\n"
    "#EXTINF:5\n"
    "foobar2.ts\n"
    "#EXTINF:8\n"
    "foobar3.ts\n"
    "#EXTINF:5\n"
    "foobar4.ts\n"
    "#EXTINF:8\n"
    "foobar5.ts\n";

    m3u = ParseM3U8(obj, manifest2, sizeof(manifest2));
    try
    {
        Expect(m3u);
        Expect(m3u->isLive() == true);
        BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->
                                  getRepresentations().front();
        uint64_t number;
        Expect(rep->getSegmentNumberByTime(vlc_tick_from_sec(2), &number));
        Expect(number == 10);
        Expect(rep->getSegmentNumberByTime(vlc_tick_from_sec(8), &number));
        Expect(number == 11);
        Expect(rep->getSegmentNumberByTime(vlc_tick_from_sec(100), &number));
        Expect(number == 14);
        Expect(bufferingLogic.getStartSegmentNumber(rep) < 13);

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

    /* Manifest 3 */
    const char manifest3[] =
    "#EXTM3U\n"
    "#EXT-X-MEDIA-SEQUENCE:10\n"
    "#EXT-X-PROGRAM-DATE-TIME:1970-01-01T00:00:10.000+00:00\n"
    "#EXTINF:8\n"
    "foobar.ts\n"
    "#EXTINF:5\n"
    "foobar2.ts\n"
    "#EXTINF:8\n"
    "foobar3.ts\n"
    "#EXT-X-DISCONTINUITY\n"
    "#EXT-X-PROGRAM-DATE-TIME:1970-01-01T02:00:00.000+00:00\n"
    "#EXT-X-MEDIA-SEQUENCE:20\n"
    "#EXTINF:5\n"
    "foobar4.ts\n"
    "#EXTINF:8\n"
    "foobar5.ts\n";

    m3u = ParseM3U8(obj, manifest3, sizeof(manifest3));
    try
    {
        Expect(m3u);
        BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->
                                  getRepresentations().front();
        /* media sequence and discontinuity handling */
        uint64_t number;
        bool discont;
        Segment *seg = rep->getNextMediaSegment(13, &number, &discont);
        Expect(seg);
        Expect(number == 20);
        Expect(discont);

        /* mapping past discontinuity */
        Expect(rep->getSegmentNumberByTime(vlc_tick_from_sec(23), &number));
        Expect(number == 20);

        /* date set and incremented */
        seg = rep->getMediaSegment(10);
        Expect(seg);
        Expect(static_cast<HLSSegment *>(seg)->getDisplayTime() == VLC_TICK_0 + vlc_tick_from_sec(10));
        seg = rep->getMediaSegment(11);
        Expect(seg);
        Expect(static_cast<HLSSegment *>(seg)->getDisplayTime() == VLC_TICK_0 + vlc_tick_from_sec(10 + 8));

        /* date change after discontinuity */
        seg = rep->getMediaSegment(20);
        Expect(seg);
        Expect(static_cast<HLSSegment *>(seg)->getDisplayTime() == VLC_TICK_0 + vlc_tick_from_sec(7200));

        vlc_tick_t begin, end, duration;
        Expect(rep->getMediaPlaybackRange(&begin, &end, &duration));
        Expect(begin == vlc_tick_from_sec(0));
        Expect(end == vlc_tick_from_sec(34));
        Expect(duration == vlc_tick_from_sec(34));

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

    /* Manifest 4 */
    const char manifest4[] =
    "#EXTM3U\n"
    "#EXT-X-MEDIA-SEQUENCE:10\n"
    "#EXT-X-START:TIME-OFFSET=-11.5,PRECISE=NO\n"
    "#EXTINF:10\n"
    "foobar.ts\n"
    "#EXTINF:10\n"
    "foobar.ts\n"
    "#EXTINF:10\n"
    "foobar.ts\n"
    "#EXTINF:10\n"
    "foobar.ts\n"
    "#EXTINF:10\n"
    "foobar.ts\n"
    "#EXT-X-ENDLIST\n";

    m3u = ParseM3U8(obj, manifest4, sizeof(manifest4));
    try
    {
        Expect(m3u);
        Expect(m3u->isLive() == false);
        Expect(m3u->presentationStartOffset == vlc_tick_from_sec(50 - 11.5));
        BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->
                                  getRepresentations().front();
        Expect(bufferingLogic.getStartSegmentNumber(rep) == 13);
        m3u->presentationStartOffset = vlc_tick_from_sec(11.5);
        Expect(bufferingLogic.getStartSegmentNumber(rep) == 11);

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

    /* Manifest 5 */
    const char manifest5[] =
    "#EXTM3U\n"
    "#EXT-X-MEDIA-SEQUENCE:10\n"
    "#EXTINF:1\n"
    "foobar.ts\n"
    "#EXTINF:1\n"
    "foobar.ts\n"
    "#EXTINF:1\n"
    "foobar.ts\n"
    "#EXTINF:1\n"
    "foobar.ts\n"
    "#EXTINF:1\n"
    "foobar.ts\n";

    m3u = ParseM3U8(obj, manifest5, sizeof(manifest5));
    try
    {
        bufferingLogic = DefaultBufferingLogic();
        bufferingLogic.setLowDelay(true);
        Expect(m3u);
        Expect(m3u->isLive() == true);
        BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->
                                  getRepresentations().front();
        Expect(bufferingLogic.getStartSegmentNumber(rep) ==
               (UINT64_C(14) - SEC_FROM_VLC_TICK(DefaultBufferingLogic::BUFFERING_LOWEST_LIMIT)));

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


    /* Manifest 6 */
    const char manifest6[] =
        "#EXTM3U\n"
        "#EXT-X-MEDIA-SEQUENCE:10\n"
        "#EXTINF:1\n"
        "#EXT-X-BYTERANGE:1000@0\n"
        "foobar.ts\n"
        "#EXT-X-BYTERANGE:4000@2000\n"
        "foobar.ts\n"
        "#EXT-X-BYTERANGE:500\n"
        "foobar.ts\n"
        "#EXT-X-BYTERANGE:1000@0\n"
        "foobar.ts\n";

    m3u = ParseM3U8(obj, manifest6, sizeof(manifest6));
    try
    {
        Expect(m3u);
        BaseRepresentation *rep = m3u->getFirstPeriod()->getAdaptationSets().front()->
                                  getRepresentations().front();
        Segment *seg = rep->getMediaSegment(10);
        Expect(seg);
        Expect(seg->getOffset() == 0);
        seg = rep->getMediaSegment(11);
        Expect(seg);
        Expect(seg->getOffset() == 2000);
        seg = rep->getMediaSegment(12);
        Expect(seg);
        Expect(seg->getOffset() == 6000);
        seg = rep->getMediaSegment(13);
        Expect(seg);
        Expect(seg->getOffset() == 0);
        delete m3u;
    }
    catch (...)
    {
        delete m3u;
        return 1;
    }


    return 0;
}

Messung
CHZG
839810093

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

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

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104857
#Domains=439030