Skip to content

Commit

Permalink
Reworked method to insert live segments
Browse files Browse the repository at this point in the history
  • Loading branch information
CastagnaIT committed Jul 14, 2023
1 parent 0fe0853 commit c4908dd
Show file tree
Hide file tree
Showing 19 changed files with 292 additions and 164 deletions.
34 changes: 18 additions & 16 deletions src/Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,12 @@ bool CSession::GetNextSample(ISampleReader*& sampleReader)
}
else if (res)
{
CheckFragmentDuration(*res);
if (res->m_hasSegmentChanged)
{
OnSegmentChangedRead(res);
res->m_hasSegmentChanged = false;
}

ISampleReader* sr{res->GetReader()};

if (sr->PTS() != STREAM_NOPTS_VALUE)
Expand Down Expand Up @@ -1432,25 +1437,22 @@ void CSession::OnStreamChange(adaptive::AdaptiveStream* adStream)
}
}

void CSession::CheckFragmentDuration(CStream& stream)
void CSession::OnSegmentChangedRead(CStream* stream)
{
uint64_t nextTs;
uint64_t nextDur;
ISampleReader* streamReader{stream.GetReader()};
if (!streamReader)
if (m_adaptiveTree->IsLive())
{
LOG::LogF(LOGERROR, "Cannot get the stream sample reader");
return;
}
ISampleReader* sr = stream->GetReader();
uint64_t duration;

if (stream.m_hasSegmentChanged && streamReader->GetNextFragmentInfo(nextTs, nextDur))
{
m_adaptiveTree->SetFragmentDuration(
stream.m_adStream.getPeriod(), stream.m_adStream.getAdaptationSet(),
stream.m_adStream.getRepresentation(), stream.m_adStream.getSegmentPos(), nextTs,
static_cast<uint32_t>(nextDur), streamReader->GetTimeScale());
if (sr->GetFragmentInfo(duration))
{
adaptive::AdaptiveStream& adStream = stream->m_adStream;

m_adaptiveTree->InsertLiveSegment(adStream.getPeriod(), adStream.getAdaptationSet(),
adStream.getRepresentation(), adStream.getSegmentPos(),
0, duration, sr->GetTimeScale());
}
}
stream.m_hasSegmentChanged = false;
}

const AP4_UI08* CSession::GetDefaultKeyId(const uint16_t index) const
Expand Down
9 changes: 5 additions & 4 deletions src/Session.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,12 @@ class ATTR_DLL_LOCAL CSession : public adaptive::AdaptiveStreamObserver
void OnStreamChange(adaptive::AdaptiveStream* adStream) override;

protected:
/*! \brief If available, read the duration and timestamp of the next fragment and
* set the related members
* \param adStream [OUT] The adaptive stream to check
/*!
* \brief Event raised when the current segment is changed and
* the data has already been read by the sample reader.
* \param stream The stream for which segment has changed.
*/
void CheckFragmentDuration(CStream& stream);
void OnSegmentChangedRead(CStream* stream);

/*! \brief Check for and load decrypter module matching the supplied key system
* \param key_system [OUT] Will be assigned to if a decrypter is found matching
Expand Down
6 changes: 6 additions & 0 deletions src/Stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ void CStream::Reset()
m_mainId = 0;
}
}

void SESSION::CStream::SetReader(std::unique_ptr<ISampleReader> reader)
{
m_streamReader = std::move(reader);
m_streamReader->SetObserver(&m_adStream);
}
2 changes: 1 addition & 1 deletion src/Stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class ATTR_DLL_LOCAL CStream
* \brief Set the stream sample reader
* \param reader The reader
*/
void SetReader(std::unique_ptr<ISampleReader> reader) { m_streamReader = std::move(reader); }
void SetReader(std::unique_ptr<ISampleReader> reader);

/*!
* \brief Get the stream file handler pointer
Expand Down
6 changes: 6 additions & 0 deletions src/common/AdaptiveStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,12 @@ int AdaptiveStream::SecondsSinceUpdate() const
.count());
}

void AdaptiveStream::OnTFRFatom(uint64_t ts, uint64_t duration, uint32_t mediaTimescale)
{
tree_.InsertLiveSegment(current_period_, current_adp_, current_rep_, getSegmentPos(), ts,
duration, mediaTimescale);
}

bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep,
const std::vector<uint8_t>& buffer)
{
Expand Down
6 changes: 5 additions & 1 deletion src/common/AdaptiveStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include "AdaptiveTree.h"

#include "../samplereader/SampleReader.h"

#include <atomic>
#include <condition_variable>
#include <map>
Expand All @@ -30,7 +32,7 @@ class AdaptiveStream;
virtual void OnStreamChange(AdaptiveStream *stream) = 0;
};

class ATTR_DLL_LOCAL AdaptiveStream
class ATTR_DLL_LOCAL AdaptiveStream : public SampleReaderObserver
{
public:
AdaptiveStream(AdaptiveTree& tree,
Expand Down Expand Up @@ -88,6 +90,8 @@ class AdaptiveStream;
void SetSegmentFileOffset(uint64_t offset) { m_segmentFileOffset = offset; };
bool StreamChanged() { return stream_changed_; }

void OnTFRFatom(uint64_t ts, uint64_t duration, uint32_t mediaTimescale) override;

protected:
virtual bool parseIndexRange(PLAYLIST::CRepresentation* rep,
const std::vector<uint8_t>& buffer);
Expand Down
75 changes: 0 additions & 75 deletions src/common/AdaptiveTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,81 +96,6 @@ namespace adaptive
repr->current_segment_ = nullptr;
}

void AdaptiveTree::SetFragmentDuration(PLAYLIST::CPeriod* period,
PLAYLIST::CAdaptationSet* adpSet,
PLAYLIST::CRepresentation* repr,
size_t pos,
uint64_t timestamp,
uint32_t fragmentDuration,
uint32_t movie_timescale)
{
if (!m_isLive || HasManifestUpdatesSegs())
return;

// Check if its the last frame we watch
if (!adpSet->SegmentTimelineDuration().IsEmpty())
{
if (pos == adpSet->SegmentTimelineDuration().GetSize() - 1)
{
adpSet->SegmentTimelineDuration().Insert(
static_cast<std::uint32_t>(static_cast<std::uint64_t>(fragmentDuration) *
period->GetTimescale() / movie_timescale));
}
else
{
repr->expired_segments_++;
return;
}
}
else if (pos != repr->SegmentTimeline().GetSize() - 1)
return;

// Add new segment
// This may happen for example when a DASH live manifest
// has very long duration validity (set by minimumUpdatePeriod) and segments
// dont cover the entire duration until minimumUpdatePeriod interval time
// in this new segments must be added until the future manifest update
CSegment* segment = repr->SegmentTimeline().Get(pos);

if (!segment)
{
LOG::LogF(LOGERROR, "Segment at position %zu not found from representation id: %s", pos,
repr->GetId().data());
return;
}

if (segment->HasByteRange())
return;

CSegment segCopy = *segment;

if (!timestamp)
{
LOG::LogF(LOGDEBUG, "Scale fragment duration: fdur:%u, rep-scale:%u, mov-scale:%u",
fragmentDuration, repr->GetTimescale(), movie_timescale);
fragmentDuration = static_cast<std::uint32_t>(
(static_cast<std::uint64_t>(fragmentDuration) * repr->GetTimescale()) / movie_timescale);
}
else
{
LOG::LogF(LOGDEBUG, "Fragment duration from timestamp: ts:%llu, base:%llu, s-pts:%llu",
timestamp, base_time_, segCopy.startPTS_);
fragmentDuration = static_cast<uint32_t>(timestamp - base_time_ - segCopy.startPTS_);
}

segCopy.startPTS_ += fragmentDuration;
segCopy.m_time += fragmentDuration;
segCopy.m_number++;

LOG::LogF(LOGDEBUG, "Insert live segment: pts: %llu number: %llu", segCopy.startPTS_,
segCopy.m_number);

for (auto& repr : adpSet->GetRepresentations())
{
repr->SegmentTimeline().Insert(segCopy);
}
}

void AdaptiveTree::OnDataArrived(uint64_t segNum,
uint16_t psshSet,
uint8_t iv[16],
Expand Down
29 changes: 21 additions & 8 deletions src/common/AdaptiveTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ class ATTR_DLL_LOCAL AdaptiveTree
uint64_t m_totalTimeSecs{0}; // Total playing time in seconds
uint64_t stream_start_{0};
uint64_t available_time_{0};
uint64_t base_time_{0}; // SmoothTree only, the lower start PTS time between all StreamIndex tags
uint64_t m_liveDelay{0}; // Apply a delay in seconds from the live edge

std::string m_supportedKeySystem;
Expand Down Expand Up @@ -133,13 +132,27 @@ class ATTR_DLL_LOCAL AdaptiveTree

void FreeSegments(PLAYLIST::CPeriod* period, PLAYLIST::CRepresentation* repr);

void SetFragmentDuration(PLAYLIST::CPeriod* period,
PLAYLIST::CAdaptationSet* adpSet,
PLAYLIST::CRepresentation* repr,
size_t pos,
uint64_t timestamp,
uint32_t fragmentDuration,
uint32_t movie_timescale);
/*!
* \brief Some adaptive streaming protocols allow the client to download the live playlist once and
* build future segments based on metadata contained in the fragments e.g. to avoid repeated
* manifest downloads or to cover the duration of a period not fully covered by the segments.
* \param period Current period
* \param adpSet Current adaptation set
* \param repr Current representation
* \param pos Current segment position
* \param timestamp Fragment start timestamp
* \param fragmentDuration Fragment duration
* \param movieTimescale Fragment movie timescale
*/
virtual void InsertLiveSegment(PLAYLIST::CPeriod* period,
PLAYLIST::CAdaptationSet* adpSet,
PLAYLIST::CRepresentation* repr,
size_t pos,
uint64_t timestamp,
uint64_t fragmentDuration,
uint32_t movieTimescale)
{
}

// Insert a PSSHSet to the specified Period and return the position
uint16_t InsertPsshSet(PLAYLIST::StreamType streamType,
Expand Down
63 changes: 63 additions & 0 deletions src/parser/DASHTree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1710,6 +1710,69 @@ void adaptive::CDashTree::RefreshLiveSegments()
}
}

void adaptive::CDashTree::InsertLiveSegment(PLAYLIST::CPeriod* period,
PLAYLIST::CAdaptationSet* adpSet,
PLAYLIST::CRepresentation* repr,
size_t pos,
uint64_t timestamp,
uint64_t fragmentDuration,
uint32_t movieTimescale)
{
if (HasManifestUpdatesSegs())
return;

// Check if its the last frame we watch
if (!adpSet->SegmentTimelineDuration().IsEmpty())
{
if (pos == adpSet->SegmentTimelineDuration().GetSize() - 1)
{
adpSet->SegmentTimelineDuration().Insert(
static_cast<std::uint32_t>(fragmentDuration * period->GetTimescale() / movieTimescale));
}
else
{
repr->expired_segments_++;
return;
}
}
else if (pos != repr->SegmentTimeline().GetSize() - 1)
return;

// When a live manifest has very long duration validity (set by minimumUpdatePeriod)
// and segments dont cover the entire duration until minimumUpdatePeriod interval time
// we add new segments until the future manifest update
CSegment* segment = repr->SegmentTimeline().Get(pos);

if (!segment)
{
LOG::LogF(LOGERROR, "Segment at position %zu not found from representation id: %s", pos,
repr->GetId().data());
return;
}

if (segment->HasByteRange())
return;

CSegment segCopy = *segment;

LOG::LogF(LOGDEBUG,
"Scale fragment duration (duration: %llu, repr. timescale: %u, movie timescale: %u)",
fragmentDuration, repr->GetTimescale(), movieTimescale);
fragmentDuration = (fragmentDuration * repr->GetTimescale()) / movieTimescale;

segCopy.startPTS_ += fragmentDuration;
segCopy.m_time += fragmentDuration;
segCopy.m_number++;

LOG::LogF(LOGDEBUG, "Insert live segment to adptation set \"%s\" (PTS: %llu, number: %llu)",
adpSet->GetId().data(), segCopy.startPTS_, segCopy.m_number);

for (auto& repr : adpSet->GetRepresentations())
{
repr->SegmentTimeline().Insert(segCopy);
}
}

uint64_t adaptive::CDashTree::GetTimestamp()
{
return UTILS::GetTimestamp();
Expand Down
8 changes: 8 additions & 0 deletions src/parser/DASHTree.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ class ATTR_DLL_LOCAL CDashTree : public adaptive::AdaptiveTree
const std::map<std::string, std::string>& headers,
const std::string& data) override;

virtual void InsertLiveSegment(PLAYLIST::CPeriod* period,
PLAYLIST::CAdaptationSet* adpSet,
PLAYLIST::CRepresentation* repr,
size_t pos,
uint64_t timestamp,
uint64_t fragmentDuration,
uint32_t movieTimescale);

protected:
virtual CDashTree* Clone() const override { return new CDashTree{*this}; }

Expand Down
Loading

0 comments on commit c4908dd

Please sign in to comment.