Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/demux/adaptive/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 29 kB image not shown  

Quelle  Streams.cpp   Sprache: C

 

/*
 * Streams.cpp
 *****************************************************************************
 * Copyright (C) 2014 - 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 "Streams.hpp"
#include "logic/AbstractAdaptationLogic.h"
#include "http/HTTPConnection.hpp"
#include "http/HTTPConnectionManager.h"
#include "playlist/BaseAdaptationSet.h"
#include "playlist/BaseRepresentation.h"
#include "playlist/SegmentChunk.hpp"
#include "plumbing/SourceStream.hpp"
#include "plumbing/CommandsQueue.hpp"
#include "tools/Debug.hpp"
#include <vlc_demux.h>

#include <algorithm>

using namespace adaptive;
using namespace adaptive::http;

AbstractStream::AbstractStream(demux_t * demux_)
{
    p_realdemux = demux_;
    format = StreamFormat::Type::Unknown;
    currentChunk = nullptr;
    eof = false;
    valid = true;
    disabled = false;
    contiguous = true;
    segmentgap = false;
    discontinuity = false;
    needrestart = false;
    inrestart = false;
    demuxfirstchunk = false;
    segmentTracker = nullptr;
    demuxersource = nullptr;
    demuxer = nullptr;
    fakeesout = nullptr;
    notfound_sequence = 0;
    mightalwaysstartfromzero = false;
    last_buffer_status = BufferingStatus::Lessthanmin;
    currentrep.width = 0;
    currentrep.height = 0;
    vlc_mutex_init(&lock);
}

bool AbstractStream::init(const StreamFormat &format_, SegmentTracker *tracker)
{
    /* Don't even try if not supported or already init */
    if(format_ == StreamFormat::Type::Unsupported || demuxersource)
        return false;

    demuxersource = new (std::nothrow) BufferedChunksSourceStream( VLC_OBJECT(p_realdemux), this );
    if(demuxersource)
    {
        CommandsFactory *factory = new (std::nothrow) CommandsFactory();
        AbstractCommandsQueue *commandsqueue = new (std::nothrow) CommandsQueue();
        if(factory && commandsqueue)
        {
            fakeesout = new (std::nothrow) FakeESOut(p_realdemux->out,
                                                     commandsqueue, factory);
            if(fakeesout)
            {
                /* All successful */
                fakeesout->setExtraInfoProvider( this );
                const Role & streamRole = tracker->getStreamRole();
                if(streamRole.isDefault() && streamRole.autoSelectable())
                    fakeesout->setPriority(ES_PRIORITY_MIN + 10);
                else if(!streamRole.autoSelectable())
                    fakeesout->setPriority(ES_PRIORITY_NOT_DEFAULTABLE);
                format = format_;
                segmentTracker = tracker;
                segmentTracker->registerListener(this);
                segmentTracker->notifyBufferingState(true);
                if(mightalwaysstartfromzero)
                    fakeesout->setExpectedTimestamp(VLC_TICK_0 + segmentTracker->getPlaybackTime());
                declaredCodecs();
                return true;
            }
        }
        delete factory;
        delete commandsqueue;
        delete demuxersource;
    }

    return false;
}

AbstractStream::~AbstractStream()
{
    delete currentChunk;
    if(segmentTracker)
        segmentTracker->notifyBufferingState(false);
    delete segmentTracker;

    delete demuxer;
    delete demuxersource;
    delete fakeesout;
}

void AbstractStream::prepareRestart(bool b_discontinuity)
{
    if(demuxer)
    {
        /* Enqueue Del Commands for all current ES */
        demuxer->drain();
        fakeEsOut()->resetTimestamps();
        /* Enqueue Del Commands for all current ES */
        fakeEsOut()->scheduleAllForDeletion();
        if(b_discontinuity)
            fakeEsOut()->schedulePCRReset();
        fakeEsOut()->commandsQueue()->Commit();
        /* ignoring demuxer's own Del commands */
        fakeEsOut()->commandsQueue()->setDrop(true);
        delete demuxer;
        fakeEsOut()->commandsQueue()->setDrop(false);
        demuxer = nullptr;
    }
}

bool AbstractStream::resetForNewPosition(vlc_tick_t seekMediaTime)
{
    // clear eof flag before restartDemux() to prevent readNextBlock() fail
    eof = false;
    demuxfirstchunk = true;
    notfound_sequence = 0;
    last_buffer_status = BufferingStatus::Lessthanmin;
    inrestart = false;
    needrestart = false;
    discontinuity = false;
    if(!demuxer || demuxer->needsRestartOnSeek()) /* needs (re)start */
    {
        delete currentChunk;
        currentChunk = nullptr;
        needrestart = false;
        segmentgap = false;

        fakeEsOut()->resetTimestamps();

        fakeEsOut()->commandsQueue()->Abort( true );
        startTimeContext = SegmentTimes();
        currentTimeContext = SegmentTimes();
        prevEndTimeContext = SegmentTimes();
        currentChunk = getNextChunk();
        if(mightalwaysstartfromzero)
            fakeEsOut()->setExpectedTimestamp(VLC_TICK_0 + seekMediaTime);
        if( !restartDemux() )
        {
            msg_Info(p_realdemux, "Restart demux failed");
            eof = true;
            valid = false;
            return false;
        }
        else
        {
            fakeEsOut()->commandsQueue()->setEOF(false);
        }
    }
    else fakeEsOut()->commandsQueue()->Abort( true );
    return true;
}

void AbstractStream::setLanguage(const std::string &lang)
{
    language = lang;
}

void AbstractStream::setDescription(const std::string &desc)
{
    description = desc;
}

vlc_tick_t AbstractStream::getMinAheadTime() const
{
    if(!segmentTracker)
        return 0;
    return segmentTracker->getMinAheadTime();
}

Times AbstractStream::getFirstTimes() const
{
    vlc_mutex_locker locker(&lock);

    if(!valid || disabled)
        return Times();

    Times times = fakeEsOut()->commandsQueue()->getFirstTimes();
    if(times.continuous == VLC_TICK_INVALID)
        times = fakeEsOut()->commandsQueue()->getPCR();
    return times;
}

int AbstractStream::esCount() const
{
    return fakeEsOut()->esCount();
}

bool AbstractStream::seekAble() const
{
    bool restarting = fakeEsOut()->restarting();
    bool draining = fakeEsOut()->commandsQueue()->isDraining();
    bool eof = fakeEsOut()->commandsQueue()->isEOF();

    msg_Dbg(p_realdemux, "demuxer %p, fakeesout restarting %d, "
            "discontinuity %d, commandsqueue draining %d, commandsqueue eof %d",
            static_cast<void *>(demuxer), restarting, discontinuity, draining, eof);

    if(!valid || restarting || discontinuity || (!eof && draining))
    {
        msg_Warn(p_realdemux, "not seekable");
        return false;
    }
    else
    {
        return true;
    }
}

bool AbstractStream::isSelected() const
{
    return fakeEsOut()->hasSelectedEs();
}

AbstractStream::StreamPosition::StreamPosition()
{
    number = std::numeric_limits<uint64_t>::max();
    pos = -1;
}

bool AbstractStream::reactivate(const StreamPosition &pos)
{
    vlc_mutex_locker locker(&lock);
    if(setPosition(pos, false))
    {
        setDisabled(false);
        return true;
    }
    else
    {
        eof = true; /* can't reactivate */
        return false;
    }
}

bool AbstractStream::startDemux()
{
    if(demuxer)
        return false;

    if(!currentChunk)
    {
        segmentgap = false;
        currentChunk = getNextChunk();
        needrestart = false;
        discontinuity = false;
    }

    demuxersource->Reset();
    demuxfirstchunk = true;
    fakeEsOut()->setPCRTrusted(format != StreamFormat::Type::MPEG2TS);
    demuxer = createDemux(format);
    if(!demuxer && format != StreamFormat())
        msg_Err(p_realdemux, "Failed to create demuxer %p %s", (void *)demuxer,
                format.str().c_str());

    return !!demuxer;
}

bool AbstractStream::restartDemux()
{
    bool b_ret = true;
    if(!demuxer)
    {
        fakeesout->recycleAll();
        b_ret = startDemux();
    }
    else if(demuxer->needsRestartOnSeek())
    {
        inrestart = true;
        /* Push all ES as recycling candidates */
        fakeEsOut()->recycleAll();
        /* Restart with ignoring es_Del pushes to queue when terminating demux */
        fakeEsOut()->commandsQueue()->setDrop(true);
        demuxer->destroy();
        fakeEsOut()->commandsQueue()->setDrop(false);
        b_ret = demuxer->create();
        inrestart = false;
    }
    else
    {
        fakeEsOut()->commandsQueue()->Commit();
    }
    return b_ret;
}

void AbstractStream::setDisabled(bool b)
{
    if(disabled != b)
        segmentTracker->notifyBufferingState(!b);
    disabled = b;
}

bool AbstractStream::isValid() const
{
    vlc_mutex_locker locker(&lock);
    return valid;
}

bool AbstractStream::isDisabled() const
{
    vlc_mutex_locker locker(&lock);
    return disabled;
}

void AbstractStream::setLivePause(bool b)
{
    vlc_mutex_locker locker(&lock);
    if(!b)
    {
        segmentTracker->setPosition(segmentTracker->getStartPosition(),
                                    !demuxer || demuxer->needsRestartOnSeek());
    }
}

vlc_tick_t AbstractStream::getDemuxedAmount(Times from) const
{
    vlc_tick_t i_demuxed = fakeEsOut()->commandsQueue()->getDemuxedAmount(from).continuous;
    if(contiguous)
    {
        vlc_tick_t i_media_demuxed = fakeEsOut()->commandsQueue()->getDemuxedMediaAmount(from).segment.media;
        if(i_media_demuxed > i_demuxed)
            i_demuxed = i_media_demuxed;
    }
    return i_demuxed;
}

bool AbstractStream::isBufferingSufficient(Times from, vlc_tick_t minimum) const
{
    vlc_mutex_locker locker(&lock);

    if(!valid || disabled || fakeEsOut()->commandsQueue()->isEOF())
        return true;

    return getDemuxedAmount(from) >= minimum;
}

AbstractStream::BufferingStatus
AbstractStream::getBufferAndStatus(const Times &deadline,
                                   vlc_tick_t i_min_buffering,
                                   vlc_tick_t i_max_buffering,
                                   vlc_tick_t *pi_demuxed)
{
    if(last_buffer_status == BufferingStatus::End)
        return BufferingStatus::End;
    *pi_demuxed = getDemuxedAmount(deadline);

    if(*pi_demuxed < i_max_buffering) /* need to read more */
    {
        if(*pi_demuxed < i_min_buffering)
            return BufferingStatus::Lessthanmin; /* high prio */
        return BufferingStatus::Ongoing;
    }

    return BufferingStatus::Full;
}

AbstractStream::BufferingStatus AbstractStream::bufferize(Times deadline,
                                                           vlc_tick_t i_min_buffering,
                                                           vlc_tick_t i_extra_buffering,
                                                           vlc_tick_t i_target_buffering,
                                                           bool b_keep_alive)
{
    last_buffer_status = doBufferize(deadline, i_min_buffering, i_extra_buffering,
                                     i_target_buffering, b_keep_alive);
    return last_buffer_status;
}

AbstractStream::BufferingStatus AbstractStream::doBufferize(Times deadline,
                                                             vlc_tick_t i_min_buffering,
                                                             vlc_tick_t i_max_buffering,
                                                             vlc_tick_t i_target_buffering,
                                                             bool b_keep_alive)
{
    vlc_mutex_lock(&lock);

    /* Ensure it is configured */
    if(!segmentTracker || !valid)
    {
        vlc_mutex_unlock(&lock);
        return BufferingStatus::End;
    }

    /* Disable streams that are not selected (alternate streams) */
    if(esCount() && !isSelected() && !fakeEsOut()->restarting() && !b_keep_alive)
    {
        setDisabled(true);
        segmentTracker->reset();
        fakeEsOut()->commandsQueue()->Abort(false);
        msg_Dbg(p_realdemux, "deactivating %s stream %s",
                format.str().c_str(), description.c_str());
        vlc_mutex_unlock(&lock);
        return BufferingStatus::End;
    }

    if(fakeEsOut()->commandsQueue()->isDraining())
    {
        vlc_mutex_unlock(&lock);
        return BufferingStatus::Suspended;
    }

    segmentTracker->setStartPosition();

    /* Reached end of live playlist */
    if(!segmentTracker->bufferingAvailable())
    {
        vlc_mutex_unlock(&lock);
        return BufferingStatus::Suspended;
    }

    if(!contiguous)
    {
        if(!fakeEsOut()->hasSynchronizationReference())
        {
            if(!demuxer)
            {
                /* We always need a prepared chunk info for querying a syncref */
                if(!currentChunk)
                {
                    currentChunk = getNextChunk();
                    if(!currentChunk)
                    {
                        vlc_mutex_unlock(&lock);
                        return BufferingStatus::End;
                    }
                    segmentgap = false;
                    needrestart = false;
                    discontinuity = false;
                }
            }
            SynchronizationReference r;
            if(segmentTracker->getSynchronizationReference(currentSequence, startTimeContext.media, r))
            {
                fakeEsOut()->setSynchronizationReference(r);
            }
            else
            {
                msg_Dbg(p_realdemux, "Waiting sync reference for seq %" PRIu64, currentSequence);
                vlc_mutex_unlock(&lock);
                return BufferingStatus::Suspended;
            }
        }
    }

    if(!demuxer)
    {
        if(!startDemux())
        {
            valid = false; /* Prevent further retries */
            fakeEsOut()->commandsQueue()->setEOF(true);
            vlc_mutex_unlock(&lock);
            return BufferingStatus::End;
        }
    }

    vlc_tick_t i_demuxed = fakeEsOut()->commandsQueue()->getDemuxedAmount(deadline).continuous;
    if(!contiguous && prevEndTimeContext.media != VLC_TICK_INVALID
       && deadline.segment.media != VLC_TICK_INVALID)
    {
        vlc_tick_t i_mediaamount = fakeEsOut()->commandsQueue()->getDemuxedMediaAmount(deadline).segment.media;
        if(i_mediaamount > i_demuxed)
            i_demuxed = i_mediaamount;
    }

    segmentTracker->notifyBufferingLevel(i_min_buffering, i_max_buffering, i_demuxed, i_target_buffering);
    if(i_demuxed < i_max_buffering) /* not already demuxed */
    {
        Times extdeadline = fakeEsOut()->commandsQueue()->getBufferingLevel();
        extdeadline.offsetBy((i_max_buffering - i_demuxed) / 4);

        Times newdeadline = deadline;
        newdeadline.offsetBy(VLC_TICK_FROM_SEC(1));

        if(extdeadline.continuous < newdeadline.continuous)
            deadline = extdeadline;
        else
            deadline = newdeadline;

        /* need to read, demuxer still buffering, ... */
        vlc_mutex_unlock(&lock);
        Demuxer::Status demuxStatus = demuxer->demux(deadline.continuous);
        fakeEsOut()->scheduleNecessaryMilestone();
        vlc_mutex_lock(&lock);
        if(demuxStatus != Demuxer::Status::Success)
        {
            if(discontinuity || needrestart)
            {
                msg_Dbg(p_realdemux, "Restarting demuxer %d %d", needrestart, discontinuity);
                prepareRestart(discontinuity);
                if(discontinuity)
                {
                    msg_Dbg(p_realdemux, "Draining on discontinuity");
                    fakeEsOut()->commandsQueue()->setDraining();
                    fakeEsOut()->setSegmentStartTimes(startTimeContext);
                    assert(startTimeContext.media);
                }
                assert(startTimeContext.media);
                if(!fakeEsOut()->hasSegmentStartTimes())
                    fakeEsOut()->setSegmentStartTimes(startTimeContext);
                if(!fakeEsOut()->hasSynchronizationReference())
                {
                    SynchronizationReference r(currentSequence, Times());
                    fakeEsOut()->setSynchronizationReference(r);
                }
                discontinuity = false;
                needrestart = false;
                vlc_mutex_unlock(&lock);
                return BufferingStatus::Ongoing;
            }
            fakeEsOut()->commandsQueue()->setEOF(true);
            vlc_mutex_unlock(&lock);
            return BufferingStatus::End;
        }

        if(deadline.continuous != VLC_TICK_INVALID)
        {
            i_demuxed = fakeEsOut()->commandsQueue()->getDemuxedAmount(deadline).continuous;
            segmentTracker->notifyBufferingLevel(i_min_buffering, i_max_buffering, i_demuxed, i_target_buffering);
        }
        else
        {
            /* On initial pass, there's no demux time known, we need to fake it */
            if(fakeEsOut()->commandsQueue()->getBufferingLevel().continuous != VLC_TICK_INVALID)
                i_demuxed = i_min_buffering;
        }
    }
    vlc_mutex_unlock(&lock);

    Times first = fakeEsOut()->commandsQueue()->getFirstTimes();
    if(contiguous && first.continuous != VLC_TICK_INVALID && first.segment.demux != VLC_TICK_INVALID)
        segmentTracker->updateSynchronizationReference(currentSequence, first);

    if(i_demuxed < i_max_buffering) /* need to read more */
    {
        if(i_demuxed < i_min_buffering)
            return BufferingStatus::Lessthanmin; /* high prio */
        return BufferingStatus::Ongoing;
    }
    return BufferingStatus::Full;
}

AbstractStream::Status AbstractStream::dequeue(Times deadline, Times *times)
{
    vlc_mutex_locker locker(&lock);

    if(fakeEsOut()->commandsQueue()->isDraining())
    {
        AdvDebug(vlc_tick_t pcrvalue = fakeEsOut()->commandsQueue()->getPCR().continuous;
                 vlc_tick_t dtsvalue = fakeEsOut()->commandsQueue()->getFirstTimes().continuous;
                 vlc_tick_t bufferingLevel = fakeEsOut()->commandsQueue()->getBufferingLevel().continuous;
                 msg_Dbg(p_realdemux, "Stream pcr %" PRId64 " dts %" PRId64 " deadline %" PRId64 " buflevel %" PRId64 "(+%" PRId64 ") [DRAINING] :%s",
                         pcrvalue, dtsvalue, deadline.continuous, bufferingLevel,
                         pcrvalue ? bufferingLevel - pcrvalue : 0,
                         description.c_str()));

        *times = fakeEsOut()->commandsQueue()->Process(deadline);
        if(!fakeEsOut()->commandsQueue()->isEmpty())
            return Status::Demuxed;

        if(!fakeEsOut()->commandsQueue()->isEOF())
        {
            fakeEsOut()->commandsQueue()->Abort(true); /* reset buffering level and flags */
            return Status::Discontinuity;
        }
    }

    if(!valid || disabled || fakeEsOut()->commandsQueue()->isEOF())
    {
        *times = deadline;
        return Status::Eof;
    }

    vlc_tick_t bufferingLevel = fakeEsOut()->commandsQueue()->getBufferingLevel().continuous;
    AdvDebug(vlc_tick_t pcrvalue = fakeEsOut()->commandsQueue()->getPCR().continuous;
             vlc_tick_t dtsvalue = fakeEsOut()->commandsQueue()->getFirstTimes().continuous;
             msg_Dbg(p_realdemux, "Stream pcr %" PRId64 " dts %" PRId64 " deadline %" PRId64 " buflevel %" PRId64 "(+%" PRId64 "): %s",
                     pcrvalue, dtsvalue, deadline.continuous, bufferingLevel,
                     pcrvalue ? bufferingLevel - pcrvalue : 0,
                     description.c_str()));

    if(deadline.continuous <= bufferingLevel) /* demuxed */
    {
        *times = fakeEsOut()->commandsQueue()->Process(deadline);
        return Status::Demuxed;
    }
    else if(!contiguous &&
            fakeEsOut()->commandsQueue()->getDemuxedMediaAmount(deadline).segment.media > 0)
    {
        *times = deadline;
        fakeEsOut()->commandsQueue()->Process(Times()); /* handle untimed events (es add) */
        return Status::Demuxed;
    }

    return Status::Buffering;
}

ChunkInterface * AbstractStream::getNextChunk() const
{
    const bool b_restarting = fakeEsOut()->restarting();
    ChunkInterface *ck = segmentTracker->getNextChunk(!b_restarting);

    if(ck && !fakeEsOut()->hasSegmentStartTimes())
        fakeEsOut()->setSegmentStartTimes(startTimeContext);

    if(ck && !fakeEsOut()->hasSynchronizationReference())
    {
        if(!fakeEsOut()->hasSegmentStartTimes())
            return ck;
        assert(fakeEsOut()->hasSegmentStartTimes());
        SynchronizationReference r;
        if(segmentTracker->getSynchronizationReference(currentSequence, startTimeContext.media, r))
            fakeEsOut()->setSynchronizationReference(r);
    }
    return ck;
}

block_t * AbstractStream::readNextBlock()
{
    if (currentChunk == nullptr && !eof)
    {
        segmentgap = false;
        currentChunk = getNextChunk();
    }

    if(demuxfirstchunk)
    {
        /* clear up discontinuity on demux start (discontinuity on start segment bug) */
        discontinuity = false;
        needrestart = false;
        fakeesout->setSrcID(nextSrcID);
    }
    else if(discontinuity || needrestart)
    {
        msg_Info(p_realdemux, "Ending demuxer stream. %s%s",
                 discontinuity ? "[discontinuity]" : "",
                 needrestart ? "[needrestart]" : "");
        /* Force stream/demuxer to end for this call */
        return nullptr;
    }

    if(currentChunk == nullptr)
    {
        eof = true;
        return nullptr;
    }

    const bool b_segment_head_chunk = (currentChunk->getBytesRead() == 0);

    block_t *block = currentChunk->readBlock();
    if(block == nullptr)
    {
        if(currentChunk->getRequestStatus() == RequestStatus::NotFound &&
           ++notfound_sequence < 3)
        {
            segmentgap = true;
        }
        delete currentChunk;
        currentChunk = nullptr;
        return nullptr;
    }
    else notfound_sequence = 0;

    demuxfirstchunk = false;

    if (!currentChunk->hasMoreData())
    {
        delete currentChunk;
        currentChunk = nullptr;
    }

    block = checkBlock(block, b_segment_head_chunk);

    return block;
}

bool AbstractStream::setPosition(const StreamPosition &pos, bool tryonly)
{
    if(!seekAble())
        return false;

    bool b_needs_restart = demuxer ? demuxer->needsRestartOnSeek() : true;
    bool ret = segmentTracker->setPositionByTime(pos.times.segment.media,
                                                 b_needs_restart, tryonly);
    if(!tryonly && ret)
    {
// in some cases, media time seek != sent dts
//        es_out_Control(p_realdemux->out, ES_OUT_SET_NEXT_DISPLAY_TIME,
//                       VLC_TICK_0 + time);
    }
    return ret;
}

bool AbstractStream::getMediaPlaybackTimes(vlc_tick_t *start, vlc_tick_t *end,
                                           vlc_tick_t *length) const
{
    return segmentTracker->getMediaPlaybackRange(start, end, length);
}

bool AbstractStream::getMediaAdvanceAmount(vlc_tick_t *duration) const
{
    if(startTimeContext.media == VLC_TICK_INVALID)
        return false;
    *duration = currentTimeContext.media - startTimeContext.media;
    return true;
}

bool AbstractStream::runUpdates(bool)
{
    if(!valid)
        return false;

    if(!disabled)
        return segmentTracker->updateSelected();
    else
        return false;
}

void AbstractStream::fillExtraFMTInfo( es_format_t *p_fmt ) const
{
    if(!p_fmt->psz_language && !language.empty())
        p_fmt->psz_language = strdup(language.c_str());
    if(!p_fmt->psz_description && !description.empty())
        p_fmt->psz_description = strdup(description.c_str());
    if( p_fmt->i_cat == VIDEO_ES && p_fmt->video.i_visible_width == 0)
    {
        p_fmt->video.i_visible_width = currentrep.width;
        p_fmt->video.i_visible_height = currentrep.height;
    }
}

block_t *AbstractStream::checkBlock(block_t *p_block, bool)
{
    return p_block;
}

AbstractDemuxer * AbstractStream::createDemux(const StreamFormat &format)
{
    AbstractDemuxer *ret = newDemux( VLC_OBJECT(p_realdemux), format,
                                     (es_out_t *)fakeEsOut(), demuxersource );
    if(ret && !ret->create())
    {
        delete ret;
        ret = nullptr;
    }
    else fakeEsOut()->commandsQueue()->Commit();

    return ret;
}

AbstractDemuxer *AbstractStream::newDemux(vlc_object_t *p_obj, const StreamFormat &format,
                                          es_out_t *out, AbstractSourceStream *source) const
{
    AbstractDemuxer *ret = nullptr;
    switch(format)
    {
        case StreamFormat::Type::MP4:
            ret = new Demuxer(p_obj, "mp4", out, source);
            break;

        case StreamFormat::Type::MPEG2TS:
            ret = new Demuxer(p_obj, "ts", out, source);
            break;

        default:
        case StreamFormat::Type::Unsupported:
            break;
    }
    return ret;
}

void AbstractStream::trackerEvent(const TrackerEvent &ev)
{
    switch(ev.getType())
    {
        case TrackerEvent::Type::Discontinuity:
        {
            const DiscontinuityEvent &event =
                    static_cast<const DiscontinuityEvent &>(ev);
            discontinuity = true;
            currentSequence = event.discontinuitySequenceNumber;
            nextSrcID = SrcID::make();
        }
            break;

        case TrackerEvent::Type::SegmentGap:
            segmentgap = true;
            prevEndTimeContext = SegmentTimes();
            currentTimeContext = SegmentTimes(); /* fired before segmentchanged */
            break;

        case TrackerEvent::Type::FormatChange:
        {
            const FormatChangedEvent &event =
                    static_cast<const FormatChangedEvent &>(ev);
            /* Check if our current demux is still valid */
            if(*event.format != format)
            {
                /* Format has changed between segments, we need to drain and change demux */
                msg_Info(p_realdemux, "Changing stream format %s -> %s",
                         format.str().c_str(), event.format->str().c_str());
                format = *event.format;
                needrestart = true;
            }
        }
            break;

        case TrackerEvent::Type::RepresentationSwitch:
        {
            const RepresentationSwitchEvent &event =
                    static_cast<const RepresentationSwitchEvent &>(ev);
            if(demuxer && !inrestart && event.prev)
            {
                if(!demuxer->bitstreamSwitchCompatible() ||
                   /* HLS variants can move from TS to Raw AAC */
                   format == StreamFormat(StreamFormat::Type::Unknown) ||
                   (event.next &&
                   !event.next->getAdaptationSet()->isBitSwitchable()))
                    needrestart = true;
            }
            AdvDebug(msg_Dbg(p_realdemux, "Stream %s switching %s %s to %s %s",
                    description.c_str(),
                    event.prev ? event.prev->getID().str().c_str() : "",
                    event.prev ? event.prev->getStreamFormat().str().c_str() : "",
                    event.next ? event.next->getID().str().c_str() : "",
                    event.next ? event.next->getStreamFormat().str().c_str() : ""));
            if(event.next)
            {
                nextSrcID = SrcID::make();
                currentrep.width = event.next->getWidth() > 0 ? event.next->getWidth() : 0;
                currentrep.height = event.next->getHeight() > 0 ? event.next->getHeight() : 0;
            }
            else
            {
                currentrep.width = 0;
                currentrep.height = 0;
            }
        }
            break;

        case TrackerEvent::Type::RepresentationUpdated:
        {
            if(last_buffer_status == BufferingStatus::Suspended)
                last_buffer_status = BufferingStatus::Lessthanmin;
        }
            break;

        case TrackerEvent::Type::RepresentationUpdateFailed:
        {
            fakeEsOut()->commandsQueue()->setEOF(true);
            msg_Err(p_realdemux, "Could not update %s anymore, disabling", description.c_str());
        }
            break;

        case TrackerEvent::Type::SegmentChange:
        {
            const SegmentChangedEvent &event =
                    static_cast<const SegmentChangedEvent &>(ev);
            if(demuxer && demuxer->needsRestartOnEachSegment() && !inrestart)
            {
                needrestart = true;
            }
            prevEndTimeContext = currentTimeContext;
            prevEndTimeContext.offsetBy(currentDuration);
            fakeEsOut()->setSegmentProgressTimes(prevEndTimeContext);
            currentTimeContext.media = event.starttime;
            currentTimeContext.display = event.displaytime;
            currentSequence = event.sequence;
            currentDuration = event.duration;
            if(startTimeContext.media == VLC_TICK_INVALID)
                startTimeContext = currentTimeContext;
        }
            break;

        case TrackerEvent::Type::PositionChange:
        {
            const PositionChangedEvent &event =
                    static_cast<const PositionChangedEvent &>(ev);
            resetForNewPosition(event.resumeTime);
        }
            break;

        default:
            break;
    }
}

void AbstractStream::declaredCodecs()
{
    CodecDescriptionList descs;
    segmentTracker->getCodecsDesc(&descs);
    for(auto it = descs.cbegin(); it != descs.cend(); ++it)
    {
        const es_format_t *fmt = (*it)->getFmt();
        if(fmt->i_cat != UNKNOWN_ES)
            fakeEsOut()->declareEs(fmt);
    }
}

FakeESOut::LockedFakeEsOut AbstractStream::fakeEsOut()
{
    return fakeesout->WithLock();
}

FakeESOut::LockedFakeEsOut AbstractStream::fakeEsOut() const
{
    return fakeesout->WithLock();
}

Messung
CHZG
849510093

¤ 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.