bool SegmentTracker::segmentsListReady() const { BaseRepresentation *rep = curRepresentation; if(!rep) rep = logic->getNextRepresentation(adaptationSet, NULL); if(rep && rep->getPlaylist()->isLive()) return rep->getMinAheadTime(curNumber) > 0; return true; }
SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionManager *connManager) { BaseRepresentation *rep = NULL, *prevRep = NULL; ISegment *segment; if(!adaptationSet) 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 ) 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(!init_sent) { init_sent = true; segment = rep->getSegment(BaseRepresentation::INFOTYPE_INIT); if(segment) return segment->toChunk(next, rep, connManager); } if(!index_sent) { index_sent = true; segment = rep->getSegment(BaseRepresentation::INFOTYPE_INDEX); if(segment) return segment->toChunk(next, rep, connManager); } bool b_gap = false; segment = rep->getNextSegment(BaseRepresentation::INFOTYPE_MEDIA, next, &next, &b_gap); if(!segment) { reset(); return NULL; } if(initializing) { b_gap = false; /* stop initializing after 1st chunk */ initializing = false; } SegmentChunk *chunk = segment->toChunk(next, rep, connManager); /* 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++; } return chunk; }
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; }