void SegmentList::pruneByPlaybackTime(mtime_t time) { uint64_t num; const Timescale timescale = inheritTimescale(); if(getSegmentNumberByScaledTime(timescale.ToScaled(time), &num)) pruneBySegmentNumber(num); }
void SegmentInformation::SplitUsingIndex(std::vector<SplitPoint> &splitlist) { std::vector<ISegment *> seglist; getSegments(INFOTYPE_MEDIA, seglist); size_t prevstart = 0; stime_t prevtime = 0; const Timescale timescale = inheritTimescale(); SplitPoint split = {0,0,0}; std::vector<SplitPoint>::const_iterator splitIt; for(splitIt = splitlist.begin(); splitIt < splitlist.end(); ++splitIt) { split = *splitIt; if(splitIt != splitlist.begin()) { /* do previous splitpoint */ const stime_t duration = timescale.ToScaled(split.duration); insertIntoSegment(seglist, prevstart, split.offset - 1, prevtime, duration); } prevstart = split.offset; prevtime = timescale.ToScaled(split.time); } if(splitlist.size() == 1) { const stime_t duration = timescale.ToScaled(split.duration); insertIntoSegment(seglist, prevstart, 0, prevtime, duration); } else if(splitlist.size() > 1) { const stime_t duration = timescale.ToScaled(split.duration); insertIntoSegment(seglist, prevstart, split.offset - 1, prevtime, duration); } }
void MediaSegmentTemplate::mergeWith(MediaSegmentTemplate *updated, vlc_tick_t prunebarrier) { SegmentTimeline *timeline = segmentTimeline.Get(); if(timeline && updated->segmentTimeline.Get()) { timeline->mergeWith(*updated->segmentTimeline.Get()); if(prunebarrier) { const Timescale timescale = timeline->inheritTimescale(); const uint64_t number = timeline->getElementNumberByScaledPlaybackTime(timescale.ToScaled(prunebarrier)); timeline->pruneBySequenceNumber(number); } } }
uint64_t MediaSegmentTemplate::getCurrentLiveTemplateNumber() const { uint64_t number = startNumber.Get(); /* live streams / templated */ const stime_t dur = duration.Get(); if(dur) { /* compute, based on current time */ const time_t playbacktime = time(NULL); const Timescale timescale = inheritTimescale(); time_t streamstart = parentSegmentInformation->getPlaylist()->availabilityStartTime.Get(); streamstart += parentSegmentInformation->getPeriodStart(); stime_t elapsed = timescale.ToScaled(vlc_tick_from_sec(playbacktime - streamstart)); number += elapsed / dur; } return number; }
bool SegmentList::getPlaybackTimeDurationBySegmentNumber(uint64_t number, vlc_tick_t *time, vlc_tick_t *dur) const { *time = *dur = VLC_TICK_INVALID; if(segments.empty()) return false; const Timescale timescale = inheritTimescale(); const ISegment *first = segments.front(); if(first->getSequenceNumber() > number) return false; bool found = false; stime_t seg_start = first->startTime.Get(); stime_t seg_dura = 0; std::vector<ISegment *>::const_iterator it = segments.begin(); for(it = segments.begin(); it != segments.end(); ++it) { const ISegment *seg = *it; if(seg->duration.Get()) seg_dura = seg->duration.Get(); else seg_dura = duration.Get(); /* Assuming there won't be any discontinuity in sequence */ if(seg->getSequenceNumber() == number) { found = true; break; } seg_start += seg_dura; } if(!found) return false; *time = VLC_TICK_0 + timescale.ToTime(seg_start); *dur = VLC_TICK_0 + timescale.ToTime(seg_dura); return true; }
bool SegmentList::getPlaybackTimeDurationBySegmentNumber(uint64_t number, mtime_t *time, mtime_t *dur) const { *time = *dur = VLC_TS_INVALID; if(segments.empty()) return false; const Timescale timescale = inheritTimescale(); const ISegment *first = segments.front(); if(first->getSequenceNumber() > number) return false; *time = first->startTime.Get(); std::vector<ISegment *>::const_iterator it = segments.begin(); for(it = segments.begin(); it != segments.end(); ++it) { const ISegment *seg = *it; /* Assuming there won't be any discontinuity in sequence */ if(seg->getSequenceNumber() == number) { break; } else if(seg->duration.Get()) { *time += seg->duration.Get(); *dur = seg->duration.Get(); } else { *time += duration.Get(); *dur = duration.Get(); } } *time = VLC_TS_0 + timescale.ToTime( *time ); *dur = VLC_TS_0 + timescale.ToTime( *dur ); return true; }
bool SegmentInformation::getSegmentNumberByTime(mtime_t time, uint64_t *ret) const { if( mediaSegmentTemplate ) { const Timescale timescale = mediaSegmentTemplate->inheritTimescale(); SegmentTimeline *timeline = mediaSegmentTemplate->segmentTimeline.Get(); if(timeline) { time = timescale.ToScaled(time); *ret = timeline->getElementNumberByScaledPlaybackTime(time); return true; } const stime_t duration = mediaSegmentTemplate->duration.Get(); *ret = mediaSegmentTemplate->startNumber.Get(); if(duration) { *ret += timescale.ToScaled(time) / duration; return true; } } else if ( segmentList && !segmentList->getSegments().empty() ) { const Timescale timescale = segmentList->inheritTimescale(); time = timescale.ToScaled(time); return segmentList->getSegmentNumberByScaledTime(time, ret); } else if( segmentBase ) { const Timescale timescale = inheritTimescale(); time = timescale.ToScaled(time); *ret = 0; const std::vector<ISegment *> list = segmentBase->subSegments(); return SegmentInfoCommon::getSegmentNumberByScaledTime(list, time, ret); } if(parent) return parent->getSegmentNumberByTime(time, ret); else return false; }
bool SegmentInformation::getPlaybackTimeDurationBySegmentNumber(uint64_t number, mtime_t *time, mtime_t *duration) const { SegmentList *segList; MediaSegmentTemplate *mediaTemplate; if( (mediaTemplate = inheritSegmentTemplate()) ) { const Timescale timescale = mediaTemplate->inheritTimescale(); stime_t stime, sduration; if(mediaTemplate->segmentTimeline.Get()) { mediaTemplate->segmentTimeline.Get()-> getScaledPlaybackTimeDurationBySegmentNumber(number, &stime, &sduration); } else { stime = number * mediaTemplate->duration.Get(); sduration = mediaTemplate->duration.Get(); } *time = timescale.ToTime(stime); *duration = timescale.ToTime(sduration); return true; } else if ( (segList = inheritSegmentList()) ) { return segList->getPlaybackTimeDurationBySegmentNumber(number, time, duration); } else { const Timescale timescale = inheritTimescale(); const ISegment *segment = getSegment(SegmentInfoType::INFOTYPE_MEDIA, number); if( segment ) { *time = timescale.ToTime(segment->startTime.Get()); *duration = timescale.ToTime(segment->duration.Get()); return true; } } return false; }
SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, AbstractConnectionManager *connManager) { /* LVP added, TFE DEBUG */ //msg_Info(NULL, "TFE DEBUG SegmentTracker getNextChunk, %" PRId64, mdate()); //std::cerr << "TFE DEBUG SegmentTracker getNextChunk, " << mdate() << std::endl; BaseRepresentation *rep = NULL, *prevRep = NULL; ISegment *segment; if(!adaptationSet) { /* LVP added, TFE DEBUG */ //msg_Info(NULL, "TFE DEBUG SegmentTracker getNextChunk no adaptation set, %" PRId64, mdate()); //std::cerr << "TFE DEBUG SegmentTracker getNextChunk no adaptation set, " << mdate() << std::endl; return NULL; } /* Ensure we don't keep chaining init/index without data */ if( initializing ) { if( curRepresentation ) switch_allowed = false; else switch_allowed = true; } if( !switch_allowed || (curRepresentation && curRepresentation->getSwitchPolicy() == SegmentInformation::SWITCH_UNAVAILABLE) ) rep = curRepresentation; else rep = logic->getNextRepresentation(adaptationSet, curRepresentation); if ( rep == NULL ) { /* LVP added, TFE DEBUG */ //msg_Info(NULL, "TFE DEBUG SegmentTracker no rep 1, %" PRId64, mdate()); //std::cerr << "TFE DEBUG SegmentTracker no rep 1, " << mdate() << std::endl; return NULL; } if(rep != curRepresentation) { notify(SegmentTrackerEvent(curRepresentation, rep)); prevRep = curRepresentation; curRepresentation = rep; init_sent = false; index_sent = false; initializing = true; } bool b_updated = false; /* Ensure ephemere content is updated/loaded */ if(rep->needsUpdate()) b_updated = rep->runLocalUpdates(getPlaybackTime(), curNumber, false); if(prevRep && !rep->consistentSegmentNumber()) { /* Convert our segment number */ next = rep->translateSegmentNumber(next, prevRep); } else if(first && rep->getPlaylist()->isLive()) { next = rep->getLiveStartSegmentNumber(next); first = false; } if(b_updated) { if(!rep->consistentSegmentNumber()) curRepresentation->pruneBySegmentNumber(curNumber); curRepresentation->scheduleNextUpdate(next); } if(rep->getStreamFormat() != format) { /* Initial format ? */ if(format == StreamFormat(StreamFormat::UNSUPPORTED)) { format = rep->getStreamFormat(); } else { format = rep->getStreamFormat(); notify(SegmentTrackerEvent(&format)); /* Notify new demux format */ return NULL; /* Force current demux to end */ } } if(format == StreamFormat(StreamFormat::UNSUPPORTED)) { return NULL; /* Can't return chunk because no demux will be created */ } if(!init_sent) { init_sent = true; segment = rep->getSegment(BaseRepresentation::INFOTYPE_INIT); if(segment) { /* LVP added, TFE DEBUG */ std::cerr << "TFE DEBUG SegmentTracker getNextChunk no init sent but segment, " << mdate() << std::endl; //msg_Info(NULL, "TFE DEBUG SegmentTracker getNextChunk no init sent but segment, %" PRId64, mdate()); //std::cerr << "TFE DEBUG SegmentTracker getNextChunk no init sent but segment, " << mdate() << std::endl; return segment->toChunk(next, rep, connManager); } } if(!index_sent) { index_sent = true; segment = rep->getSegment(BaseRepresentation::INFOTYPE_INDEX); if(segment) { /* LVP added, TFE DEBUG */ // happens after no init sent //msg_Info(NULL, "TFE DEBUG SegmentTracker getNextChunk no index sent but segment, %" PRId64, mdate()); //std::cerr << "TFE DEBUG SegmentTracker getNextChunk no index sent but segment, " << mdate() << std::endl; return segment->toChunk(next, rep, connManager); } } bool b_gap = false; segment = rep->getNextSegment(BaseRepresentation::INFOTYPE_MEDIA, next, &next, &b_gap); if(!segment) { reset(); /* LVP added, TFE DEBUG */ // once at the end //msg_Info(NULL, "TFE DEBUG SegmentTracker getNextChunk no segment and reset, %" PRId64, mdate()); //std::cerr << "TFE DEBUG SegmentTracker getNextChunk no segment and reset, " << mdate() << std::endl; return NULL; } if(initializing) { b_gap = false; /* stop initializing after 1st chunk */ initializing = false; } SegmentChunk *chunk = segment->toChunk(next, rep, connManager); /* Notify new segment length for stats / logic */ if(chunk) { const Timescale timescale = rep->inheritTimescale(); notify(SegmentTrackerEvent(rep->getAdaptationSet()->getID(), timescale.ToTime(segment->duration.Get()))); } /* We need to check segment/chunk format changes, as we can't rely on representation's (HLS)*/ if(chunk && format != chunk->getStreamFormat()) { format = chunk->getStreamFormat(); notify(SegmentTrackerEvent(&format)); } /* Handle both implicit and explicit discontinuities */ if( (b_gap && next) || (chunk && chunk->discontinuity) ) { notify(SegmentTrackerEvent(chunk)); } if(chunk) { curNumber = next; next++; } /* LVP added, TFE */ //msg_Info(NULL, "TFE SegmentTracker getNextChunk done, %" PRId64 ", %" PRId64, mdate(), rep->getBandwidth()); //std::cerr << "TFE SegmentTracker getNextChunk done, " << mdate() << ", " << rep->getBandwidth() << std::endl; return chunk; }