block_t * AbstractStream::readNextBlock(size_t toread) { SegmentChunk *chunk = getChunk(); if(!chunk) return NULL; if(format != chunk->getStreamFormat()) { /* Force stream to end for this call */ msg_Info(p_realdemux, "Changing stream format %u->%u", (unsigned)format, (unsigned)chunk->getStreamFormat()); restarting_output = true; format = chunk->getStreamFormat(); /* Next stream will use current unused chunk */ return NULL; } if(chunk->discontinuity) { discontinuity = true; chunk->discontinuity = false; msg_Info(p_realdemux, "Encountered discontinuity"); return NULL; } const bool b_segment_head_chunk = (chunk->getBytesRead() == 0); block_t *block = chunk->read(toread); if(block == NULL) { currentChunk = NULL; delete chunk; return NULL; } if (chunk->getBytesToRead() == 0) { currentChunk = NULL; delete chunk; } block = checkBlock(block, b_segment_head_chunk); return block; }
size_t Stream::read(HTTPConnectionManager *connManager) { SegmentChunk *chunk = getChunk(); if(!chunk) return 0; if(!chunk->getConnection()) { if(!connManager->connectChunk(chunk)) return 0; } size_t readsize = 0; bool b_segment_head_chunk = false; /* New chunk, do query */ if(chunk->getBytesRead() == 0) { if(chunk->getConnection()->query(chunk->getPath()) != VLC_SUCCESS) { chunk->getConnection()->releaseChunk(); currentChunk = NULL; delete chunk; return 0; } b_segment_head_chunk = true; } /* Because we don't know Chunk size at start, we need to get size from content length */ readsize = chunk->getBytesToRead(); if (readsize > 32768) readsize = 32768; block_t *block = block_Alloc(readsize); if(!block) return 0; mtime_t time = mdate(); ssize_t ret = chunk->getConnection()->read(block->p_buffer, readsize); time = mdate() - time; if(ret < 0) { block_Release(block); chunk->getConnection()->releaseChunk(); currentChunk = NULL; delete chunk; return 0; } else { block->i_buffer = (size_t)ret; adaptationLogic->updateDownloadRate(block->i_buffer, time); chunk->onDownload(&block); StreamFormat chunkStreamFormat = chunk->getStreamFormat(); if(output && chunkStreamFormat != output->getStreamFormat()) { msg_Info(p_demux, "Changing stream format"); updateFormat(chunkStreamFormat); } if (chunk->getBytesToRead() == 0) { chunk->getConnection()->releaseChunk(); currentChunk = NULL; delete chunk; } } readsize = block->i_buffer; if(output) output->pushBlock(block, b_segment_head_chunk); else block_Release(block); return readsize; }
SegmentChunk * SegmentTracker::getNextChunk(bool switch_allowed, HTTPConnectionManager *connManager) { BaseRepresentation *rep = NULL; ISegment *segment; if(!adaptationSet) return NULL; /* Ensure we don't keep chaining init/index without data */ if( initializing ) { if( prevRepresentation ) switch_allowed = false; else switch_allowed = true; } if( !switch_allowed || (prevRepresentation && prevRepresentation->getSwitchPolicy() == SegmentInformation::SWITCH_UNAVAILABLE) ) rep = prevRepresentation; else rep = logic->getNextRepresentation(adaptationSet, prevRepresentation); if ( rep == NULL ) return NULL; if(rep != prevRepresentation) { notify(SegmentTrackerEvent(prevRepresentation, rep)); prevRepresentation = rep; init_sent = false; index_sent = false; initializing = true; } /* Ensure ephemere content is updated/loaded */ if(rep->needsUpdate()) updateSelected(); if(!init_sent) { init_sent = true; segment = rep->getSegment(BaseRepresentation::INFOTYPE_INIT); if(segment) return segment->toChunk(count, rep, connManager); } if(!index_sent) { index_sent = true; segment = rep->getSegment(BaseRepresentation::INFOTYPE_INDEX); if(segment) return segment->toChunk(count, rep, connManager); } bool b_gap = false; segment = rep->getNextSegment(BaseRepresentation::INFOTYPE_MEDIA, count, &count, &b_gap); if(!segment) { reset(); return NULL; } /* stop initializing after 1st chunk */ initializing = false; SegmentChunk *chunk = segment->toChunk(count, rep, connManager); if(chunk) count++; /* We need to check segment/chunk format changes, as we can't rely on representation's (HLS)*/ if(format != chunk->getStreamFormat()) { format = chunk->getStreamFormat(); notify(SegmentTrackerEvent(&format)); } /* Handle both implicit and explicit discontinuities */ if( (b_gap && count) || (chunk && chunk->discontinuity) ) { notify(SegmentTrackerEvent(chunk)); } return chunk; }
block_t * AbstractStream::readNextBlock(size_t) { SegmentChunk *chunk = getChunk(); if(!chunk) return NULL; if(format != chunk->getStreamFormat()) { /* Force stream to end for this call */ msg_Info(p_realdemux, "Changing stream format %u->%u", (unsigned)format, (unsigned)chunk->getStreamFormat()); restarting_output = true; format = chunk->getStreamFormat(); /* Next stream will use current unused chunk */ return NULL; } if(chunk->discontinuity) { discontinuity = true; chunk->discontinuity = false; msg_Info(p_realdemux, "Encountered discontinuity"); return NULL; } if(!chunk->getConnection()) { if(!connManager->connectChunk(chunk)) return NULL; } size_t readsize = 0; bool b_segment_head_chunk = false; /* New chunk, do query */ if(chunk->getBytesRead() == 0) { if(chunk->getConnection()->query(chunk->getPath()) != VLC_SUCCESS) { chunk->getConnection()->releaseChunk(); currentChunk = NULL; delete chunk; return NULL; } b_segment_head_chunk = true; } /* Because we don't know Chunk size at start, we need to get size from content length */ readsize = chunk->getBytesToRead(); if (readsize > 32768) readsize = 32768; block_t *block = block_Alloc(readsize); if(!block) return NULL; mtime_t time = mdate(); ssize_t ret = chunk->getConnection()->read(block->p_buffer, readsize); time = mdate() - time; if(ret < 0) { block_Release(block); chunk->getConnection()->releaseChunk(); currentChunk = NULL; delete chunk; return NULL; } else { block->i_buffer = (size_t)ret; adaptationLogic->updateDownloadRate(block->i_buffer, time); chunk->onDownload(&block); if (chunk->getBytesToRead() == 0) { chunk->getConnection()->releaseChunk(); currentChunk = NULL; delete chunk; } } block = checkBlock(block, b_segment_head_chunk); return block; }
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; }