Skip to content

Commit 103f110

Browse files
authored
Merge pull request #2076 from CastagnaIT/wait_segments
Rework wait for segment code
2 parents 4532955 + 2281ec1 commit 103f110

16 files changed

Lines changed: 103 additions & 59 deletions

src/AdaptiveByteStream.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ AP4_Result CAdaptiveByteStream::GetSize(AP4_LargeSize& size)
5959

6060
bool CAdaptiveByteStream::waitingForSegment() const
6161
{
62-
return m_adStream->waitingForSegment();
62+
return m_adStream->IsWaitingForSegment();
6363
}
6464

6565
void CAdaptiveByteStream::FixateInitialization(bool on)

src/Session.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ bool SESSION::CSession::GetNextSample(ISampleReader*& sampleReader)
812812
{
813813
if (!res || streamReader->DTSorPTSManifest() < res->GetReader()->DTSorPTSManifest())
814814
{
815-
if (stream->m_adStream.waitingForSegment())
815+
if (stream->m_adStream.OnSampleRequested())
816816
{
817817
waiting = stream.get();
818818
}
@@ -828,6 +828,8 @@ bool SESSION::CSession::GetNextSample(ISampleReader*& sampleReader)
828828

829829
if (waiting)
830830
{
831+
// Prevents CPU usage spikes due to continuous Kodi VP requests
832+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
831833
return true;
832834
}
833835
else if (res)

src/common/AdaptiveStream.cpp

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ void adaptive::AdaptiveStream::Reset()
7171
segment_read_pos_ = 0;
7272
currentPTSOffset_ = 0;
7373
absolutePTSOffset_ = 0;
74+
m_isWaitingForSegment = false;
7475
}
7576

7677
bool adaptive::AdaptiveStream::Download(const DownloadInfo& downloadInfo,
@@ -969,15 +970,15 @@ bool adaptive::AdaptiveStream::ensureSegment()
969970
}
970971
else if (!m_tree->IsLastSegment(current_period_, current_rep_, current_rep_->current_segment_))
971972
{
972-
if (m_segBuffers.IsEmpty() && !current_rep_->IsWaitForSegment())
973+
if (m_segBuffers.IsEmpty() && !m_isWaitingForSegment)
973974
{
974-
current_rep_->SetIsWaitForSegment(true);
975-
LOG::LogF(LOGDEBUG, "[AS-%u] Begin WaitForSegment stream rep. id \"%s\" period id \"%s\"",
975+
m_isWaitingForSegment = true;
976+
LOG::LogF(LOGDEBUG, "[AS-%u] Begin WaitForSegment (buffer is empty) stream rep. id \"%s\" period id \"%s\"",
976977
clsId, current_rep_->GetId().c_str(), current_period_->GetId().c_str());
977978
}
978979
return false;
979980
}
980-
else if (current_rep_->IsWaitForSegment() &&
981+
else if (m_isWaitingForSegment &&
981982
(m_tree->HasManifestUpdates() || m_tree->HasManifestUpdatesSegs()))
982983
{
983984
return false;
@@ -1115,7 +1116,7 @@ bool adaptive::AdaptiveStream::seek(uint64_t const pos, bool& isEos)
11151116
if (ensureSegment())
11161117
return true;
11171118

1118-
if (!current_rep_->IsWaitForSegment())
1119+
if (!m_isWaitingForSegment)
11191120
isEos = true;
11201121

11211122
return false;
@@ -1254,21 +1255,49 @@ bool adaptive::AdaptiveStream::seek_time(double seek_seconds)
12541255
return true;
12551256
}
12561257

1257-
bool adaptive::AdaptiveStream::waitingForSegment() const
1258+
bool adaptive::AdaptiveStream::OnSampleRequested()
12581259
{
1259-
if (m_tree->IsLive() && thread_data_->State() == THREADDATA::ThState::RUNNING)
1260+
if (!m_tree->IsLive() || !thread_data_)
1261+
return false;
1262+
1263+
//! @todo: its missing an appropriate buffering management, example:
1264+
//! if the bandwidth is too low stuttering may occur due to constant buffering
1265+
//! it should wait that buffer if full before to resume the playback,
1266+
//! it should also help to manage adaptive streaming (CRepresentationChooserDefault)
1267+
//! the mechanism to auto-increase/decrease stream quality based on the actual network conditions
1268+
1269+
const auto now = std::chrono::steady_clock::now();
1270+
const long long elapsedMs =
1271+
std::chrono::duration_cast<std::chrono::milliseconds>(now - m_tsOnSampleRequest).count();
1272+
1273+
// Sample are requested in a very fast way, limit the requests to a minimum interval of 500 ms
1274+
if (elapsedMs >= 500)
12601275
{
1276+
m_tsOnSampleRequest = now;
12611277
std::lock_guard<adaptive::AdaptiveTree::TreeUpdateThread> lckUpdTree(m_tree->GetTreeUpdMutex());
12621278

12631279
// Some manifests require segments to be generated and managed by the client
12641280
// so they are not provided by the server through periodic manifest updates
12651281
m_tree->InsertLiveSegment(current_period_, current_adp_, current_rep_);
12661282

1267-
// Although IsWaitForSegment may be true, do not anticipate the wait for segments
1268-
// if there are still segments in the buffer that can be read and/or downloaded
1269-
return current_rep_ && current_rep_->IsWaitForSegment() && m_segBuffers.IsEmpty();
1283+
if (m_isWaitingForSegment)
1284+
{
1285+
if (thread_data_->State() != THREADDATA::ThState::RUNNING)
1286+
return false;
1287+
1288+
// Unlocks buffering wait, if a segment exists and the buffer level is full
1289+
m_isWaitingForSegment = !current_rep_->GetNextSegment() ||
1290+
m_segBuffers.GetSizeDownloaded() < m_segBuffers.GetSize();
1291+
1292+
if (!m_isWaitingForSegment)
1293+
{
1294+
LOG::LogF(LOGDEBUG, "[AS-%u] End WaitForSegment stream rep. id \"%s\" period id \"%s\"",
1295+
clsId, current_rep_->GetId().c_str(), current_period_->GetId().c_str());
1296+
}
1297+
}
12701298
}
1271-
return false;
1299+
1300+
return m_isWaitingForSegment;
12721301
}
12731302

12741303
void adaptive::AdaptiveStream::FixateInitialization(bool on)
@@ -1355,6 +1384,8 @@ void adaptive::AdaptiveStream::Stop()
13551384
// otherwise if read some segments may invalidate this change
13561385
if (current_rep_)
13571386
current_rep_->SetIsEnabled(false);
1387+
1388+
m_isWaitingForSegment = false;
13581389
}
13591390

13601391
void adaptive::AdaptiveStream::clear()

src/common/AdaptiveStream.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,9 @@ enum class EVENT_TYPE
125125

126126
uint64_t GetCurrentPTSOffset() const { return currentPTSOffset_; }
127127
uint64_t GetAbsolutePTSOffset() const { return absolutePTSOffset_; }
128-
bool waitingForSegment() const;
128+
129+
bool OnSampleRequested();
130+
129131
void FixateInitialization(bool on);
130132
void AllowBufferQueue(bool isAllowed) { m_isAllowedBufferQueue = isAllowed; }
131133
void SetSegmentFileOffset(uint64_t offset) { m_segmentFileOffset = offset; };
@@ -140,6 +142,8 @@ enum class EVENT_TYPE
140142
*/
141143
bool IsRequiredCreateMovieAtom();
142144

145+
bool IsWaitingForSegment() const { return m_isWaitingForSegment; }
146+
143147
protected:
144148
virtual bool parseIndexRange(PLAYLIST::CRepresentation* rep,
145149
const std::vector<uint8_t>& buffer);
@@ -162,6 +166,9 @@ enum class EVENT_TYPE
162166
std::string m_streamParams;
163167
std::map<std::string, std::string> m_streamHeaders;
164168

169+
bool m_isWaitingForSegment{false};
170+
mutable std::chrono::time_point<std::chrono::steady_clock> m_tsOnSampleRequest{};
171+
165172
/*!
166173
* \brief Download a file, the representation chooser will be updated with current download speed.
167174
* \param downloadInfo The info about the file to download

src/common/Representation.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,6 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA
145145
bool IsEnabled() const { return m_isEnabled; }
146146
void SetIsEnabled(bool isEnabled) { m_isEnabled = isEnabled; }
147147

148-
bool IsWaitForSegment() const { return m_isWaitForSegment; }
149-
void SetIsWaitForSegment(bool isWaitForSegment) { m_isWaitForSegment = isWaitForSegment; }
150-
151148
// Define if it is a dummy representation for audio stream, that is embedded on the video stream
152149
bool IsIncludedStream() const { return m_isIncludedStream; }
153150
void SetIsIncludedStream(bool isIncludedStream) { m_isIncludedStream = isIncludedStream; }
@@ -229,7 +226,6 @@ class ATTR_DLL_LOCAL CRepresentation : public CCommonSegAttribs, public CCommonA
229226
bool m_isSubtitleFileStream{false};
230227

231228
bool m_isEnabled{false};
232-
bool m_isWaitForSegment{false};
233229

234230
bool m_isIncludedStream{false};
235231
std::vector<DRM::DRMInfo> m_drmInfo;

src/common/SegmentBuffer.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,21 @@ const size_t ADP::CSegmentBuffers::GetSize() const
144144
return m_buffers.size();
145145
}
146146

147+
const size_t ADP::CSegmentBuffers::GetSizeDownloaded() const
148+
{
149+
std::lock_guard<std::mutex> lock(m_mutex);
150+
size_t size{0};
151+
for (const auto& segBuffer : m_buffers)
152+
{
153+
if (segBuffer.State() == BufferState::DOWNLOADED ||
154+
segBuffer.State() == BufferState::DOWNLOADING)
155+
size++;
156+
else
157+
break;
158+
}
159+
return size;
160+
}
161+
147162
const bool ADP::CSegmentBuffers::IsEmpty() const
148163
{
149164
std::lock_guard<std::mutex> lock(m_mutex);

src/common/SegmentBuffer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ class ATTR_DLL_LOCAL CSegmentBuffers
139139
*/
140140
const size_t GetSize() const;
141141

142+
/*!
143+
* \brief Get the current number of elements contained in the segment buffers container that are in download or downloaded.
144+
*/
145+
const size_t GetSizeDownloaded() const;
146+
142147
/*!
143148
* \brief Determines whether the segment buffers container is empty.
144149
* \return True if empty, otherwise false.

src/parser/DASHTree.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,12 +1738,6 @@ void adaptive::CDashTree::OnUpdateSegments()
17381738
LOG::LogF(LOGDEBUG, "MPD update - Done (repr. id \"%s\", period id \"%s\")",
17391739
updRepr->GetId().c_str(), period->GetId().c_str());
17401740
}
1741-
1742-
if (repr->IsWaitForSegment() && repr->GetNextSegment())
1743-
{
1744-
repr->SetIsWaitForSegment(false);
1745-
LOG::LogF(LOGDEBUG, "End WaitForSegment repr. id %s", repr->GetId().c_str());
1746-
}
17471741
}
17481742
}
17491743
}
@@ -1875,14 +1869,6 @@ void adaptive::CDashTree::InsertLiveSegment(PLAYLIST::CPeriod* currPeriod,
18751869
PLAYLIST::CAdaptationSet* currAdpSet,
18761870
PLAYLIST::CRepresentation* currRepr)
18771871
{
1878-
// InsertLiveSegment is called very frequently, since this implementation update all manifest data
1879-
// you do not need to have all these callbacks in such a short time
1880-
auto now = std::chrono::steady_clock::now();
1881-
if (now - m_insertLiveSegUpdate < std::chrono::milliseconds(500))
1882-
return;
1883-
1884-
m_insertLiveSegUpdate = now;
1885-
18861872
// This code will keep updated the timeline on all representations
18871873
// (across all periods) with current now time (TSB included),
18881874
// exclusive case of representations having SegmentTemplate without defined timeline
@@ -1952,12 +1938,6 @@ void adaptive::CDashTree::InsertLiveSegment(PLAYLIST::CPeriod* currPeriod,
19521938
period->SetTlDuration(tlDuration);
19531939
}
19541940
}
1955-
1956-
if (rep->IsWaitForSegment())
1957-
{
1958-
rep->SetIsWaitForSegment(false);
1959-
LOG::LogF(LOGDEBUG, "End WaitForSegment repr. id %s", rep->GetId().c_str());
1960-
}
19611941
}
19621942
}
19631943
}

src/parser/DASHTree.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ class ATTR_DLL_LOCAL CDashTree : public adaptive::AdaptiveTree
126126
uint64_t m_minimumUpdatePeriod{PLAYLIST::NO_VALUE}; // in seconds, NO_VALUE if not set
127127
std::optional<int64_t> m_clockOffset; // Clock offset in ms, based on UTCTiming element
128128

129-
// The time point when the last live "insert segment update" has been called
130-
mutable std::chrono::time_point<std::chrono::steady_clock> m_insertLiveSegUpdate{};
131-
132129
std::string m_locationUrl; // Redirect manifest updates
133130
};
134131
} // namespace adaptive

src/parser/HLSTree.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -933,15 +933,6 @@ void adaptive::CHLSTree::PrepareSegments(PLAYLIST::CPeriod* period,
933933
rep->current_segment_.reset();
934934
}
935935
}
936-
937-
//! @todo: m_currentPeriod != m_periods.back().get() condition should be removed from here
938-
//! this is done on AdaptiveStream::ensureSegment on IsLastSegment check
939-
if (rep->IsWaitForSegment() &&
940-
(rep->GetNextSegment() || m_currentPeriod != m_periods.back().get()))
941-
{
942-
LOG::LogF(LOGDEBUG, "End WaitForSegment stream id \"%s\"", rep->GetId().c_str());
943-
rep->SetIsWaitForSegment(false);
944-
}
945936
}
946937

947938
void adaptive::CHLSTree::OnDataArrived(uint64_t segNum,

0 commit comments

Comments
 (0)