From 170e8511897b42ec406ecb41361e888006c23e9a Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Mon, 1 Jul 2024 10:36:44 +0200 Subject: [PATCH 1/6] [AdaptiveTree] Removed CSpinCache use from SegmentTimelineDuration --- src/common/AdaptationSet.h | 6 +++--- src/common/AdaptiveStream.cpp | 13 ------------- src/common/Period.h | 7 +++---- src/parser/DASHTree.cpp | 29 +++++++++++++++-------------- src/parser/DASHTree.h | 2 +- src/parser/SmoothTree.cpp | 12 ++++++------ 6 files changed, 28 insertions(+), 41 deletions(-) diff --git a/src/common/AdaptationSet.h b/src/common/AdaptationSet.h index eb3d94dd8..7e23989a7 100644 --- a/src/common/AdaptationSet.h +++ b/src/common/AdaptationSet.h @@ -79,8 +79,8 @@ class ATTR_DLL_LOCAL CAdaptationSet : public CCommonSegAttribs, public CCommonAt void AddSwitchingIds(std::string_view switchingIds); const std::vector& GetSwitchingIds() { return m_switchingIds; } - CSpinCache& SegmentTimelineDuration() { return m_segmentTimelineDuration; } - bool HasSegmentTimelineDuration() { return !m_segmentTimelineDuration.IsEmpty(); } + std::vector& SegmentTimelineDuration() { return m_segmentTimelineDuration; } + bool HasSegmentTimelineDuration() { return !m_segmentTimelineDuration.empty(); } /*! * \brief Get the timescale of segment durations tag. @@ -175,7 +175,7 @@ class ATTR_DLL_LOCAL CAdaptationSet : public CCommonSegAttribs, public CCommonAt std::string m_language; std::vector m_switchingIds; - CSpinCache m_segmentTimelineDuration; + std::vector m_segmentTimelineDuration; uint64_t m_segDurationsTimescale{NO_VALUE}; // Custom ISAdaptive attributes (used on DASH only) diff --git a/src/common/AdaptiveStream.cpp b/src/common/AdaptiveStream.cpp index cd5ecf193..f15daa431 100644 --- a/src/common/AdaptiveStream.cpp +++ b/src/common/AdaptiveStream.cpp @@ -477,13 +477,6 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, seg.range_begin_ = cue.pos_start; seg.range_end_ = cue.pos_end; rep->SegmentTimeline().GetData().emplace_back(seg); - - //! todo: use SegmentTimelineDuration should not be needed - if (adpSet->SegmentTimelineDuration().GetSize() < rep->SegmentTimeline().GetSize()) - { - adpSet->SegmentTimelineDuration().GetData().emplace_back( - static_cast(cue.duration)); - } } return true; } @@ -550,12 +543,6 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, seg.range_end_ = seg.range_begin_ + refs[i].m_ReferencedSize - 1; rep->SegmentTimeline().GetData().emplace_back(seg); - //! todo: use SegmentTimelineDuration should not be needed - if (adpSet->SegmentTimelineDuration().GetSize() < rep->SegmentTimeline().GetSize()) - { - adpSet->SegmentTimelineDuration().GetData().emplace_back(refs[i].m_SubsegmentDuration); - } - seg.startPTS_ += refs[i].m_SubsegmentDuration; seg.m_endPts = seg.startPTS_ + refs[i].m_SubsegmentDuration; seg.m_time += refs[i].m_SubsegmentDuration; diff --git a/src/common/Period.h b/src/common/Period.h index cc9626bec..a063dd20b 100644 --- a/src/common/Period.h +++ b/src/common/Period.h @@ -8,7 +8,6 @@ #pragma once -#include "AdaptiveUtils.h" #include "CommonSegAttribs.h" #include "SegTemplate.h" #include "utils/CryptoUtils.h" @@ -89,8 +88,8 @@ class ATTR_DLL_LOCAL CPeriod : public CCommonSegAttribs m_isSecureDecoderNeeded = isSecureDecoderNeeded; }; - CSpinCache& SegmentTimelineDuration() { return m_segmentTimelineDuration; } - bool HasSegmentTimelineDuration() { return !m_segmentTimelineDuration.IsEmpty(); } + std::vector& SegmentTimelineDuration() { return m_segmentTimelineDuration; } + bool HasSegmentTimelineDuration() { return !m_segmentTimelineDuration.empty(); } void CopyHLSData(const CPeriod* other); @@ -143,7 +142,7 @@ class ATTR_DLL_LOCAL CPeriod : public CCommonSegAttribs uint64_t m_duration{0}; EncryptionState m_encryptionState{EncryptionState::UNENCRYPTED}; bool m_isSecureDecoderNeeded{false}; - CSpinCache m_segmentTimelineDuration; + std::vector m_segmentTimelineDuration; }; } // namespace adaptive diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index e6537b4a8..5b8d80fd8 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -632,7 +632,7 @@ void adaptive::CDashTree::ParseTagAdaptationSet(pugi::xml_node nodeAdp, PLAYLIST // add all duration values as timeline segments for (xml_node node : nodeSegDur.children("S")) { - adpSet->SegmentTimelineDuration().GetData().emplace_back(XML::GetAttribUint32(node, "d")); + adpSet->SegmentTimelineDuration().emplace_back(XML::GetAttribUint32(node, "d")); } } @@ -875,8 +875,10 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, uint64_t segNumber = segList.GetStartNumber(); // If tag is present it could use a different timescale - bool isTsRescale = adpSet->GetSegDurationsTimescale() != NO_VALUE && - adpSet->GetSegDurationsTimescale() != segList.GetTimescale(); + const size_t TLDurationSize = adpSet->SegmentTimelineDuration().size(); + const bool isTLDurTsRescale = adpSet->HasSegmentTimelineDuration() && + adpSet->GetSegDurationsTimescale() != NO_VALUE && + adpSet->GetSegDurationsTimescale() != segList.GetTimescale(); for (xml_node node : nodeSeglist.children("SegmentURL")) { @@ -895,11 +897,10 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } uint64_t duration; - uint32_t* sdDuration = adpSet->SegmentTimelineDuration().Get(index); // tag is present - if (sdDuration) + if (TLDurationSize > 0 && index < TLDurationSize) { - duration = *sdDuration; - if (isTsRescale) + duration = adpSet->SegmentTimelineDuration()[index]; + if (isTLDurTsRescale) { duration = static_cast(static_cast(duration) / @@ -924,9 +925,9 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, uint64_t totalDur; if (adpSet->HasSegmentTimelineDuration()) { - auto& segTLData = adpSet->SegmentTimelineDuration().GetData(); + auto& segTLData = adpSet->SegmentTimelineDuration(); totalDur = std::accumulate(segTLData.begin(), segTLData.end(), 0ULL); - if (isTsRescale) + if (isTLDurTsRescale) { totalDur = static_cast(static_cast(totalDur) / @@ -1174,7 +1175,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } void adaptive::CDashTree::ParseTagSegmentTimeline(pugi::xml_node nodeSegTL, - CSpinCache& SCTimeline) + std::vector& SCTimeline) { uint64_t nextPts{0}; @@ -1186,22 +1187,22 @@ void adaptive::CDashTree::ParseTagSegmentTimeline(pugi::xml_node nodeSegTL, uint32_t repeat = XML::GetAttribUint32(node, "r"); repeat += 1; - if (SCTimeline.IsEmpty()) + if (SCTimeline.empty()) { nextPts = time; } else if (time > 0) { //Go back to the previous timestamp to calculate the real gap. - nextPts -= SCTimeline.GetData().back(); - SCTimeline.GetData().back() = static_cast(time - nextPts); + nextPts -= SCTimeline.back(); + SCTimeline.back() = static_cast(time - nextPts); nextPts = time; } if (duration > 0) { for (; repeat > 0; --repeat) { - SCTimeline.GetData().emplace_back(duration); + SCTimeline.emplace_back(duration); nextPts += duration; } } diff --git a/src/parser/DASHTree.h b/src/parser/DASHTree.h index 8648429ca..34d28d13b 100644 --- a/src/parser/DASHTree.h +++ b/src/parser/DASHTree.h @@ -68,7 +68,7 @@ class ATTR_DLL_LOCAL CDashTree : public adaptive::AdaptiveTree PLAYLIST::CPeriod* period); void ParseTagSegmentTimeline(pugi::xml_node parentNode, - PLAYLIST::CSpinCache& SCTimeline); + std::vector& SCTimeline); void ParseSegmentTemplate(pugi::xml_node node, PLAYLIST::CSegmentTemplate& segTpl); diff --git a/src/parser/SmoothTree.cpp b/src/parser/SmoothTree.cpp index 543284fab..8ccddc86e 100644 --- a/src/parser/SmoothTree.cpp +++ b/src/parser/SmoothTree.cpp @@ -229,11 +229,11 @@ void adaptive::CSmoothTree::ParseTagStreamIndex(pugi::xml_node nodeSI, uint64_t t{0}; if (XML::QueryAttrib(node, "t", t)) { - if (!adpSet->SegmentTimelineDuration().IsEmpty()) + if (!adpSet->SegmentTimelineDuration().empty()) { //Go back to the previous timestamp to calculate the real gap. - previousPts -= adpSet->SegmentTimelineDuration().GetData().back(); - adpSet->SegmentTimelineDuration().GetData().back() = static_cast(t - previousPts); + previousPts -= adpSet->SegmentTimelineDuration().back(); + adpSet->SegmentTimelineDuration().back() = static_cast(t - previousPts); } else { @@ -252,13 +252,13 @@ void adaptive::CSmoothTree::ParseTagStreamIndex(pugi::xml_node nodeSI, { while (repeatCount--) { - adpSet->SegmentTimelineDuration().GetData().emplace_back(duration); + adpSet->SegmentTimelineDuration().emplace_back(duration); previousPts += duration; } } } - if (adpSet->SegmentTimelineDuration().IsEmpty()) + if (adpSet->SegmentTimelineDuration().empty()) { LOG::LogF(LOGDEBUG, "No generated timeline, adaptation set skipped."); return; @@ -396,7 +396,7 @@ void adaptive::CSmoothTree::CreateSegmentTimeline() uint64_t nextStartPts = adpSet->GetStartPTS() - m_ptsBase; uint64_t index = 1; - for (uint32_t segDuration : adpSet->SegmentTimelineDuration().GetData()) + for (uint32_t segDuration : adpSet->SegmentTimelineDuration()) { CSegment seg; seg.startPTS_ = nextStartPts; From 369d632c072969054354bd5136e6ad9b9fdce767 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Mon, 1 Jul 2024 19:45:28 +0200 Subject: [PATCH 2/6] [AdaptiveTree] Removed CSpinCache / new CSegContainer --- src/common/AdaptiveStream.cpp | 10 +- src/common/AdaptiveTree.cpp | 2 +- src/common/AdaptiveUtils.cpp | 1 + src/common/AdaptiveUtils.h | 131 +---------------------- src/common/Representation.h | 20 ++-- src/common/Segment.cpp | 86 +++++++++++++++ src/common/Segment.h | 97 +++++++++++++++++ src/common/SegmentBase.cpp | 1 + src/common/SegmentList.cpp | 1 + src/parser/DASHTree.cpp | 10 +- src/parser/HLSTree.cpp | 4 +- src/parser/SmoothTree.cpp | 2 +- src/samplereader/SampleReaderFactory.cpp | 1 + src/test/TestDASHTree.cpp | 2 +- src/test/TestHLSTree.cpp | 8 +- 15 files changed, 217 insertions(+), 159 deletions(-) diff --git a/src/common/AdaptiveStream.cpp b/src/common/AdaptiveStream.cpp index f15daa431..f3b8f37c8 100644 --- a/src/common/AdaptiveStream.cpp +++ b/src/common/AdaptiveStream.cpp @@ -476,7 +476,7 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, seg.m_time = cue.pts; seg.range_begin_ = cue.pos_start; seg.range_end_ = cue.pos_end; - rep->SegmentTimeline().GetData().emplace_back(seg); + rep->SegmentTimeline().Add(seg); } return true; } @@ -541,7 +541,7 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, { seg.range_begin_ = seg.range_end_ + 1; seg.range_end_ = seg.range_begin_ + refs[i].m_ReferencedSize - 1; - rep->SegmentTimeline().GetData().emplace_back(seg); + rep->SegmentTimeline().Add(seg); seg.startPTS_ += refs[i].m_SubsegmentDuration; seg.m_endPts = seg.startPTS_ + refs[i].m_SubsegmentDuration; @@ -810,7 +810,7 @@ bool AdaptiveStream::ensureSegment() if (m_fixateInitialization) return false; - CSegment* nextSegment{nullptr}; + const CSegment* nextSegment{nullptr}; if (valid_segment_buffers_ > 0) { @@ -938,7 +938,7 @@ bool AdaptiveStream::ensureSegment() segPos = nextSegPos; else // Continue adding segments that follow the last one added in to the buffer { - CSegment* followSeg = + const CSegment* followSeg = current_rep_->GetNextSegment(segment_buffers_[available_segment_buffers_ - 1]->segment); if (followSeg) segPos = current_rep_->get_segment_pos(followSeg); @@ -1221,7 +1221,7 @@ bool AdaptiveStream::seek_time(double seek_seconds, bool preceeding, bool& needR ++choosen_seg; } - CSegment* old_seg = current_rep_->current_segment_; + const CSegment* old_seg = current_rep_->current_segment_; const CSegment* newSeg = current_rep_->get_segment(choosen_seg); if (newSeg) diff --git a/src/common/AdaptiveTree.cpp b/src/common/AdaptiveTree.cpp index 43d18436b..c5feb9bb3 100644 --- a/src/common/AdaptiveTree.cpp +++ b/src/common/AdaptiveTree.cpp @@ -114,7 +114,7 @@ namespace adaptive void AdaptiveTree::FreeSegments(CPeriod* period, CRepresentation* repr) { - for (auto& segment : repr->SegmentTimeline().GetData()) + for (const CSegment& segment : repr->SegmentTimeline()) { period->DecreasePSSHSetUsageCount(segment.pssh_set_); } diff --git a/src/common/AdaptiveUtils.cpp b/src/common/AdaptiveUtils.cpp index d60d5c41b..7fe9ab667 100644 --- a/src/common/AdaptiveUtils.cpp +++ b/src/common/AdaptiveUtils.cpp @@ -10,6 +10,7 @@ #include "AdaptiveStream.h" #include "Representation.h" +#include "utils/log.h" #include "utils/Utils.h" #include diff --git a/src/common/AdaptiveUtils.h b/src/common/AdaptiveUtils.h index addeda387..75dea1077 100644 --- a/src/common/AdaptiveUtils.h +++ b/src/common/AdaptiveUtils.h @@ -9,13 +9,11 @@ #pragma once #include -#include #include +#include #include #include -#include "utils/log.h" - // forwards class AP4_Movie; namespace adaptive @@ -119,133 +117,6 @@ bool ParseRangeValues(std::string_view range, AP4_Movie* CreateMovieAtom(adaptive::AdaptiveStream& adStream, kodi::addon::InputstreamInfo& streamInfo); -template -class CSpinCache -{ -public: - /*! - * \brief Get the value pointer from the specified position - * \param pos The position of - * \return value pointer, otherwise nullptr if not found - */ - const T* Get(size_t pos) const - { - if (pos == SEGMENT_NO_POS || m_data.empty()) - return nullptr; - - if (pos >= m_data.size()) - { - LOG::LogF(LOGWARNING, "Position out-of-range (%zu of %zu)", pos, m_data.size()); - return nullptr; - } - - return &m_data[pos]; - } - - /*! - * \brief Get the value pointer from the specified position - * \param pos The position of - * \return value pointer, otherwise nullptr if not found - */ - T* Get(size_t pos) - { - if (pos == SEGMENT_NO_POS || m_data.empty()) - return nullptr; - - if (pos >= m_data.size()) - { - LOG::LogF(LOGWARNING, "Position out-of-range (%zu of %zu)", pos, m_data.size()); - return nullptr; - } - - return &m_data[pos]; - } - - /*! - * \brief Get the last value pointer - * \return value pointer, otherwise nullptr if not found - */ - T* GetBack() - { - if (m_data.empty()) - return nullptr; - - return &m_data.back(); - } - - /*! - * \brief Get the first value pointer - * \return value pointer, otherwise nullptr if not found - */ - T* GetFront() - { - if (m_data.empty()) - return nullptr; - - return &m_data.front(); - } - - /*! - * \brief Get index position of value pointer - * \param elem The pointer to get the position - * \return The index position, or SEGMENT_NO_POS if not found - */ - const size_t GetPosition(const T* elem) const - { - for (size_t i = 0; i < m_data.size(); ++i) - { - if (&m_data[i] == elem) - return i; - } - - return SEGMENT_NO_POS; - }; - - /*! - * \brief Append value to the container, by increasing the count. - * \param elem The value to append - */ - void Append(const T& elem) - { - m_data.emplace_back(elem); - m_appendCount += 1; - } - - void Swap(CSpinCache& other) - { - m_data.swap(other.m_data); - std::swap(m_appendCount, other.m_appendCount); - } - - void Clear() - { - m_data.clear(); - m_appendCount = 0; - } - - bool IsEmpty() const { return m_data.empty(); } - - /*! - * \brief Get the number of the appended elements. - * \return The number of appended elements. - */ - size_t GetAppendCount() const { return m_appendCount; } - - size_t GetSize() const { return m_data.size(); } - - /*! - * \brief Get the number of elements without taking into account those appended. - * \return The number of elements. - */ - size_t GetInitialSize() const { return m_data.size() - m_appendCount; } - - std::deque& GetData() { return m_data; } - -private: - std::deque m_data; - size_t m_appendCount{0}; // Number of appended elements -}; - // \brief Get the position of a pointer within a vector of unique_ptr template size_t GetPtrPosition(const std::vector>& container, const Ptr* ptr) diff --git a/src/common/Representation.h b/src/common/Representation.h index 396211f01..67f768a14 100644 --- a/src/common/Representation.h +++ b/src/common/Representation.h @@ -103,8 +103,8 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA uint16_t GetHdcpVersion() const { return m_hdcpVersion; } void SetHdcpVersion(uint16_t hdcpVersion) { m_hdcpVersion = hdcpVersion; } - CSpinCache& SegmentTimeline() { return m_segmentTimeline; } - CSpinCache SegmentTimeline() const { return m_segmentTimeline; } + CSegContainer& SegmentTimeline() { return m_segmentTimeline; } + CSegContainer SegmentTimeline() const { return m_segmentTimeline; } bool HasSegmentTimeline() { return !m_segmentTimeline.IsEmpty(); } std::optional& GetSegmentBase() { return m_segmentBase; } @@ -175,7 +175,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA size_t expired_segments_{0}; - CSegment* current_segment_{nullptr}; + const CSegment* current_segment_{nullptr}; bool HasInitSegment() const { return m_initSegment.has_value(); } @@ -227,7 +227,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA return m_segmentTimeline.IsEmpty() ? 0 : m_segmentTimeline.GetPosition(segment); } - CSegment* GetSegment(const CSegment& segment) + const CSegment* GetSegment(const CSegment& segment) { // If available, find the segment by number, this is because some // live services provide inconsistent timestamps between manifest updates @@ -236,7 +236,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA { const uint64_t number = segment.m_number; - for (CSegment& segment : m_segmentTimeline.GetData()) + for (const CSegment& segment : m_segmentTimeline) { if (segment.m_number == number) return &segment; @@ -246,7 +246,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA { const uint64_t startPTS = segment.startPTS_; - for (CSegment& segment : m_segmentTimeline.GetData()) + for (const CSegment& segment : m_segmentTimeline) { // Search by >= is intended to allow minimizing problems with encoders // that provide inconsistent timestamps between manifest updates @@ -258,7 +258,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA return nullptr; } - CSegment* GetNextSegment(const CSegment& segment) + const CSegment* GetNextSegment(const CSegment& segment) { // If available, find the segment by number, this is because some // live services provide inconsistent timestamps between manifest updates @@ -267,7 +267,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA { const uint64_t number = segment.m_number; - for (CSegment& segment : m_segmentTimeline.GetData()) + for (const CSegment& segment : m_segmentTimeline) { if (segment.m_number > number) return &segment; @@ -277,7 +277,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA { const uint64_t startPTS = segment.startPTS_; - for (CSegment& segment : m_segmentTimeline.GetData()) + for (const CSegment& segment : m_segmentTimeline) { if (segment.startPTS_ > startPTS) return &segment; @@ -355,7 +355,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA uint64_t m_startNumber{1}; - CSpinCache m_segmentTimeline; + CSegContainer m_segmentTimeline; uint64_t m_duration{0}; uint32_t m_timescale{0}; diff --git a/src/common/Segment.cpp b/src/common/Segment.cpp index f6a0b77b8..2980d3716 100644 --- a/src/common/Segment.cpp +++ b/src/common/Segment.cpp @@ -7,3 +7,89 @@ */ #include "Segment.h" +#include "utils/log.h" + +using namespace PLAYLIST; + +const CSegment* PLAYLIST::CSegContainer::Get(size_t pos) const +{ + if (pos == SEGMENT_NO_POS || m_segments.empty()) + return nullptr; + + if (pos >= m_segments.size()) + { + LOG::LogF(LOGWARNING, "Position out-of-range (%zu of %zu)", pos, m_segments.size()); + return nullptr; + } + + return &m_segments[pos]; +} + +CSegment* PLAYLIST::CSegContainer::Get(size_t pos) +{ + if (pos == SEGMENT_NO_POS || m_segments.empty()) + return nullptr; + + if (pos >= m_segments.size()) + { + LOG::LogF(LOGWARNING, "Position out-of-range (%zu of %zu)", pos, m_segments.size()); + return nullptr; + } + + return &m_segments[pos]; +} + +CSegment* PLAYLIST::CSegContainer::GetBack() +{ + if (m_segments.empty()) + return nullptr; + + return &m_segments.back(); +} + +CSegment* PLAYLIST::CSegContainer::GetFront() +{ + if (m_segments.empty()) + return nullptr; + + return &m_segments.front(); +} + +const size_t PLAYLIST::CSegContainer::GetPosition(const CSegment* elem) const +{ + for (size_t i = 0; i < m_segments.size(); ++i) + { + if (&m_segments[i] == elem) + return i; + } + + return SEGMENT_NO_POS; +} + +void PLAYLIST::CSegContainer::Add(const CSegment& elem) +{ + m_duration += elem.m_endPts - elem.startPTS_; + m_segments.emplace_back(elem); +} + +void PLAYLIST::CSegContainer::Append(const CSegment& elem) +{ + m_duration += elem.m_endPts - elem.startPTS_; + m_segments.emplace_back(elem); + m_appendCount += 1; +} + +void PLAYLIST::CSegContainer::Swap(CSegContainer& other) +{ + m_segments.swap(other.m_segments); + std::swap(m_appendCount, other.m_appendCount); + std::swap(m_duration, other.m_duration); +} + +void PLAYLIST::CSegContainer::Clear() +{ + m_segments.clear(); + m_appendCount = 0; + m_duration = 0; +} + diff --git a/src/common/Segment.h b/src/common/Segment.h index 58a1b2723..03e46e717 100644 --- a/src/common/Segment.h +++ b/src/common/Segment.h @@ -17,8 +17,10 @@ #endif #include +#include #include #include +#include namespace PLAYLIST { @@ -60,4 +62,99 @@ class ATTR_DLL_LOCAL CSegment bool m_isInitialization{false}; }; +class ATTR_DLL_LOCAL CSegContainer +{ +public: + CSegContainer() = default; + ~CSegContainer() = default; + + /*! + * \brief Get the segment pointer from the specified position + * \param pos The position of segment + * \return Segment pointer, otherwise nullptr if not found + */ + const CSegment* Get(size_t pos) const; + + /*! + * \brief Get the segment pointer from the specified position + * \param pos The position of segment + * \return Segment pointer, otherwise nullptr if not found + */ + CSegment* Get(size_t pos); + + /*! + * \brief Get the last segment pointer + * \return Segment pointer, otherwise nullptr if not found + */ + CSegment* GetBack(); + + /*! + * \brief Get the first segment as pointer + * \return Segment pointer, otherwise nullptr if not found + */ + CSegment* GetFront(); + + /*! + * \brief Get index position of a segment pointer + * \param elem The segment pointer to get the position + * \return The index position, or SEGMENT_NO_POS if not found + */ + const size_t GetPosition(const CSegment* elem) const; + + /*! + * \brief Add a segment to the container. + * \param elem The segment to add + */ + void Add(const CSegment& elem); + + /*! + * \brief Append segment to the container, by increasing the count. + * \param elem The segment to append + */ + void Append(const CSegment& elem); + + void Swap(CSegContainer& other); + + /*! + * \brief Delete all segments and clear the properties. + */ + void Clear(); + + bool IsEmpty() const { return m_segments.empty(); } + + /*! + * \brief Get the number of the appended segments. + * \return The number of appended segments. + */ + size_t GetAppendCount() const { return m_appendCount; } + + /*! + * \brief Get the number of segments. + * \return The number of segments. + */ + size_t GetSize() const { return m_segments.size(); } + + /*! + * \brief Get the number of elements without taking into account those appended. + * \return The number of elements. + */ + size_t GetInitialSize() const { return m_segments.size() - m_appendCount; } + + /*! + * \brief Get the duration of all segments. + * \return The duration of all segments. + */ + uint64_t GetDuration() const { return m_duration; } + + std::deque::const_iterator begin() const { return m_segments.begin(); } + std::deque::const_iterator end() const { return m_segments.end(); } + +private: + // Has been used std::deque because there are uses of pointer references + // deque container keeps memory addresses even if the container size increases (no reallocations) + std::deque m_segments; + size_t m_appendCount{0}; // Number of appended segments + uint64_t m_duration{0}; // Sum of the duration of all segments +}; + } // namespace PLAYLIST diff --git a/src/common/SegmentBase.cpp b/src/common/SegmentBase.cpp index c4688c41f..9e0bee192 100644 --- a/src/common/SegmentBase.cpp +++ b/src/common/SegmentBase.cpp @@ -10,6 +10,7 @@ #include "AdaptiveUtils.h" #include "Segment.h" +#include "utils/log.h" using namespace PLAYLIST; diff --git a/src/common/SegmentList.cpp b/src/common/SegmentList.cpp index 7ed5994bb..25f114518 100644 --- a/src/common/SegmentList.cpp +++ b/src/common/SegmentList.cpp @@ -8,6 +8,7 @@ #include "SegmentList.h" #include "Segment.h" +#include "utils/log.h" using namespace PLAYLIST; diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index 5b8d80fd8..d68706b87 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -915,7 +915,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, seg.m_time = segStartPts; seg.m_number = segNumber++; - repr->SegmentTimeline().GetData().push_back(seg); + repr->SegmentTimeline().Add(seg); segStartPts += duration; index++; @@ -1080,7 +1080,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, seg.m_time = time; totalDuration += tlElem.duration; - repr->SegmentTimeline().GetData().emplace_back(seg); + repr->SegmentTimeline().Add(seg); time += tlElem.duration; } while (repeat-- > 0); @@ -1158,7 +1158,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, seg.m_time = time; - repr->SegmentTimeline().GetData().emplace_back(seg); + repr->SegmentTimeline().Add(seg); time = seg.m_endPts; } @@ -1701,10 +1701,10 @@ void adaptive::CDashTree::OnUpdateSegments() continue; } - CSegment* foundSeg{nullptr}; + const CSegment* foundSeg{nullptr}; const uint64_t segStartPTS = repr->current_segment_->startPTS_; - for (CSegment& segment : updRepr->SegmentTimeline().GetData()) + for (const CSegment& segment : updRepr->SegmentTimeline()) { if (segment.startPTS_ == segStartPTS) { diff --git a/src/parser/HLSTree.cpp b/src/parser/HLSTree.cpp index 7ab48b27c..31f208a5a 100644 --- a/src/parser/HLSTree.cpp +++ b/src/parser/HLSTree.cpp @@ -462,7 +462,7 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, uint64_t mediaSequenceNbr{0}; - CSpinCache newSegments; + CSegContainer newSegments; std::optional newSegment; // Pssh set used between segments @@ -701,7 +701,7 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, } newSegment->pssh_set_ = psshSetPos; - newSegments.GetData().emplace_back(*newSegment); + newSegments.Add(*newSegment); newSegment.reset(); } else if (tagName == "#EXT-X-DISCONTINUITY-SEQUENCE") diff --git a/src/parser/SmoothTree.cpp b/src/parser/SmoothTree.cpp index 8ccddc86e..73fdf5467 100644 --- a/src/parser/SmoothTree.cpp +++ b/src/parser/SmoothTree.cpp @@ -404,7 +404,7 @@ void adaptive::CSmoothTree::CreateSegmentTimeline() seg.m_time = nextStartPts + m_ptsBase; seg.m_number = index; - repr->SegmentTimeline().GetData().emplace_back(seg); + repr->SegmentTimeline().Add(seg); nextStartPts += segDuration; index++; diff --git a/src/samplereader/SampleReaderFactory.cpp b/src/samplereader/SampleReaderFactory.cpp index d451b1d50..8a44655ea 100644 --- a/src/samplereader/SampleReaderFactory.cpp +++ b/src/samplereader/SampleReaderFactory.cpp @@ -16,6 +16,7 @@ #include "samplereader/SubtitleSampleReader.h" #include "samplereader/TSSampleReader.h" #include "samplereader/WebmSampleReader.h" +#include "utils/log.h" #include diff --git a/src/test/TestDASHTree.cpp b/src/test/TestDASHTree.cpp index 3e2dcf51e..e6ca74ba3 100644 --- a/src/test/TestDASHTree.cpp +++ b/src/test/TestDASHTree.cpp @@ -601,7 +601,7 @@ TEST_F(DASHTreeAdaptiveStreamTest, MisalignedSegmentTimeline) auto& repr = tree->m_currentPeriod->GetAdaptationSets()[1]->GetRepresentations()[0]; // Set the last segment to the current segment to simulate reaching the last segment - repr->current_segment_ = &repr->SegmentTimeline().GetData().back(); + repr->current_segment_ = repr->SegmentTimeline().GetBack(); EXPECT_EQ(repr->current_segment_->startPTS_, 95687379264); EXPECT_EQ(repr->getCurrentSegmentPos(), 4); diff --git a/src/test/TestHLSTree.cpp b/src/test/TestHLSTree.cpp index bd8f01664..c4e4c9552 100644 --- a/src/test/TestHLSTree.cpp +++ b/src/test/TestHLSTree.cpp @@ -292,8 +292,8 @@ TEST_F(HLSTreeTest, PtsSetInMultiPeriod) auto& periodSecond = tree->m_periods[1]; auto& adp0rep1 = periodSecond->GetAdaptationSets()[0]->GetRepresentations()[0]; - auto& adp0rep1seg1 = adp0rep1->SegmentTimeline().GetData().front(); - EXPECT_EQ(adp0rep1seg1.startPTS_, 0); + auto adp0rep1seg1 = adp0rep1->SegmentTimeline().GetFront(); + EXPECT_EQ(adp0rep1seg1->startPTS_, 0); } { auto& periodFirst = tree->m_periods[0]; @@ -308,8 +308,8 @@ TEST_F(HLSTreeTest, PtsSetInMultiPeriod) auto& periodSecond = tree->m_periods[1]; auto& adp1rep0 = periodSecond->GetAdaptationSets()[1]->GetRepresentations()[0]; - auto& adp1rep0seg1 = adp1rep0->SegmentTimeline().GetData().front(); - EXPECT_EQ(adp1rep0seg1.startPTS_, 0); + auto adp1rep0seg1 = adp1rep0->SegmentTimeline().GetFront(); + EXPECT_EQ(adp1rep0seg1->startPTS_, 0); } } From f9f5892fa7ff73b7ace516b91ffe724a498a39bd Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Mon, 1 Jul 2024 15:03:06 +0200 Subject: [PATCH 3/6] [Representation] Renamed SegmentTimeline to Timeline --- src/Session.cpp | 2 +- src/common/AdaptiveStream.cpp | 46 +++++++++++++++++------------------ src/common/AdaptiveTree.cpp | 8 +++--- src/common/Representation.h | 11 ++++++--- src/parser/DASHTree.cpp | 34 +++++++++++++------------- src/parser/HLSTree.cpp | 24 +++++++++--------- src/parser/SmoothTree.cpp | 6 ++--- src/test/TestDASHTree.cpp | 28 ++++++++++----------- src/test/TestHLSTree.cpp | 4 +-- src/test/TestSmoothTree.cpp | 6 ++--- 10 files changed, 87 insertions(+), 82 deletions(-) diff --git a/src/Session.cpp b/src/Session.cpp index 1a5e07125..9186462f2 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -938,7 +938,7 @@ void CSession::PrepareStream(CStream* stream) // Prepare the representation when the period change usually its not needed, // because the timeline is always already updated - if ((!m_adaptiveTree->IsChangingPeriod() || !repr->HasSegmentTimeline()) && + if ((!m_adaptiveTree->IsChangingPeriod() || !repr->Timeline().IsEmpty()) && (startEvent == EVENT_TYPE::STREAM_START || startEvent == EVENT_TYPE::STREAM_ENABLE)) { m_adaptiveTree->PrepareRepresentation(stream->m_adStream.getPeriod(), diff --git a/src/common/AdaptiveStream.cpp b/src/common/AdaptiveStream.cpp index f3b8f37c8..96c7c692e 100644 --- a/src/common/AdaptiveStream.cpp +++ b/src/common/AdaptiveStream.cpp @@ -476,7 +476,7 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, seg.m_time = cue.pts; seg.range_begin_ = cue.pos_start; seg.range_end_ = cue.pos_end; - rep->SegmentTimeline().Add(seg); + rep->Timeline().Add(seg); } return true; } @@ -541,7 +541,7 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, { seg.range_begin_ = seg.range_end_ + 1; seg.range_end_ = seg.range_begin_ + refs[i].m_ReferencedSize - 1; - rep->SegmentTimeline().Add(seg); + rep->Timeline().Add(seg); seg.startPTS_ += refs[i].m_SubsegmentDuration; seg.m_endPts = seg.startPTS_ + refs[i].m_SubsegmentDuration; @@ -631,7 +631,7 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) thread_data_->signal_dl_.wait(lckdl); } - if (current_rep_->SegmentTimeline().IsEmpty()) + if (current_rep_->Timeline().IsEmpty()) { // GenerateSidxSegments assumes mutex_dl locked std::lock_guard lck(thread_data_->mutex_dl_); @@ -666,9 +666,9 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) { if (m_startEvent == EVENT_TYPE::STREAM_START && m_tree->IsLive() && !m_tree->IsChangingPeriod() && !CSrvBroker::GetKodiProps().IsPlayTimeshift() && - !current_rep_->SegmentTimeline().IsEmpty()) + !current_rep_->Timeline().IsEmpty()) { - size_t segPos = current_rep_->SegmentTimeline().GetSize() - 1; + size_t segPos = current_rep_->Timeline().GetSize() - 1; //! @todo: segment duration is not fixed for each segment, this can calculate a wrong delay uint64_t segDur = current_rep_->get_segment(segPos)->m_endPts - current_rep_->get_segment(segPos)->startPTS_; @@ -690,9 +690,9 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) else if (m_startEvent == EVENT_TYPE::REP_CHANGE) // switching streams, align new stream segment no. { uint64_t segmentId = segment_buffers_[0]->segment_number; - if (segmentId >= current_rep_->GetStartNumber() + current_rep_->SegmentTimeline().GetSize()) + if (segmentId >= current_rep_->GetStartNumber() + current_rep_->Timeline().GetSize()) { - segmentId = current_rep_->GetStartNumber() + current_rep_->SegmentTimeline().GetSize() - 1; + segmentId = current_rep_->GetStartNumber() + current_rep_->Timeline().GetSize() - 1; } current_rep_->current_segment_ = current_rep_->get_segment( static_cast(segmentId - current_rep_->GetStartNumber())); @@ -752,7 +752,7 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) valid_segment_buffers_ = valid_segment_buffers + 1; } - if (!current_rep_->SegmentTimeline().Get(0)) + if (!current_rep_->Timeline().Get(0)) { LOG::LogF(LOGERROR, "[AS-%u] Segment at position 0 not found from representation id: %s", clsId, current_rep_->GetId().data()); @@ -764,7 +764,7 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) currentPTSOffset_ = (next_segment->startPTS_ * current_rep_->timescale_ext_) / current_rep_->timescale_int_; absolutePTSOffset_ = - (current_rep_->SegmentTimeline().Get(0)->startPTS_ * current_rep_->timescale_ext_) / + (current_rep_->Timeline().Get(0)->startPTS_ * current_rep_->timescale_ext_) / current_rep_->timescale_int_; } @@ -879,7 +879,7 @@ bool AdaptiveStream::ensureSegment() (nextSegment->startPTS_ * current_rep_->timescale_ext_) / current_rep_->timescale_int_; absolutePTSOffset_ = - (current_rep_->SegmentTimeline().Get(0)->startPTS_ * current_rep_->timescale_ext_) / + (current_rep_->Timeline().Get(0)->startPTS_ * current_rep_->timescale_ext_) / current_rep_->timescale_int_; current_rep_->current_segment_ = nextSegment; @@ -903,7 +903,7 @@ bool AdaptiveStream::ensureSegment() CRepresentation* prevRep = segment_buffers_[available_segment_buffers_ - 1]->rep; bool isLastSegment = nextSegPos + available_segment_buffers_ == - current_rep_->SegmentTimeline().GetSize() - 1; + current_rep_->Timeline().GetSize() - 1; // Dont change representation if it is the last segment of a period otherwise when it comes // the time to play the last segment in a period, AdaptiveStream wasn't able to insert the // initialization segment (in the case of fMP4) and you would get corrupted or blank video @@ -924,14 +924,14 @@ bool AdaptiveStream::ensureSegment() m_tree->OnStreamChange(current_period_, current_adp_, current_rep_, newRep); // If the representation has been changed, segments may have to be generated (DASH) - if (newRep->SegmentTimeline().IsEmpty()) + if (newRep->Timeline().IsEmpty()) GenerateSidxSegments(newRep); } } // Add to the buffer next segment (and the next following segments, if available) - const size_t maxPos = newRep->SegmentTimeline().GetSize(); + const size_t maxPos = newRep->Timeline().GetSize(); size_t segPos; if (available_segment_buffers_ == 0) // Buffer empty, add the current segment @@ -1095,19 +1095,19 @@ bool AdaptiveStream::retrieveCurrentSegmentBufferSize(size_t& size) uint64_t AdaptiveStream::getMaxTimeMs() { - if (current_rep_->SegmentTimeline().IsEmpty()) + if (current_rep_->Timeline().IsEmpty()) return 0; uint64_t duration{0}; - if (current_rep_->SegmentTimeline().GetSize() > 1) + if (current_rep_->Timeline().GetSize() > 1) { duration = - current_rep_->SegmentTimeline().Get(current_rep_->SegmentTimeline().GetSize() - 1)->startPTS_ - - current_rep_->SegmentTimeline().Get(current_rep_->SegmentTimeline().GetSize() - 2)->startPTS_; + current_rep_->Timeline().Get(current_rep_->Timeline().GetSize() - 1)->startPTS_ - + current_rep_->Timeline().Get(current_rep_->Timeline().GetSize() - 2)->startPTS_; } - uint64_t timeExt = ((current_rep_->SegmentTimeline() - .Get(current_rep_->SegmentTimeline().GetSize() - 1) + uint64_t timeExt = ((current_rep_->Timeline() + .Get(current_rep_->Timeline().GetSize() - 1) ->startPTS_ + duration) * current_rep_->timescale_ext_) / @@ -1186,22 +1186,22 @@ bool AdaptiveStream::seek_time(double seek_seconds, bool preceeding, bool& needR //Skip initialization size_t choosen_seg{0}; - while (choosen_seg < current_rep_->SegmentTimeline().GetSize() && + while (choosen_seg < current_rep_->Timeline().GetSize() && sec_in_ts > current_rep_->get_segment(choosen_seg)->startPTS_) { ++choosen_seg; } - if (choosen_seg == current_rep_->SegmentTimeline().GetSize()) + if (choosen_seg == current_rep_->Timeline().GetSize()) { - if (!current_rep_->SegmentTimeline().Get(0)) + if (!current_rep_->Timeline().Get(0)) { LOG::LogF(LOGERROR, "[AS-%u] Segment at position 0 not found from representation id: %s", clsId, current_rep_->GetId().data()); return false; } - if (sec_in_ts < current_rep_->SegmentTimeline().Get(0)->startPTS_ + current_rep_->GetDuration()) + if (sec_in_ts < current_rep_->Timeline().Get(0)->startPTS_ + current_rep_->GetDuration()) --choosen_seg; else return false; diff --git a/src/common/AdaptiveTree.cpp b/src/common/AdaptiveTree.cpp index c5feb9bb3..454d047bf 100644 --- a/src/common/AdaptiveTree.cpp +++ b/src/common/AdaptiveTree.cpp @@ -114,12 +114,12 @@ namespace adaptive void AdaptiveTree::FreeSegments(CPeriod* period, CRepresentation* repr) { - for (const CSegment& segment : repr->SegmentTimeline()) + for (const CSegment& segment : repr->Timeline()) { period->DecreasePSSHSetUsageCount(segment.pssh_set_); } - repr->SegmentTimeline().Clear(); + repr->Timeline().Clear(); repr->current_segment_ = nullptr; } @@ -189,7 +189,7 @@ namespace adaptive const PLAYLIST::CRepresentation* segRep, const PLAYLIST::CSegment* segment) const { - if (segRep->SegmentTimeline().IsEmpty()) + if (segRep->Timeline().IsEmpty()) return true; if (!segment || !segPeriod || !segRep) @@ -212,7 +212,7 @@ namespace adaptive } else { - const CSegment* lastSeg = segRep->SegmentTimeline().GetBack(); + const CSegment* lastSeg = segRep->Timeline().GetBack(); return segment == lastSeg; } return false; diff --git a/src/common/Representation.h b/src/common/Representation.h index 67f768a14..a8ec58850 100644 --- a/src/common/Representation.h +++ b/src/common/Representation.h @@ -103,9 +103,14 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA uint16_t GetHdcpVersion() const { return m_hdcpVersion; } void SetHdcpVersion(uint16_t hdcpVersion) { m_hdcpVersion = hdcpVersion; } - CSegContainer& SegmentTimeline() { return m_segmentTimeline; } - CSegContainer SegmentTimeline() const { return m_segmentTimeline; } - bool HasSegmentTimeline() { return !m_segmentTimeline.IsEmpty(); } + /*! + * \brief The segment timeline. + */ + CSegContainer& Timeline() { return m_segmentTimeline; } + /*! + * \brief The segment timeline. + */ + CSegContainer Timeline() const { return m_segmentTimeline; } std::optional& GetSegmentBase() { return m_segmentBase; } void SetSegmentBase(const CSegmentBase& segBase) { m_segmentBase = segBase; } diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index d68706b87..ff519c96d 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -915,7 +915,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, seg.m_time = segStartPts; seg.m_number = segNumber++; - repr->SegmentTimeline().Add(seg); + repr->Timeline().Add(seg); segStartPts += duration; index++; @@ -936,7 +936,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } else { - totalDur = static_cast(repr->SegmentTimeline().GetSize()) * segList.GetDuration(); + totalDur = static_cast(repr->Timeline().GetSize()) * segList.GetDuration(); } repr->SetDuration(totalDur); @@ -1013,7 +1013,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } if (repr->GetContainerType() == ContainerType::TEXT && repr->GetMimeType() != "application/mp4" && - !repr->HasSegmentBase() && !repr->HasSegmentTemplate() && !repr->HasSegmentTimeline()) + !repr->HasSegmentBase() && !repr->HasSegmentTemplate() && !repr->Timeline().IsEmpty()) { // Raw unsegmented subtitles called "sidecar" is a single file specified in the tag, // must not have the MP4 ISOBMFF mime type or any other dash element. @@ -1021,7 +1021,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } // Generate segments from SegmentTemplate - if (repr->HasSegmentTemplate() && !repr->HasSegmentTimeline()) + if (repr->HasSegmentTemplate() && !repr->Timeline().IsEmpty()) { auto& segTemplate = repr->GetSegmentTemplate(); @@ -1080,7 +1080,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, seg.m_time = time; totalDuration += tlElem.duration; - repr->SegmentTimeline().Add(seg); + repr->Timeline().Add(seg); time += tlElem.duration; } while (repeat-- > 0); @@ -1158,7 +1158,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, seg.m_time = time; - repr->SegmentTimeline().Add(seg); + repr->Timeline().Add(seg); time = seg.m_endPts; } @@ -1675,7 +1675,7 @@ void adaptive::CDashTree::OnUpdateSegments() { auto repr = (*itRepr).get(); - if (updRepr->SegmentTimeline().IsEmpty()) + if (updRepr->Timeline().IsEmpty()) { LOG::LogF(LOGWARNING, "MPD update - Updated timeline has no segments " @@ -1684,16 +1684,16 @@ void adaptive::CDashTree::OnUpdateSegments() continue; } - if (!repr->SegmentTimeline().IsEmpty()) + if (!repr->Timeline().IsEmpty()) { if (!repr->current_segment_) // Representation that should not be used for playback { - repr->SegmentTimeline().Swap(updRepr->SegmentTimeline()); + repr->Timeline().Swap(updRepr->Timeline()); } else { - if (repr->SegmentTimeline().GetInitialSize() == updRepr->SegmentTimeline().GetSize() && - repr->SegmentTimeline().Get(0)->startPTS_ == updRepr->SegmentTimeline().Get(0)->startPTS_) + if (repr->Timeline().GetInitialSize() == updRepr->Timeline().GetSize() && + repr->Timeline().Get(0)->startPTS_ == updRepr->Timeline().Get(0)->startPTS_) { LOG::LogF(LOGDEBUG, "MPD update - No new segments (repr. id \"%s\", period id \"%s\")", @@ -1704,7 +1704,7 @@ void adaptive::CDashTree::OnUpdateSegments() const CSegment* foundSeg{nullptr}; const uint64_t segStartPTS = repr->current_segment_->startPTS_; - for (const CSegment& segment : updRepr->SegmentTimeline()) + for (const CSegment& segment : updRepr->Timeline()) { if (segment.startPTS_ == segStartPTS) { @@ -1736,7 +1736,7 @@ void adaptive::CDashTree::OnUpdateSegments() } else { - repr->SegmentTimeline().Swap(updRepr->SegmentTimeline()); + repr->Timeline().Swap(updRepr->Timeline()); repr->current_segment_ = foundSeg; LOG::LogF(LOGDEBUG, "MPD update - Done (repr. id \"%s\", period id \"%s\")", @@ -1801,7 +1801,7 @@ bool adaptive::CDashTree::InsertLiveSegment(PLAYLIST::CPeriod* period, //! @todo: expired_segments_ should be reworked, see also other parsers repr->expired_segments_++; - CSegment* segment = repr->SegmentTimeline().Get(pos); + CSegment* segment = repr->Timeline().Get(pos); if (!segment) { @@ -1822,7 +1822,7 @@ bool adaptive::CDashTree::InsertLiveSegment(PLAYLIST::CPeriod* period, for (auto& repr : adpSet->GetRepresentations()) { - repr->SegmentTimeline().Append(segCopy); + repr->Timeline().Append(segCopy); } return true; } @@ -1838,7 +1838,7 @@ bool adaptive::CDashTree::InsertLiveFragment(PLAYLIST::CAdaptationSet* adpSet, if (!m_isLive || !repr->HasSegmentTemplate() || m_minimumUpdatePeriod != NO_VALUE) return false; - CSegment* lastSeg = repr->SegmentTimeline().GetBack(); + CSegment* lastSeg = repr->Timeline().GetBack(); if (!lastSeg) return false; @@ -1867,7 +1867,7 @@ bool adaptive::CDashTree::InsertLiveFragment(PLAYLIST::CAdaptationSet* adpSet, for (auto& repr : adpSet->GetRepresentations()) { - repr->SegmentTimeline().Append(segCopy); + repr->Timeline().Append(segCopy); } return true; diff --git a/src/parser/HLSTree.cpp b/src/parser/HLSTree.cpp index 31f208a5a..fc382d281 100644 --- a/src/parser/HLSTree.cpp +++ b/src/parser/HLSTree.cpp @@ -186,7 +186,7 @@ bool adaptive::CHLSTree::PrepareRepresentation(PLAYLIST::CPeriod* period, PLAYLIST::CAdaptationSet* adp, PLAYLIST::CRepresentation* rep) { - if (!m_isLive && rep->HasSegmentTimeline()) + if (!m_isLive && rep->Timeline().IsEmpty()) return true; if (!ProcessChildManifest(period, adp, rep, SEGMENT_NO_NUMBER)) @@ -225,9 +225,9 @@ void adaptive::CHLSTree::FixMediaSequence(std::stringstream& streamData, { // Get the last segment PTS and number in the last period auto& lastPRep = m_periods.back()->GetAdaptationSets()[adpSetPos]->GetRepresentations()[reprPos]; - if (lastPRep->SegmentTimeline().IsEmpty()) + if (lastPRep->Timeline().IsEmpty()) return; - CSegment* lastSeg = lastPRep->SegmentTimeline().GetBack(); + CSegment* lastSeg = lastPRep->Timeline().GetBack(); uint64_t segStartPts = lastSeg->startPTS_; // The start PTS refer to date-time uint64_t segNumber = lastSeg->m_number; @@ -735,7 +735,7 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, { auto& pCurrAdp = m_currentPeriod->GetAdaptationSets()[adpSetPos]; auto& pCurrRep = pCurrAdp->GetRepresentations()[reprPos]; - pCurrRep->SegmentTimeline().Clear(); + pCurrRep->Timeline().Clear(); pCurrRep->current_segment_ = nullptr; LOG::Log(LOGDEBUG, "Clear outdated period of discontinuity %u", itPeriod->get()->GetSequence()); @@ -785,7 +785,7 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, } FreeSegments(period, rep); - rep->SegmentTimeline().Swap(newSegments); + rep->Timeline().Swap(newSegments); rep->SetStartNumber(mediaSequenceNbr); } @@ -793,7 +793,7 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, isSkipUntilDiscont = false; ++discontCount; - mediaSequenceNbr += rep->SegmentTimeline().GetSize(); + mediaSequenceNbr += rep->Timeline().GetSize(); currentSegNumber = mediaSequenceNbr; CPeriod* newPeriod = FindDiscontinuityPeriod(m_discontSeq + discontCount); @@ -880,12 +880,12 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, } FreeSegments(period, rep); - rep->SegmentTimeline().Swap(newSegments); + rep->Timeline().Swap(newSegments); rep->SetStartNumber(mediaSequenceNbr); uint64_t reprDur{0}; - if (rep->SegmentTimeline().Get(0)) - reprDur = rep->SegmentTimeline().GetBack()->m_endPts - rep->SegmentTimeline().GetFront()->startPTS_; + if (rep->Timeline().Get(0)) + reprDur = rep->Timeline().GetBack()->m_endPts - rep->Timeline().GetFront()->startPTS_; rep->SetDuration(reprDur); period->SetSequence(m_discontSeq + discontCount); @@ -929,9 +929,9 @@ void adaptive::CHLSTree::PrepareSegments(PLAYLIST::CPeriod* period, } else { - if (segNumber >= rep->GetStartNumber() + rep->SegmentTimeline().GetSize()) + if (segNumber >= rep->GetStartNumber() + rep->Timeline().GetSize()) { - segNumber = rep->GetStartNumber() + rep->SegmentTimeline().GetSize() - 1; + segNumber = rep->GetStartNumber() + rep->Timeline().GetSize() - 1; } rep->current_segment_ = @@ -1054,7 +1054,7 @@ void adaptive::CHLSTree::OnStreamChange(PLAYLIST::CPeriod* period, PLAYLIST::CRepresentation* previousRep, PLAYLIST::CRepresentation* currentRep) { - if (!m_isLive && currentRep->HasSegmentTimeline()) + if (!m_isLive && currentRep->Timeline().IsEmpty()) return; const uint64_t currentSegNumber = previousRep->getCurrentSegmentNumber(); diff --git a/src/parser/SmoothTree.cpp b/src/parser/SmoothTree.cpp index 73fdf5467..eb60f46ea 100644 --- a/src/parser/SmoothTree.cpp +++ b/src/parser/SmoothTree.cpp @@ -404,7 +404,7 @@ void adaptive::CSmoothTree::CreateSegmentTimeline() seg.m_time = nextStartPts + m_ptsBase; seg.m_number = index; - repr->SegmentTimeline().Add(seg); + repr->Timeline().Add(seg); nextStartPts += segDuration; index++; @@ -427,7 +427,7 @@ bool adaptive::CSmoothTree::InsertLiveFragment(PLAYLIST::CAdaptationSet* adpSet, //! then add a better way to delete old segments from the timeline based on timeshift window //! this also requires taking care of the Dash parser - CSegment* lastSeg = repr->SegmentTimeline().GetBack(); + CSegment* lastSeg = repr->Timeline().GetBack(); if (!lastSeg) return false; @@ -458,7 +458,7 @@ bool adaptive::CSmoothTree::InsertLiveFragment(PLAYLIST::CAdaptationSet* adpSet, for (auto& repr : adpSet->GetRepresentations()) { - repr->SegmentTimeline().Append(segCopy); + repr->Timeline().Append(segCopy); } return true; diff --git a/src/test/TestDASHTree.cpp b/src/test/TestDASHTree.cpp index e6ca74ba3..6ab85b5cb 100644 --- a/src/test/TestDASHTree.cpp +++ b/src/test/TestDASHTree.cpp @@ -270,7 +270,7 @@ TEST_F(DASHTreeTest, CalculateCorrectSegmentNumbersFromSegmentTimeline) OpenTestFile("mpd/segtimeline_live_ast.mpd"); auto& segments = - tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(segments.GetSize(), 13); EXPECT_EQ(segments.Get(0)->m_number, 487050); @@ -283,7 +283,7 @@ TEST_F(DASHTreeTest, CalculateCorrectSegmentNumbersFromSegmentTemplateWithPTO) OpenTestFile("mpd/segtpl_pto.mpd"); - auto& segments = tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + auto& segments = tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(segments.GetSize(), 450); EXPECT_EQ(segments.Get(0)->m_number, 404314437); @@ -295,7 +295,7 @@ TEST_F(DASHTreeTest, CalculateCorrectSegmentNumbersFromSegmentTemplateWithOldPub OpenTestFile("mpd/segtpl_old_publish_time.mpd"); - auto& segments = tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + auto& segments = tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(segments.GetSize(), 30); EXPECT_EQ(segments.Get(0)->m_number, 603271); @@ -492,22 +492,22 @@ TEST_F(DASHTreeTest, CalculateMultipleSegTpl) EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[0]->GetSegmentTemplate()->GetInitialization()), "3c1055cb-a842-4449-b393-7f31693b4a8f_1_448x252init.mp4"); EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[0]->GetSegmentTemplate()->GetMedia()), "3c1055cb-a842-4449-b393-7f31693b4a8f_1_448x252_$Number%09d$.mp4"); EXPECT_EQ(adpSets[0]->GetRepresentations()[0]->GetSegmentTemplate()->GetTimescale(), 120000); - EXPECT_EQ(adpSets[0]->GetRepresentations()[0]->SegmentTimeline().Get(0)->m_number, 3); + EXPECT_EQ(adpSets[0]->GetRepresentations()[0]->Timeline().Get(0)->m_number, 3); EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[1]->GetSegmentTemplate()->GetInitialization()), "3c1055cb-a842-4449-b393-7f31693b4a8f_2_1920x1080init.mp4"); EXPECT_EQ(STR(adpSets[0]->GetRepresentations()[1]->GetSegmentTemplate()->GetMedia()), "3c1055cb-a842-4449-b393-7f31693b4a8f_2_1920x1080_$Number%09d$.mp4"); EXPECT_EQ(adpSets[0]->GetRepresentations()[1]->GetSegmentTemplate()->GetTimescale(), 90000); - EXPECT_EQ(adpSets[0]->GetRepresentations()[1]->SegmentTimeline().Get(0)->m_number, 5); + EXPECT_EQ(adpSets[0]->GetRepresentations()[1]->Timeline().Get(0)->m_number, 5); EXPECT_EQ(STR(adpSets[1]->GetRepresentations()[0]->GetSegmentTemplate()->GetInitialization()), "3c1055cb-a842-4449-b393-7f31693b4a8f_aac1init.mp4"); EXPECT_EQ(STR(adpSets[1]->GetRepresentations()[0]->GetSegmentTemplate()->GetMedia()), "3c1055cb-a842-4449-b393-7f31693b4a8f_aac1_$Number%09d$.mp4"); EXPECT_EQ(adpSets[1]->GetRepresentations()[0]->GetSegmentTemplate()->GetTimescale(), 48000); - EXPECT_EQ(adpSets[1]->GetRepresentations()[0]->SegmentTimeline().Get(0)->m_number, 1); + EXPECT_EQ(adpSets[1]->GetRepresentations()[0]->Timeline().Get(0)->m_number, 1); EXPECT_EQ(STR(adpSets[2]->GetRepresentations()[0]->GetSegmentTemplate()->GetInitialization()), "abc_aac1init.mp4"); EXPECT_EQ(STR(adpSets[2]->GetRepresentations()[0]->GetSegmentTemplate()->GetMedia()), "abc2_$Number%09d$.mp4"); EXPECT_EQ(adpSets[2]->GetRepresentations()[0]->GetSegmentTemplate()->GetTimescale(), 68000); - EXPECT_EQ(adpSets[2]->GetRepresentations()[0]->SegmentTimeline().Get(0)->m_number, 5); + EXPECT_EQ(adpSets[2]->GetRepresentations()[0]->Timeline().Get(0)->m_number, 5); } TEST_F(DASHTreeAdaptiveStreamTest, CalculateRedirectSegTpl) @@ -601,7 +601,7 @@ TEST_F(DASHTreeAdaptiveStreamTest, MisalignedSegmentTimeline) auto& repr = tree->m_currentPeriod->GetAdaptationSets()[1]->GetRepresentations()[0]; // Set the last segment to the current segment to simulate reaching the last segment - repr->current_segment_ = repr->SegmentTimeline().GetBack(); + repr->current_segment_ = repr->Timeline().GetBack(); EXPECT_EQ(repr->current_segment_->startPTS_, 95687379264); EXPECT_EQ(repr->getCurrentSegmentPos(), 4); @@ -678,7 +678,7 @@ TEST_F(DASHTreeTest, SegmentTemplateStartNumber) EXPECT_EQ(adpSets[0]->GetRepresentations()[0]->GetSegmentTemplate()->GetDuration(), 48000); // Verify segments - auto& rep1Timeline = adpSets[0]->GetRepresentations()[0]->SegmentTimeline(); + auto& rep1Timeline = adpSets[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(rep1Timeline.GetSize(), 144); EXPECT_EQ(rep1Timeline.Get(0)->startPTS_, 0); @@ -700,14 +700,14 @@ TEST_F(DASHTreeTest, TSBMiddlePeriods) OpenTestFile("mpd/tsb_middle_periods.mpd"); auto& tlPeriod1 = - tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(tlPeriod1.GetSize(), 90); EXPECT_EQ(tlPeriod1.GetFront()->m_number, 856065330); EXPECT_EQ(tlPeriod1.GetBack()->m_number, 856065419); auto& tlPeriod2 = - tree->m_periods[1]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + tree->m_periods[1]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(tlPeriod2.GetSize(), 2); EXPECT_EQ(tlPeriod2.GetFront()->m_number, 856065420); @@ -724,14 +724,14 @@ TEST_F(DASHTreeTest, TSBMiddlePeriodsPastNowTime) OpenTestFile("mpd/tsb_middle_periods.mpd"); auto& tlPeriod1 = - tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(tlPeriod1.GetSize(), 90); EXPECT_EQ(tlPeriod1.GetFront()->m_number, 856065330); EXPECT_EQ(tlPeriod1.GetBack()->m_number, 856065419); auto& tlPeriod2 = - tree->m_periods[1]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + tree->m_periods[1]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(tlPeriod2.GetSize(), 1); EXPECT_EQ(tlPeriod2.GetFront()->m_number, 856065420); @@ -746,7 +746,7 @@ TEST_F(DASHTreeTest, TSBAvailabilityStartTime) OpenTestFile("mpd/tsb_availstarttime.mpd"); auto& tl = - tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + tree->m_periods[0]->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(tl.GetSize(), 1200); EXPECT_EQ(tl.GetFront()->m_number, 129069); diff --git a/src/test/TestHLSTree.cpp b/src/test/TestHLSTree.cpp index c4e4c9552..ecc6106b4 100644 --- a/src/test/TestHLSTree.cpp +++ b/src/test/TestHLSTree.cpp @@ -292,7 +292,7 @@ TEST_F(HLSTreeTest, PtsSetInMultiPeriod) auto& periodSecond = tree->m_periods[1]; auto& adp0rep1 = periodSecond->GetAdaptationSets()[0]->GetRepresentations()[0]; - auto adp0rep1seg1 = adp0rep1->SegmentTimeline().GetFront(); + auto adp0rep1seg1 = adp0rep1->Timeline().GetFront(); EXPECT_EQ(adp0rep1seg1->startPTS_, 0); } { @@ -308,7 +308,7 @@ TEST_F(HLSTreeTest, PtsSetInMultiPeriod) auto& periodSecond = tree->m_periods[1]; auto& adp1rep0 = periodSecond->GetAdaptationSets()[1]->GetRepresentations()[0]; - auto adp1rep0seg1 = adp1rep0->SegmentTimeline().GetFront(); + auto adp1rep0seg1 = adp1rep0->Timeline().GetFront(); EXPECT_EQ(adp1rep0seg1->startPTS_, 0); } } diff --git a/src/test/TestSmoothTree.cpp b/src/test/TestSmoothTree.cpp index 7a62d4f94..7943269a5 100644 --- a/src/test/TestSmoothTree.cpp +++ b/src/test/TestSmoothTree.cpp @@ -95,21 +95,21 @@ TEST_F(SmoothTreeTest, CheckAsyncTimelineStartPTS) // Each start with different chunk timestamp // so to sync streams we adjust PTS with which has the lowest timestamp (CSmoothTree::m_ptsBase) auto& period = tree->m_periods[0]; - auto& segTL = period->GetAdaptationSets()[0]->GetRepresentations()[0]->SegmentTimeline(); + auto& segTL = period->GetAdaptationSets()[0]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(segTL.GetSize(), 30); EXPECT_EQ(segTL.Get(0)->startPTS_, 7058030); EXPECT_EQ(segTL.Get(0)->m_time, 3903180167058030); EXPECT_EQ(segTL.Get(0)->m_number, 1); - segTL = period->GetAdaptationSets()[1]->GetRepresentations()[0]->SegmentTimeline(); + segTL = period->GetAdaptationSets()[1]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(segTL.GetSize(), 30); EXPECT_EQ(segTL.Get(0)->startPTS_, 71363); EXPECT_EQ(segTL.Get(0)->m_time, 3903180160071363); EXPECT_EQ(segTL.Get(0)->m_number, 1); - segTL = period->GetAdaptationSets()[3]->GetRepresentations()[0]->SegmentTimeline(); + segTL = period->GetAdaptationSets()[3]->GetRepresentations()[0]->Timeline(); EXPECT_EQ(segTL.GetSize(), 29); EXPECT_EQ(segTL.Get(0)->startPTS_, 0); From 828584c67520f0368d0cb52c3101be4893b35c49 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Tue, 2 Jul 2024 09:46:43 +0200 Subject: [PATCH 4/6] [AdaptiveTree] Moved segment methods to CSegContainer --- src/Session.cpp | 2 +- src/common/AdaptiveStream.cpp | 39 +++++----- src/common/Representation.cpp | 23 ++++++ src/common/Representation.h | 138 ++-------------------------------- src/common/Segment.cpp | 94 +++++++++++++++++------ src/common/Segment.h | 31 +++++--- src/parser/DASHTree.cpp | 10 +-- src/parser/HLSTree.cpp | 18 ++--- src/parser/SmoothTree.cpp | 2 +- src/test/TestDASHTree.cpp | 8 +- 10 files changed, 157 insertions(+), 208 deletions(-) diff --git a/src/Session.cpp b/src/Session.cpp index 9186462f2..7f3cfe1b0 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -938,7 +938,7 @@ void CSession::PrepareStream(CStream* stream) // Prepare the representation when the period change usually its not needed, // because the timeline is always already updated - if ((!m_adaptiveTree->IsChangingPeriod() || !repr->Timeline().IsEmpty()) && + if ((!m_adaptiveTree->IsChangingPeriod() || repr->Timeline().IsEmpty()) && (startEvent == EVENT_TYPE::STREAM_START || startEvent == EVENT_TYPE::STREAM_ENABLE)) { m_adaptiveTree->PrepareRepresentation(stream->m_adStream.getPeriod(), diff --git a/src/common/AdaptiveStream.cpp b/src/common/AdaptiveStream.cpp index 96c7c692e..b77399355 100644 --- a/src/common/AdaptiveStream.cpp +++ b/src/common/AdaptiveStream.cpp @@ -670,8 +670,8 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) { size_t segPos = current_rep_->Timeline().GetSize() - 1; //! @todo: segment duration is not fixed for each segment, this can calculate a wrong delay - uint64_t segDur = current_rep_->get_segment(segPos)->m_endPts - - current_rep_->get_segment(segPos)->startPTS_; + const CSegment* lastSeg = current_rep_->Timeline().GetBack(); + uint64_t segDur = lastSeg->m_endPts - lastSeg->startPTS_; size_t segPosDelay = static_cast((m_tree->m_liveDelay * current_rep_->GetTimescale()) / segDur); @@ -685,7 +685,7 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) segPos = 0; } - current_rep_->current_segment_ = current_rep_->get_segment(segPos); + current_rep_->current_segment_ = current_rep_->Timeline().Get(segPos); } else if (m_startEvent == EVENT_TYPE::REP_CHANGE) // switching streams, align new stream segment no. { @@ -694,7 +694,7 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) { segmentId = current_rep_->GetStartNumber() + current_rep_->Timeline().GetSize() - 1; } - current_rep_->current_segment_ = current_rep_->get_segment( + current_rep_->current_segment_ = current_rep_->Timeline().Get( static_cast(segmentId - current_rep_->GetStartNumber())); } else @@ -706,8 +706,7 @@ bool AdaptiveStream::start_stream(const uint64_t startPts) // Reset the event for the next one m_startEvent = EVENT_TYPE::NONE; - const CSegment* next_segment = - current_rep_->get_next_segment(current_rep_->current_segment_); + const CSegment* next_segment = current_rep_->GetNextSegment(); if (!next_segment && current_adp_->GetStreamType() != StreamType::SUBTITLE) { @@ -844,11 +843,11 @@ bool AdaptiveStream::ensureSegment() if (!segment_buffers_[0]->segment.IsInitialization()) { // Search the same segment on the timeline (which in the meantime may have been updated) - nextSegment = current_rep_->GetSegment(segment_buffers_[0]->segment); + nextSegment = current_rep_->Timeline().Find(segment_buffers_[0]->segment); } } else - nextSegment = current_rep_->get_next_segment(current_rep_->current_segment_); + nextSegment = current_rep_->GetNextSegment(); if (!nextSegment && (m_tree->HasManifestUpdates() || m_tree->HasManifestUpdatesSegs()) && !m_tree->IsLastSegment(current_period_, current_rep_, current_rep_->current_segment_)) @@ -860,7 +859,7 @@ bool AdaptiveStream::ensureSegment() getSegmentPos())) { //! @todo: seem to be possible get the segment from InsertLiveSegment and then avoid call get_next_segment - nextSegment = current_rep_->get_next_segment(current_rep_->current_segment_); + nextSegment = current_rep_->GetNextSegment(); } if (!nextSegment && !current_rep_->IsWaitForSegment()) @@ -891,7 +890,7 @@ bool AdaptiveStream::ensureSegment() observer_->OnSegmentChanged(this); } - const size_t nextSegPos = current_rep_->get_segment_pos(nextSegment); + const size_t nextSegPos = current_rep_->Timeline().GetPos(nextSegment); CRepresentation* newRep = current_rep_; bool isBufferFull = valid_segment_buffers_ >= max_buffer_length_; @@ -939,9 +938,9 @@ bool AdaptiveStream::ensureSegment() else // Continue adding segments that follow the last one added in to the buffer { const CSegment* followSeg = - current_rep_->GetNextSegment(segment_buffers_[available_segment_buffers_ - 1]->segment); + current_rep_->Timeline().GetNext(&segment_buffers_[available_segment_buffers_ - 1]->segment); if (followSeg) - segPos = current_rep_->get_segment_pos(followSeg); + segPos = current_rep_->Timeline().GetPos(followSeg); else // No segment, EOS or you need to wait next manifest update segPos = maxPos; } @@ -951,10 +950,10 @@ bool AdaptiveStream::ensureSegment() //! this can cause a bad initial buffering because the stream dont fit the bandwidth. for (size_t index = available_segment_buffers_; index < max_buffer_length_; ++index) { - if (segPos == maxPos) // To avoid out-of-range log prints with get_segment + if (segPos == maxPos) // To avoid out-of-range log prints with Timeline().Get break; - const CSegment* futureSegment = newRep->get_segment(segPos); + const CSegment* futureSegment = newRep->Timeline().Get(segPos); if (futureSegment) { segment_buffers_[index]->segment = *futureSegment; @@ -1132,7 +1131,7 @@ void AdaptiveStream::ResetCurrentSegment(const PLAYLIST::CSegment* newSegment) WaitWorker(); // EnsureSegment loads always the next segment, so go back 1 current_rep_->current_segment_ = - current_rep_->get_segment(current_rep_->get_segment_pos(newSegment) - 1); + current_rep_->Timeline().Get(current_rep_->Timeline().GetPos(newSegment) - 1); // TODO: if new segment is already prefetched, don't ResetActiveBuffer; ResetActiveBuffer(false); } @@ -1187,7 +1186,7 @@ bool AdaptiveStream::seek_time(double seek_seconds, bool preceeding, bool& needR size_t choosen_seg{0}; while (choosen_seg < current_rep_->Timeline().GetSize() && - sec_in_ts > current_rep_->get_segment(choosen_seg)->startPTS_) + sec_in_ts > current_rep_->Timeline().Get(choosen_seg)->startPTS_) { ++choosen_seg; } @@ -1207,14 +1206,14 @@ bool AdaptiveStream::seek_time(double seek_seconds, bool preceeding, bool& needR return false; } - if (choosen_seg && current_rep_->get_segment(choosen_seg)->startPTS_ > sec_in_ts) + if (choosen_seg && current_rep_->Timeline().Get(choosen_seg)->startPTS_ > sec_in_ts) --choosen_seg; // Never seek into expired segments..... if (choosen_seg < current_rep_->expired_segments_) choosen_seg = current_rep_->expired_segments_; - if (!preceeding && sec_in_ts > current_rep_->get_segment(choosen_seg)->startPTS_ && + if (!preceeding && sec_in_ts > current_rep_->Timeline().Get(choosen_seg)->startPTS_ && current_adp_->GetStreamType() == StreamType::VIDEO) { //Assume that we have I-Frames only at segment start @@ -1222,7 +1221,7 @@ bool AdaptiveStream::seek_time(double seek_seconds, bool preceeding, bool& needR } const CSegment* old_seg = current_rep_->current_segment_; - const CSegment* newSeg = current_rep_->get_segment(choosen_seg); + const CSegment* newSeg = current_rep_->Timeline().Get(choosen_seg); if (newSeg) { @@ -1254,7 +1253,7 @@ bool AdaptiveStream::seek_time(double seek_seconds, bool preceeding, bool& needR size_t adaptive::AdaptiveStream::getSegmentPos() { - return current_rep_->getCurrentSegmentPos(); + return current_rep_->Timeline().GetPos(current_rep_->current_segment_); } bool AdaptiveStream::waitingForSegment() const diff --git a/src/common/Representation.cpp b/src/common/Representation.cpp index 79b811b3f..3ca77e9f9 100644 --- a/src/common/Representation.cpp +++ b/src/common/Representation.cpp @@ -51,6 +51,29 @@ void PLAYLIST::CRepresentation::CopyHLSData(const CRepresentation* other) m_isEnabled = other->m_isEnabled; } +const CSegment* PLAYLIST::CRepresentation::GetNextSegment() +{ + return m_segmentTimeline.GetNext(current_segment_); +} + +const uint64_t PLAYLIST::CRepresentation::GetCurrentSegNumber() const +{ + return GetSegNumber(current_segment_); +} + +const uint64_t PLAYLIST::CRepresentation::GetSegNumber(const CSegment* seg) const +{ + if (!seg) + return SEGMENT_NO_NUMBER; + + const size_t segPos = m_segmentTimeline.GetPos(seg); + + if (segPos == SEGMENT_NO_POS) + return SEGMENT_NO_NUMBER; + + return static_cast(segPos) + m_startNumber; +} + void PLAYLIST::CRepresentation::SetScaling() { if (!m_timescale) diff --git a/src/common/Representation.h b/src/common/Representation.h index a8ec58850..b0d7b60d2 100644 --- a/src/common/Representation.h +++ b/src/common/Representation.h @@ -110,7 +110,7 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA /*! * \brief The segment timeline. */ - CSegContainer Timeline() const { return m_segmentTimeline; } + const CSegContainer& Timeline() const { return m_segmentTimeline; } std::optional& GetSegmentBase() { return m_segmentBase; } void SetSegmentBase(const CSegmentBase& segBase) { m_segmentBase = segBase; } @@ -182,155 +182,27 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA const CSegment* current_segment_{nullptr}; - bool HasInitSegment() const { return m_initSegment.has_value(); } void SetInitSegment(CSegment initSegment) { m_initSegment = initSegment; } std::optional& GetInitSegment() { return m_initSegment; } /*! - * \brief Get the next segment after the one specified. - * \return If found the segment pointer, otherwise nullptr. - */ - CSegment* get_next_segment(const CSegment* seg) - { - if (!seg || seg->IsInitialization()) - return m_segmentTimeline.Get(0); - - const size_t segPos = m_segmentTimeline.GetPosition(seg); - - if (segPos == SEGMENT_NO_POS) - return nullptr; - - size_t nextPos = segPos + 1; - if (nextPos == m_segmentTimeline.GetSize()) - return nullptr; - - return m_segmentTimeline.Get(nextPos); - } - - /*! - * \brief Get the segment from specified position. + * \brief Get segment following the current one. * \return If found the segment pointer, otherwise nullptr. */ - CSegment* get_segment(size_t pos) - { - if (pos == SEGMENT_NO_POS) - return nullptr; - - return m_segmentTimeline.Get(pos); - } - - /*! - * \brief Get the segment position. - * \return If found the position, otherwise SEGMENT_NO_POS. - */ - const size_t get_segment_pos(const CSegment* segment) const - { - if (!segment) - return SEGMENT_NO_POS; - - return m_segmentTimeline.IsEmpty() ? 0 : m_segmentTimeline.GetPosition(segment); - } - - const CSegment* GetSegment(const CSegment& segment) - { - // If available, find the segment by number, this is because some - // live services provide inconsistent timestamps between manifest updates - // which will make it ineffective to find the same segment - if (segment.m_number != SEGMENT_NO_NUMBER) - { - const uint64_t number = segment.m_number; - - for (const CSegment& segment : m_segmentTimeline) - { - if (segment.m_number == number) - return &segment; - } - } - else - { - const uint64_t startPTS = segment.startPTS_; - - for (const CSegment& segment : m_segmentTimeline) - { - // Search by >= is intended to allow minimizing problems with encoders - // that provide inconsistent timestamps between manifest updates - if (segment.startPTS_ >= startPTS) - return &segment; - } - } - - return nullptr; - } - - const CSegment* GetNextSegment(const CSegment& segment) - { - // If available, find the segment by number, this is because some - // live services provide inconsistent timestamps between manifest updates - // which will make it ineffective to find the next segment - if (segment.m_number != SEGMENT_NO_NUMBER) - { - const uint64_t number = segment.m_number; - - for (const CSegment& segment : m_segmentTimeline) - { - if (segment.m_number > number) - return &segment; - } - } - else - { - const uint64_t startPTS = segment.startPTS_; - - for (const CSegment& segment : m_segmentTimeline) - { - if (segment.startPTS_ > startPTS) - return &segment; - } - } - return nullptr; - } - - /*! - * \brief Get the position of current segment. - * \return If found the position, otherwise SEGMENT_NO_POS. - */ - const size_t getCurrentSegmentPos() const { return get_segment_pos(current_segment_); } + const CSegment* GetNextSegment(); /*! * \brief Get the segment number of current segment. * \return If found the number, otherwise SEGMENT_NO_NUMBER. */ - const uint64_t getCurrentSegmentNumber() const - { - if (!current_segment_) - return SEGMENT_NO_NUMBER; - - const size_t segPos = get_segment_pos(current_segment_); - - if (segPos == SEGMENT_NO_POS) - return SEGMENT_NO_NUMBER; - - return static_cast(segPos) + m_startNumber; - } + const uint64_t GetCurrentSegNumber() const; /*! * \brief Get the segment number of specified segment. * \return If found the number, otherwise SEGMENT_NO_NUMBER. */ - const uint64_t getSegmentNumber(const CSegment* segment) const - { - if (!segment) - return SEGMENT_NO_NUMBER; - - const size_t segPos = get_segment_pos(current_segment_); - - if (segPos == SEGMENT_NO_POS) - return SEGMENT_NO_NUMBER; - - return static_cast(segPos) + m_startNumber; - } - + const uint64_t GetSegNumber(const CSegment* seg) const; uint32_t timescale_ext_{0}; uint32_t timescale_int_{0}; diff --git a/src/common/Segment.cpp b/src/common/Segment.cpp index 2980d3716..f3b3b8572 100644 --- a/src/common/Segment.cpp +++ b/src/common/Segment.cpp @@ -25,57 +25,105 @@ const CSegment* PLAYLIST::CSegContainer::Get(size_t pos) const return &m_segments[pos]; } -CSegment* PLAYLIST::CSegContainer::Get(size_t pos) +const CSegment* PLAYLIST::CSegContainer::GetBack() const { - if (pos == SEGMENT_NO_POS || m_segments.empty()) - return nullptr; - - if (pos >= m_segments.size()) - { - LOG::LogF(LOGWARNING, "Position out-of-range (%zu of %zu)", pos, m_segments.size()); + if (m_segments.empty()) return nullptr; - } - return &m_segments[pos]; + return &m_segments.back(); } -CSegment* PLAYLIST::CSegContainer::GetBack() +const CSegment* PLAYLIST::CSegContainer::GetFront() const { if (m_segments.empty()) return nullptr; - return &m_segments.back(); + return &m_segments.front(); } -CSegment* PLAYLIST::CSegContainer::GetFront() +const CSegment* PLAYLIST::CSegContainer::GetNext(const CSegment* seg) const { - if (m_segments.empty()) - return nullptr; + if (!seg || seg->IsInitialization()) + return GetFront(); - return &m_segments.front(); + // If available, find the segment by number, this is because some + // live services provide inconsistent timestamps between manifest updates + // which will make it ineffective to find the next segment + if (seg->m_number != SEGMENT_NO_NUMBER) + { + const uint64_t number = seg->m_number; + + for (const CSegment& segment : m_segments) + { + if (segment.m_number > number) + return &segment; + } + } + else + { + const uint64_t startPTS = seg->startPTS_; + + for (const CSegment& segment : m_segments) + { + if (segment.startPTS_ > startPTS) + return &segment; + } + } + return nullptr; +} + +const CSegment* PLAYLIST::CSegContainer::Find(const CSegment& seg) const +{ + // If available, find the segment by number, this is because some + // live services provide inconsistent timestamps between manifest updates + // which will make it ineffective to find the same segment + if (seg.m_number != SEGMENT_NO_NUMBER) + { + const uint64_t number = seg.m_number; + + for (const CSegment& segment : m_segments) + { + if (segment.m_number == number) + return &segment; + } + } + else + { + const uint64_t startPTS = seg.startPTS_; + + for (const CSegment& segment : m_segments) + { + // Search by >= is intended to allow minimizing problems with encoders + // that provide inconsistent timestamps between manifest updates + if (segment.startPTS_ >= startPTS) + return &segment; + } + } + + return nullptr; } -const size_t PLAYLIST::CSegContainer::GetPosition(const CSegment* elem) const +const size_t PLAYLIST::CSegContainer::GetPos(const CSegment* seg) const { for (size_t i = 0; i < m_segments.size(); ++i) { - if (&m_segments[i] == elem) + if (&m_segments[i] == seg) return i; } return SEGMENT_NO_POS; } -void PLAYLIST::CSegContainer::Add(const CSegment& elem) +void PLAYLIST::CSegContainer::Add(const CSegment& seg) { - m_duration += elem.m_endPts - elem.startPTS_; - m_segments.emplace_back(elem); + m_duration += seg.m_endPts - seg.startPTS_; + m_segments.emplace_back(seg); } -void PLAYLIST::CSegContainer::Append(const CSegment& elem) +void PLAYLIST::CSegContainer::Append(const CSegment& seg) { - m_duration += elem.m_endPts - elem.startPTS_; - m_segments.emplace_back(elem); + m_duration += seg.m_endPts - seg.startPTS_; + m_segments.emplace_back(seg); m_appendCount += 1; } diff --git a/src/common/Segment.h b/src/common/Segment.h index 03e46e717..ffc1c0821 100644 --- a/src/common/Segment.h +++ b/src/common/Segment.h @@ -76,42 +76,49 @@ class ATTR_DLL_LOCAL CSegContainer const CSegment* Get(size_t pos) const; /*! - * \brief Get the segment pointer from the specified position - * \param pos The position of segment + * \brief Get the last segment pointer * \return Segment pointer, otherwise nullptr if not found */ - CSegment* Get(size_t pos); + const CSegment* GetBack() const; /*! - * \brief Get the last segment pointer + * \brief Get the first segment as pointer * \return Segment pointer, otherwise nullptr if not found */ - CSegment* GetBack(); + const CSegment* GetFront() const; /*! - * \brief Get the first segment as pointer - * \return Segment pointer, otherwise nullptr if not found + * \brief Get the next segment after the one specified. + * The search is done by number (if available) otherwise by PTS. + * \return If found the segment pointer, otherwise nullptr. + */ + const CSegment* GetNext(const CSegment* seg) const; + + /*! + * \brief Try find same/similar segment in the timeline. + * The search is done by number (if available) otherwise by PTS. + * \return If found the segment pointer, otherwise nullptr. */ - CSegment* GetFront(); + const CSegment* Find(const CSegment& seg) const; /*! - * \brief Get index position of a segment pointer + * \brief Get index position of a segment pointer in the timeline. * \param elem The segment pointer to get the position * \return The index position, or SEGMENT_NO_POS if not found */ - const size_t GetPosition(const CSegment* elem) const; + const size_t GetPos(const CSegment* seg) const; /*! * \brief Add a segment to the container. * \param elem The segment to add */ - void Add(const CSegment& elem); + void Add(const CSegment& seg); /*! * \brief Append segment to the container, by increasing the count. * \param elem The segment to append */ - void Append(const CSegment& elem); + void Append(const CSegment& seg); void Swap(CSegContainer& other); diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index ff519c96d..5bda7934a 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -1013,7 +1013,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } if (repr->GetContainerType() == ContainerType::TEXT && repr->GetMimeType() != "application/mp4" && - !repr->HasSegmentBase() && !repr->HasSegmentTemplate() && !repr->Timeline().IsEmpty()) + !repr->HasSegmentBase() && !repr->HasSegmentTemplate() && repr->Timeline().IsEmpty()) { // Raw unsegmented subtitles called "sidecar" is a single file specified in the tag, // must not have the MP4 ISOBMFF mime type or any other dash element. @@ -1021,7 +1021,7 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } // Generate segments from SegmentTemplate - if (repr->HasSegmentTemplate() && !repr->Timeline().IsEmpty()) + if (repr->HasSegmentTemplate() && repr->Timeline().IsEmpty()) { auto& segTemplate = repr->GetSegmentTemplate(); @@ -1744,7 +1744,7 @@ void adaptive::CDashTree::OnUpdateSegments() } } - if (repr->IsWaitForSegment() && (repr->get_next_segment(repr->current_segment_))) + if (repr->IsWaitForSegment() && repr->GetNextSegment()) { repr->SetIsWaitForSegment(false); LOG::LogF(LOGDEBUG, "End WaitForSegment repr. id %s", repr->GetId().data()); @@ -1801,7 +1801,7 @@ bool adaptive::CDashTree::InsertLiveSegment(PLAYLIST::CPeriod* period, //! @todo: expired_segments_ should be reworked, see also other parsers repr->expired_segments_++; - CSegment* segment = repr->Timeline().Get(pos); + const CSegment* segment = repr->Timeline().Get(pos); if (!segment) { @@ -1838,7 +1838,7 @@ bool adaptive::CDashTree::InsertLiveFragment(PLAYLIST::CAdaptationSet* adpSet, if (!m_isLive || !repr->HasSegmentTemplate() || m_minimumUpdatePeriod != NO_VALUE) return false; - CSegment* lastSeg = repr->Timeline().GetBack(); + const CSegment* lastSeg = repr->Timeline().GetBack(); if (!lastSeg) return false; diff --git a/src/parser/HLSTree.cpp b/src/parser/HLSTree.cpp index fc382d281..6c762a1b3 100644 --- a/src/parser/HLSTree.cpp +++ b/src/parser/HLSTree.cpp @@ -186,7 +186,7 @@ bool adaptive::CHLSTree::PrepareRepresentation(PLAYLIST::CPeriod* period, PLAYLIST::CAdaptationSet* adp, PLAYLIST::CRepresentation* rep) { - if (!m_isLive && rep->Timeline().IsEmpty()) + if (!m_isLive && !rep->Timeline().IsEmpty()) return true; if (!ProcessChildManifest(period, adp, rep, SEGMENT_NO_NUMBER)) @@ -227,7 +227,7 @@ void adaptive::CHLSTree::FixMediaSequence(std::stringstream& streamData, auto& lastPRep = m_periods.back()->GetAdaptationSets()[adpSetPos]->GetRepresentations()[reprPos]; if (lastPRep->Timeline().IsEmpty()) return; - CSegment* lastSeg = lastPRep->Timeline().GetBack(); + const CSegment* lastSeg = lastPRep->Timeline().GetBack(); uint64_t segStartPts = lastSeg->startPTS_; // The start PTS refer to date-time uint64_t segNumber = lastSeg->m_number; @@ -605,7 +605,7 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, } else { - CSegment* lastSeg = newSegments.GetBack(); + const CSegment* lastSeg = newSegments.GetBack(); if (lastSeg) startPts = lastSeg->m_endPts; } @@ -935,13 +935,13 @@ void adaptive::CHLSTree::PrepareSegments(PLAYLIST::CPeriod* period, } rep->current_segment_ = - rep->get_segment(static_cast(segNumber - rep->GetStartNumber())); + rep->Timeline().Get(static_cast(segNumber - rep->GetStartNumber())); } //! @todo: m_currentPeriod != m_periods.back().get() condition should be removed from here //! this is done on AdaptiveStream::ensureSegment on IsLastSegment check if (rep->IsWaitForSegment() && - (rep->get_next_segment(rep->current_segment_) || m_currentPeriod != m_periods.back().get())) + (rep->GetNextSegment() || m_currentPeriod != m_periods.back().get())) { LOG::LogF(LOGDEBUG, "End WaitForSegment stream id \"%s\"", rep->GetId().data()); rep->SetIsWaitForSegment(false); @@ -1054,10 +1054,10 @@ void adaptive::CHLSTree::OnStreamChange(PLAYLIST::CPeriod* period, PLAYLIST::CRepresentation* previousRep, PLAYLIST::CRepresentation* currentRep) { - if (!m_isLive && currentRep->Timeline().IsEmpty()) + if (!m_isLive && !currentRep->Timeline().IsEmpty()) return; - const uint64_t currentSegNumber = previousRep->getCurrentSegmentNumber(); + const uint64_t currentSegNumber = previousRep->GetCurrentSegNumber(); ProcessChildManifest(period, adp, currentRep, currentSegNumber); } @@ -1071,7 +1071,7 @@ void adaptive::CHLSTree::OnRequestSegments(PLAYLIST::CPeriod* period, // Save the current segment position before parsing the manifest // to allow find the right segment on updated playlist segments - const uint64_t segNumber = rep->getCurrentSegmentNumber(); + const uint64_t segNumber = rep->GetCurrentSegNumber(); ProcessChildManifest(period, adp, rep, segNumber); } @@ -1114,7 +1114,7 @@ void adaptive::CHLSTree::OnUpdateSegments() { // Save the current segment position before parsing the manifest // to allow find the right segment on updated playlist segments - const uint64_t segNumber = repr->getCurrentSegmentNumber(); + const uint64_t segNumber = repr->GetCurrentSegNumber(); if (!ProcessChildManifest(m_currentPeriod, adpSet, repr, segNumber)) { diff --git a/src/parser/SmoothTree.cpp b/src/parser/SmoothTree.cpp index eb60f46ea..c7e16abb4 100644 --- a/src/parser/SmoothTree.cpp +++ b/src/parser/SmoothTree.cpp @@ -427,7 +427,7 @@ bool adaptive::CSmoothTree::InsertLiveFragment(PLAYLIST::CAdaptationSet* adpSet, //! then add a better way to delete old segments from the timeline based on timeshift window //! this also requires taking care of the Dash parser - CSegment* lastSeg = repr->Timeline().GetBack(); + const CSegment* lastSeg = repr->Timeline().GetBack(); if (!lastSeg) return false; diff --git a/src/test/TestDASHTree.cpp b/src/test/TestDASHTree.cpp index 6ab85b5cb..5bf7d2223 100644 --- a/src/test/TestDASHTree.cpp +++ b/src/test/TestDASHTree.cpp @@ -604,19 +604,19 @@ TEST_F(DASHTreeAdaptiveStreamTest, MisalignedSegmentTimeline) repr->current_segment_ = repr->Timeline().GetBack(); EXPECT_EQ(repr->current_segment_->startPTS_, 95687379264); - EXPECT_EQ(repr->getCurrentSegmentPos(), 4); + EXPECT_EQ(repr->Timeline().GetPos(repr->current_segment_), 4); tree->RunManifestUpdate("mpd/bad_segtimeline_2.mpd"); EXPECT_EQ(repr->current_segment_->startPTS_, 95687381280); - EXPECT_EQ(repr->getCurrentSegmentPos(), 2); + EXPECT_EQ(repr->Timeline().GetPos(repr->current_segment_), 2); tree->RunManifestUpdate("mpd/bad_segtimeline_3.mpd"); EXPECT_EQ(repr->current_segment_->startPTS_, 95687382336); - EXPECT_EQ(repr->getCurrentSegmentPos(), 1); + EXPECT_EQ(repr->Timeline().GetPos(repr->current_segment_), 1); tree->RunManifestUpdate("mpd/bad_segtimeline_4.mpd"); EXPECT_EQ(repr->current_segment_->startPTS_, 95687382337); - EXPECT_EQ(repr->getCurrentSegmentPos(), 0); + EXPECT_EQ(repr->Timeline().GetPos(repr->current_segment_), 0); } TEST_F(DASHTreeTest, AdaptionSetSwitching) From 1e02894d4e69864acc04e6d6f65e71ac5eda9dc4 Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Mon, 1 Jul 2024 19:41:26 +0200 Subject: [PATCH 5/6] [AdaptiveTree] Set rep duration by using Timeline --- src/common/AdaptiveStream.cpp | 6 +++--- src/parser/DASHTree.cpp | 24 +----------------------- src/parser/HLSTree.cpp | 3 +-- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/common/AdaptiveStream.cpp b/src/common/AdaptiveStream.cpp index b77399355..6cb02c307 100644 --- a/src/common/AdaptiveStream.cpp +++ b/src/common/AdaptiveStream.cpp @@ -478,6 +478,8 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, seg.range_end_ = cue.pos_end; rep->Timeline().Add(seg); } + + rep->SetDuration(rep->Timeline().GetDuration()); return true; } } @@ -495,7 +497,6 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, bool isMoovFound{false}; AP4_Cardinal sidxCount{1}; - uint64_t reprDuration{0}; CSegment seg; seg.startPTS_ = 0; @@ -546,7 +547,6 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, seg.startPTS_ += refs[i].m_SubsegmentDuration; seg.m_endPts = seg.startPTS_ + refs[i].m_SubsegmentDuration; seg.m_time += refs[i].m_SubsegmentDuration; - reprDuration += refs[i].m_SubsegmentDuration; } sidxCount--; @@ -576,7 +576,7 @@ bool AdaptiveStream::parseIndexRange(PLAYLIST::CRepresentation* rep, rep->SetInitSegment(initSeg); } - rep->SetDuration(reprDuration); + rep->SetDuration(rep->Timeline().GetDuration()); return true; } diff --git a/src/parser/DASHTree.cpp b/src/parser/DASHTree.cpp index 5bda7934a..d51594a02 100644 --- a/src/parser/DASHTree.cpp +++ b/src/parser/DASHTree.cpp @@ -921,25 +921,6 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, index++; } - // Determines total duration of segments - uint64_t totalDur; - if (adpSet->HasSegmentTimelineDuration()) - { - auto& segTLData = adpSet->SegmentTimelineDuration(); - totalDur = std::accumulate(segTLData.begin(), segTLData.end(), 0ULL); - if (isTLDurTsRescale) - { - totalDur = - static_cast(static_cast(totalDur) / - adpSet->GetSegDurationsTimescale() * segList.GetTimescale()); - } - } - else - { - totalDur = static_cast(repr->Timeline().GetSize()) * segList.GetDuration(); - } - - repr->SetDuration(totalDur); repr->SetTimescale(segList.GetTimescale()); repr->SetSegmentList(segList); @@ -1055,7 +1036,6 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, if (segTemplate->HasTimeline()) // Generate segments from template timeline { uint64_t time{0}; - uint64_t totalDuration{0}; for (const auto& tlElem : segTemplate->Timeline()) { @@ -1079,7 +1059,6 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, seg.m_time = time; - totalDuration += tlElem.duration; repr->Timeline().Add(seg); time += tlElem.duration; @@ -1087,7 +1066,6 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } repr->SetTimescale(segTimescale); - repr->SetDuration(totalDuration); } else // Generate segments by using template { @@ -1164,11 +1142,11 @@ void adaptive::CDashTree::ParseTagRepresentation(pugi::xml_node nodeRepr, } repr->SetTimescale(segTemplate->GetTimescale()); - repr->SetDuration(static_cast(segDuration) * segmentsCount); } } } + repr->SetDuration(repr->Timeline().GetDuration()); repr->SetScaling(); adpSet->AddRepresentation(repr); diff --git a/src/parser/HLSTree.cpp b/src/parser/HLSTree.cpp index 6c762a1b3..4065668ec 100644 --- a/src/parser/HLSTree.cpp +++ b/src/parser/HLSTree.cpp @@ -774,8 +774,7 @@ bool adaptive::CHLSTree::ProcessChildManifest(PLAYLIST::CPeriod* period, { period->SetSequence(m_discontSeq + discontCount); - uint64_t dur = newSegments.GetBack()->m_endPts - newSegments.GetFront()->startPTS_; - rep->SetDuration(dur); + rep->SetDuration(newSegments.GetDuration()); if (adp->GetStreamType() != StreamType::SUBTITLE) { From 0e5d21d60dae141a30ad11e4ffffa5a4baab799b Mon Sep 17 00:00:00 2001 From: CastagnaIT Date: Tue, 2 Jul 2024 08:50:10 +0200 Subject: [PATCH 6/6] [AdaptationSet] Add back_inserter include --- src/common/AdaptationSet.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/AdaptationSet.cpp b/src/common/AdaptationSet.cpp index 5e525ea6c..ae110bf15 100644 --- a/src/common/AdaptationSet.cpp +++ b/src/common/AdaptationSet.cpp @@ -13,6 +13,7 @@ #include "utils/Utils.h" #include // any_of +#include // back_inserter using namespace PLAYLIST; using namespace UTILS; @@ -53,7 +54,7 @@ void PLAYLIST::CAdaptationSet::AddRepresentation( std::vector PLAYLIST::CAdaptationSet::GetRepresentationsPtr() { std::vector ptrReprs; - std::transform(m_representations.begin(), m_representations.end(), back_inserter(ptrReprs), + std::transform(m_representations.begin(), m_representations.end(), std::back_inserter(ptrReprs), [](const std::unique_ptr& r) { return r.get(); }); return ptrReprs; }