Skip to content

Commit

Permalink
[AdaptiveTree] First rework to cleanup segments
Browse files Browse the repository at this point in the history
  • Loading branch information
CastagnaIT committed Jun 21, 2023
1 parent 0044efd commit e9ecbec
Show file tree
Hide file tree
Showing 24 changed files with 582 additions and 438 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ set(ADP_SOURCES
src/common/Representation.cpp
src/common/ReprSelector.cpp
src/common/Segment.cpp
src/common/SegmentBase.cpp
src/common/SegmentList.cpp
src/common/SegTemplate.cpp
src/parser/CodecParser.cpp
Expand Down Expand Up @@ -103,6 +104,7 @@ set(ADP_HEADERS
src/common/Representation.h
src/common/ReprSelector.h
src/common/Segment.h
src/common/SegmentBase.h
src/common/SegmentList.h
src/common/SegTemplate.h
src/parser/CodecParser.h
Expand Down
2 changes: 1 addition & 1 deletion src/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,7 @@ AP4_Movie* CSession::PrepareStream(CStream* stream, bool& needRefetch)
}

if (repr->GetContainerType() == ContainerType::MP4 && !repr->HasInitPrefixed() &&
!repr->HasInitialization())
!repr->HasInitSegment())
{
//We'll create a Movie out of the things we got from manifest file
//note: movie will be deleted in destructor of stream->input_file_
Expand Down
1 change: 1 addition & 0 deletions src/common/AdaptationSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ void PLAYLIST::CAdaptationSet::CopyHLSData(const CAdaptationSet* other)
m_representations.push_back(std::move(rep));
}

m_baseUrl = other->m_baseUrl;
m_streamType = other->m_streamType;
m_duration = other->m_duration;
m_startPts = other->m_startPts;
Expand Down
182 changes: 82 additions & 100 deletions src/common/AdaptiveStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,80 +237,53 @@ bool AdaptiveStream::PrepareNextDownload(DownloadInfo& downloadInfo)
segBuffer->buffer.clear();
downloadInfo.m_segmentBuffer = segBuffer;

return PrepareDownload(segBuffer->rep, segBuffer->segment, segBuffer->segment_number,
downloadInfo);
return PrepareDownload(segBuffer->rep, segBuffer->segment, downloadInfo);
}

bool AdaptiveStream::PrepareDownload(const PLAYLIST::CRepresentation* rep,
const PLAYLIST::CSegment& seg,
const uint64_t segNum,
DownloadInfo& downloadInfo)
{
if (!rep)
return false;

std::string rangeHeader;
std::string streamUrl;

if (!rep->HasSegmentBase())
if (rep->HasSegmentTemplate())
{
if (!rep->HasSegmentTemplate())
auto segTpl = rep->GetSegmentTemplate();

if (seg.IsInitialization()) // Templated initialization segment
{
if (rep->HasSegmentsUrl())
{
if (URL::IsUrlAbsolute(seg.url))
streamUrl = seg.url;
else
streamUrl = URL::Join(rep->GetUrl(), seg.url);
}
else
streamUrl = rep->GetUrl();
if (seg.range_begin_ != CSegment::NO_RANGE_VALUE)
{
uint64_t fileOffset = ~segNum ? m_segmentFileOffset : 0;
if (seg.range_end_ != CSegment::NO_RANGE_VALUE)
{
rangeHeader = StringUtils::Format("bytes=%llu-%llu", seg.range_begin_ + fileOffset,
seg.range_end_ + fileOffset);
}
else
{
rangeHeader = StringUtils::Format("bytes=%llu-", seg.range_begin_ + fileOffset);
}
}
streamUrl = segTpl->FormatUrl(segTpl->GetInitialization(), rep->GetId().data(),
rep->GetBandwidth(), rep->GetStartNumber(), 0);
}
else if (~segNum) //templated segment
else // Templated media segment
{
streamUrl = rep->GetSegmentTemplate()->GetMediaUrl();
ReplacePlaceholder(streamUrl, "$Number", seg.range_end_);
ReplacePlaceholder(streamUrl, "$Time", seg.range_begin_);
streamUrl = segTpl->FormatUrl(segTpl->GetMedia(), rep->GetId().data(), rep->GetBandwidth(),
seg.m_number, seg.m_time);
}
else //templated initialization segment
streamUrl = rep->GetUrl();
}
else
{
if (rep->HasSegmentTemplate() && ~segNum)
if (seg.url.empty())
streamUrl = rep->GetBaseUrl();
else
streamUrl = seg.url;
}

if (URL::IsUrlRelative(streamUrl))
streamUrl = URL::Join(rep->GetBaseUrl(), streamUrl);

if (seg.range_begin_ != NO_VALUE)
{
uint64_t fileOffset = seg.IsInitialization() ? 0 : m_segmentFileOffset;
if (seg.range_end_ != NO_VALUE)
{
streamUrl = rep->GetSegmentTemplate()->GetMediaUrl();
ReplacePlaceholder(streamUrl, "$Number", rep->GetStartNumber());
ReplacePlaceholder(streamUrl, "$Time", 0);
rangeHeader = StringUtils::Format("bytes=%llu-%llu", seg.range_begin_ + fileOffset,
seg.range_end_ + fileOffset);
}
else
streamUrl = rep->GetUrl();

if (seg.range_begin_ != CSegment::NO_RANGE_VALUE)
{
uint64_t fileOffset = ~segNum ? m_segmentFileOffset : 0;
if (seg.range_end_ != CSegment::NO_RANGE_VALUE)
{
rangeHeader = StringUtils::Format("bytes=%llu-%llu", seg.range_begin_ + fileOffset,
seg.range_end_ + fileOffset);
}
else
{
rangeHeader = StringUtils::Format("bytes=%llu-", seg.range_begin_ + fileOffset);
}
rangeHeader = StringUtils::Format("bytes=%llu-", seg.range_begin_ + fileOffset);
}
}

Expand Down Expand Up @@ -475,7 +448,7 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, const std::

if (rep->GetContainerType() == ContainerType::WEBM)
{
if (!rep->m_segBaseIndexRangeMin)
if (rep->GetSegmentBase()->GetIndexRangeBegin() == 0)
return false;

WebmReader reader(&byteStream);
Expand Down Expand Up @@ -510,7 +483,7 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, const std::
}
else if (rep->GetContainerType() == ContainerType::MP4)
{
if (rep->m_segBaseIndexRangeMin == 0)
if (rep->GetSegmentBase()->GetIndexRangeBegin() == 0)
{
AP4_File fileStream{byteStream, AP4_DefaultAtomFactory::Instance_, true};
AP4_Movie* movie{fileStream.GetMovie()};
Expand All @@ -521,11 +494,15 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, const std::
return false;
}

rep->initialization_.range_begin_ = 0;
if (!rep->HasInitSegment())
{
LOG::LogF(LOGERROR, "[AS-%u] Representation has no init segment", clsId);
return false;
}
rep->GetInitSegment()->range_begin_ = 0;
AP4_Position pos;
byteStream.Tell(pos);
rep->initialization_.range_end_ = pos - 1;
rep->SetHasInitialization(true);
rep->GetInitSegment()->range_end_ = pos - 1;
}

CSegment seg;
Expand Down Expand Up @@ -565,7 +542,8 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, const std::

AP4_Position pos;
byteStream.Tell(pos);
seg.range_end_ = pos + rep->m_segBaseIndexRangeMin + sidx->GetFirstOffset() - 1;
seg.range_end_ =
pos + rep->GetSegmentBase()->GetIndexRangeBegin() + sidx->GetFirstOffset() - 1;
rep->SetTimescale(sidx->GetTimeScale());
rep->SetScaling();

Expand Down Expand Up @@ -645,10 +623,11 @@ bool AdaptiveStream::start_stream()
thread_data_->signal_dl_.wait(lckdl);
}

if (current_rep_->SegmentTimeline().IsEmpty() && current_rep_->HasSegmentBase())
{
// ResolveSegmentbase assumes mutex_dl locked
std::lock_guard<std::mutex> lck(thread_data_->mutex_dl_);
if (!ResolveSegmentBase(current_rep_, true))
if (!ResolveSegmentBase(current_rep_))
{
state_ = STOPPED;
return false;
Expand Down Expand Up @@ -717,8 +696,7 @@ bool AdaptiveStream::start_stream()
absolute_position_ = 0;

// load the initialization segment
const CSegment* loadingSeg = current_rep_->get_initialization();
if (loadingSeg)
if (current_rep_->HasInitSegment())
{
StopWorker(PAUSED);
WaitWorker();
Expand All @@ -728,10 +706,8 @@ bool AdaptiveStream::start_stream()
segment_buffers_.rend() - available_segment_buffers_, segment_buffers_.rend());
++available_segment_buffers_;

segment_buffers_[0]->segment.url.clear();
segment_buffers_[0]->segment.Copy(loadingSeg);
segment_buffers_[0]->segment = *current_rep_->GetInitSegment();
segment_buffers_[0]->rep = current_rep_;
segment_buffers_[0]->segment_number = SEGMENT_NO_NUMBER;
segment_buffers_[0]->buffer.clear();
segment_read_pos_ = 0;

Expand Down Expand Up @@ -836,7 +812,7 @@ bool AdaptiveStream::ensureSegment()
}
if (valid_segment_buffers_)
{
if (segment_buffers_[0]->segment_number != SEGMENT_NO_NUMBER)
if (!segment_buffers_[0]->segment.IsInitialization())
{
nextSegment = current_rep_->get_segment(static_cast<size_t>(
segment_buffers_[0]->segment_number - current_rep_->GetStartNumber()));
Expand Down Expand Up @@ -865,7 +841,7 @@ bool AdaptiveStream::ensureSegment()
current_rep_->current_segment_ = nextSegment;
ResetSegment(nextSegment);

if (observer_ && nextSegment != &current_rep_->initialization_ &&
if (observer_ && !nextSegment->IsInitialization() &&
nextSegment->startPTS_ != NO_PTS_VALUE)
{
observer_->OnSegmentChanged(this);
Expand All @@ -885,7 +861,7 @@ bool AdaptiveStream::ensureSegment()
}
}

if (segment_buffers_[0]->segment_number == SEGMENT_NO_NUMBER ||
if (segment_buffers_[0]->segment.IsInitialization() ||
valid_segment_buffers_ == 0 ||
current_adp_->GetStreamType() != StreamType::VIDEO)
{
Expand All @@ -906,8 +882,9 @@ bool AdaptiveStream::ensureSegment()
newRep = current_rep_;
}

// Make sure, new representation has segments!
ResolveSegmentBase(newRep, false); // For DASH
// If the representation has been changed, segments may have to be generated (DASH)
if (newRep->SegmentTimeline().IsEmpty() && newRep->HasSegmentBase())
ResolveSegmentBase(newRep);

if (tree_.SecondsSinceRepUpdate(newRep) > 1)
{
Expand All @@ -926,7 +903,7 @@ bool AdaptiveStream::ensureSegment()

if (futureSegment)
{
segment_buffers_[updPos]->segment.Copy(futureSegment);
segment_buffers_[updPos]->segment = *futureSegment;
segment_buffers_[updPos]->segment_number =
newRep->GetStartNumber() + nextsegmentPos + updPos;
segment_buffers_[updPos]->rep = newRep;
Expand Down Expand Up @@ -1219,41 +1196,46 @@ bool AdaptiveStream::waitingForSegment(bool checkTime) const

void AdaptiveStream::FixateInitialization(bool on)
{
m_fixateInitialization = on && current_rep_->get_initialization() != nullptr;
m_fixateInitialization = on && current_rep_->HasInitSegment();
}

bool AdaptiveStream::ResolveSegmentBase(PLAYLIST::CRepresentation* rep, bool stopWorker)
bool AdaptiveStream::ResolveSegmentBase(PLAYLIST::CRepresentation* rep)
{
/* If we have indexRangeExact SegmentBase, update SegmentList from SIDX */
if (rep->HasSegmentBase())
{
// We assume mutex_dl is locked so we can safely call prepare_download
CSegment seg;
unsigned int segNum = ~0U;
if (rep->m_segBaseIndexRangeMin > 0 || !rep->HasInitialization())
{
seg.range_begin_ = rep->m_segBaseIndexRangeMin;
seg.range_end_ = rep->m_segBaseIndexRangeMax;
seg.pssh_set_ = 0;
segNum = 0; // It's no an initialization segment
}
else if (rep->HasInitialization())
seg = *rep->get_initialization();
else
return false;
// Get the byte ranges to download the index segment to generate media segments from SIDX atom

std::string sidxBuffer;
DownloadInfo downloadInfo;
auto& segBase = rep->GetSegmentBase();
CSegment seg;

if (PrepareDownload(rep, seg, segNum, downloadInfo) && Download(downloadInfo, sidxBuffer) &&
parseIndexRange(rep, sidxBuffer))
{
rep->SetHasSegmentBase(false);
}
else
return false;
if (!rep->HasInitSegment() && segBase->GetIndexRangeBegin() == 0 &&
segBase->GetIndexRangeEnd() > 0)
{
seg.SetIsInitialization(true);
seg.range_end_ = segBase->GetIndexRangeEnd();
// Initialization segment will be set to representation by ParseIndexRange
}
return true;
else if (segBase->GetIndexRangeBegin() > 0 || !rep->HasInitSegment())
{
// It's no an initialization segment
seg.range_begin_ = segBase->GetIndexRangeBegin();
seg.range_end_ = segBase->GetIndexRangeEnd();
}
else if (rep->HasInitSegment())
{
seg = *rep->GetInitSegment();
}
else
return false;

std::string sidxBuffer;
DownloadInfo downloadInfo;
// We assume mutex_dl is locked so we can safely call prepare_download
if (PrepareDownload(rep, seg, downloadInfo) && Download(downloadInfo, sidxBuffer) &&
parseIndexRange(rep, sidxBuffer))
{
return true;
}

return false;
}

void AdaptiveStream::Stop()
Expand Down
5 changes: 2 additions & 3 deletions src/common/AdaptiveStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class AdaptiveStream;
{
std::string buffer;
PLAYLIST::CSegment segment;
uint64_t segment_number{0}; // SEGMENT_NO_NUMBER is initialization segment!
uint64_t segment_number{0};
PLAYLIST::CRepresentation* rep{nullptr};
};
std::vector<SEGMENTBUFFER*> segment_buffers_;
Expand Down Expand Up @@ -156,7 +156,6 @@ class AdaptiveStream;
bool PrepareNextDownload(DownloadInfo& downloadInfo);
bool PrepareDownload(const PLAYLIST::CRepresentation* rep,
const PLAYLIST::CSegment& seg,
const uint64_t segNum,
DownloadInfo& downloadInfo);

void ResetSegment(const PLAYLIST::CSegment* segment);
Expand All @@ -174,7 +173,7 @@ class AdaptiveStream;

int SecondsSinceUpdate() const;
static void ReplacePlaceholder(std::string& url, const std::string placeholder, uint64_t value);
bool ResolveSegmentBase(PLAYLIST::CRepresentation* rep, bool stopWorker);
bool ResolveSegmentBase(PLAYLIST::CRepresentation* rep);

struct THREADDATA
{
Expand Down
3 changes: 0 additions & 3 deletions src/common/AdaptiveTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ namespace adaptive
period->DecrasePSSHSetUsageCount(segment.pssh_set_);
}

if (repr->HasInitialization() && repr->HasSegmentsUrl())
repr->initialization_.url.clear();

repr->SegmentTimeline().Clear();
repr->current_segment_ = nullptr;
}
Expand Down
4 changes: 2 additions & 2 deletions src/common/AdaptiveUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ std::string_view PLAYLIST::StreamTypeToString(const StreamType streamType)
bool PLAYLIST::ParseRangeRFC(std::string_view range, uint64_t& start, uint64_t& end)
{
//! @todo: must be reworked as https://httpwg.org/specs/rfc7233.html
uint64_t startVal;
uint64_t endVal;
uint64_t startVal{0};
uint64_t endVal{0};
if (std::sscanf(range.data(), "%" SCNu64 "-%" SCNu64, &startVal, &endVal) > 0)
{
start = startVal;
Expand Down
Loading

0 comments on commit e9ecbec

Please sign in to comment.