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 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; }
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; }
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; }