Skip to content

Commit 41a1cee

Browse files
committed
Seek fixes and improvements
1 parent 5740d80 commit 41a1cee

6 files changed

Lines changed: 79 additions & 61 deletions

File tree

src/Session.cpp

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -911,10 +911,8 @@ bool SESSION::CSession::GetNextSample(ISampleReader*& sampleReader)
911911
return false;
912912
}
913913

914-
bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
914+
bool SESSION::CSession::SeekTime(double seekTime, bool& isError, bool preceeding)
915915
{
916-
bool ret{false};
917-
918916
if (m_streams.empty())
919917
return false;
920918

@@ -949,26 +947,14 @@ bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
949947

950948
seekTime -= chapterTime;
951949

952-
// don't try to seek past the end of the stream, leave a sensible amount so we can buffer properly
953950
if (m_adaptiveTree->IsLive())
954951
{
955-
double maxSeek{0};
956-
uint64_t curTime;
957-
uint64_t maxTime{0};
958-
for (auto& stream : m_streams)
959-
{
960-
if (stream->IsEnabled() && (curTime = stream->m_adStream.getMaxTimeMs()) && curTime > maxTime)
961-
{
962-
maxTime = curTime;
963-
}
964-
}
952+
double delayPtsSecs =
953+
(static_cast<double>(GetMediaDurationMs()) / 1000) - m_adaptiveTree->m_liveDelay;
965954

966-
maxSeek = (static_cast<double>(maxTime) / 1000) - m_adaptiveTree->m_liveDelay;
967-
if (maxSeek < 0)
968-
maxSeek = 0;
969-
970-
if (seekTime > maxSeek)
971-
seekTime = maxSeek;
955+
// Check to avoid seek into live delay duration portion, to allow an appropriate live buffering
956+
if (seekTime > delayPtsSecs)
957+
seekTime = delayPtsSecs;
972958
}
973959

974960
// Helper lambda to check if reader is started,
@@ -993,7 +979,7 @@ bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
993979
{
994980
if (!stream.m_adStream.seek_time(seekSecs))
995981
{
996-
stream.GetReader()->Reset(true);
982+
stream.GetReader()->Reset(false);
997983
return false;
998984
}
999985
if (!preceeding)
@@ -1057,17 +1043,22 @@ bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
10571043
const double seekSecs{static_cast<double>(seekTimeCorrected - ptsDiff) / STREAM_TIME_BASE};
10581044

10591045
if (!SeekAdStream(*stream, seekSecs, preceeding))
1060-
continue;
1046+
return false;
10611047
}
10621048

10631049
if (!CheckReaderRunning(*stream))
1064-
continue;
1050+
return false;
10651051

10661052
streamReader->SetPTSDiff(ptsDiff);
10671053

10681054
if (!streamReader->TimeSeek(seekTimeCorrected, preceeding))
10691055
{
1056+
//! @todo: check whether we can better manage EOS on stream readers
1057+
//! if it fails for other reasons, we could avoid setting isError
1058+
//! to allow an attempt to restore playback to previous state (see PosTime method)
10701059
streamReader->Reset(true);
1060+
isError = true;
1061+
return false;
10711062
}
10721063
else
10731064
{
@@ -1085,11 +1076,9 @@ bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
10851076
seekTimeCorrected = streamReader->PTS();
10861077
preceeding = false;
10871078
}
1088-
ret = true;
10891079
}
10901080
}
1091-
1092-
return ret;
1081+
return true;
10931082
}
10941083

10951084
void SESSION::CSession::OnDemuxRead()
@@ -1100,7 +1089,10 @@ void SESSION::CSession::OnDemuxRead()
11001089

11011090
if (GetChapterSeekTime() > 0)
11021091
{
1103-
SeekTime(GetChapterSeekTime());
1092+
bool isError{false};
1093+
if (!SeekTime(GetChapterSeekTime(), isError))
1094+
DeleteStreams();
1095+
11041096
ResetChapterSeekTime();
11051097
}
11061098
}
@@ -1344,3 +1336,11 @@ PLAYLIST::CAdaptationSet* SESSION::CSession::DetermineDefaultAdpSet(PLAYLIST::CP
13441336

13451337
return defaultAdp;
13461338
}
1339+
1340+
uint64_t SESSION::CSession::GetMediaDurationMs()
1341+
{
1342+
if (!m_timingStream || !m_timingStream->IsEnabled())
1343+
return 0;
1344+
1345+
return m_timingStream->m_adStream.getMaxTimeMs();
1346+
}

src/Session.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,16 @@ class ATTR_DLL_LOCAL CSession : public adaptive::AdaptiveStreamObserver
147147
*/
148148
void OnScreenResChange();
149149

150-
/*! \brief Seek streams and readers to a specified time
151-
* \param seekTime The seek time in seconds
152-
* \param preceeding True to seek to keyframe preceeding seektime,
153-
* false to clamp to the start of the next segment
154-
* \return True if seeking to another chapter or 1+ streams successfully
155-
* seeked, false on error or no streams seeked
150+
/*!
151+
* \brief Seek streams and readers to a specified time.
152+
* \param seekTime The seek time in seconds.
153+
* \param isError Cannot seek due to unrecoverable error,
154+
* in this case the method always return false.
155+
* \param preceeding True to seek to keyframe preceeding seektime,
156+
* false to clamp to the start of the next segment.
157+
* \return True if the operation is successful (or seek through chapter/s), otherwise false
156158
*/
157-
bool SeekTime(double seekTime, bool preceeding = true);
159+
bool SeekTime(double seekTime, bool& isError, bool preceeding = true);
158160

159161
/*! \brief Report if the current content is dynamic/live
160162
* \return True if live, false if VOD
@@ -264,6 +266,11 @@ class ATTR_DLL_LOCAL CSession : public adaptive::AdaptiveStreamObserver
264266
*/
265267
PLAYLIST::CAdaptationSet* DetermineDefaultAdpSet(PLAYLIST::CPeriod* period);
266268

269+
/*!
270+
* \brief Get the media duration in ms, based on segments.
271+
*/
272+
uint64_t GetMediaDurationMs();
273+
267274
private:
268275
DRM::CDRMEngine m_drmEngine;
269276

src/common/AdaptiveStream.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,25 +1135,21 @@ bool adaptive::AdaptiveStream::seek(uint64_t const pos, bool& isEos)
11351135

11361136
uint64_t adaptive::AdaptiveStream::getMaxTimeMs()
11371137
{
1138-
if (current_rep_->Timeline().IsEmpty())
1138+
const CSegment* lastSeg = current_rep_->Timeline().GetBack();
1139+
if (!lastSeg)
11391140
return 0;
11401141

1141-
uint64_t duration{0};
1142-
if (current_rep_->Timeline().GetSize() > 1)
1142+
const uint64_t maxPts =
1143+
(lastSeg->m_endPts * current_rep_->timescale_ext_) / current_rep_->timescale_int_;
1144+
1145+
if (absolutePTSOffset_ > maxPts)
11431146
{
1144-
duration =
1145-
current_rep_->Timeline().Get(current_rep_->Timeline().GetSize() - 1)->startPTS_ -
1146-
current_rep_->Timeline().Get(current_rep_->Timeline().GetSize() - 2)->startPTS_;
1147+
LOG::LogF(LOGERROR, "Absolute PTS offset (%llu) exceeds max PTS (%llu)", absolutePTSOffset_,
1148+
maxPts);
1149+
return 0;
11471150
}
11481151

1149-
uint64_t timeExt = ((current_rep_->Timeline()
1150-
.Get(current_rep_->Timeline().GetSize() - 1)
1151-
->startPTS_ +
1152-
duration) *
1153-
current_rep_->timescale_ext_) /
1154-
current_rep_->timescale_int_;
1155-
1156-
return (timeExt - absolutePTSOffset_) / 1000;
1152+
return (maxPts - absolutePTSOffset_) / 1000;
11571153
}
11581154

11591155
void adaptive::AdaptiveStream::Disable()
@@ -1231,7 +1227,7 @@ bool adaptive::AdaptiveStream::seek_time(double seek_seconds)
12311227
std::lock_guard<adaptive::AdaptiveTree::TreeUpdateThread> lckUpdTree(m_tree->GetTreeUpdMutex());
12321228

12331229
const uint64_t pts = static_cast<uint64_t>(seek_seconds * current_rep_->GetTimescale());
1234-
const CSegment* seekSeg = current_rep_->Timeline().FindByPTSOrNext(pts);
1230+
const CSegment* seekSeg = current_rep_->Timeline().FindByNearestPTS(pts);
12351231

12361232
if (!seekSeg)
12371233
return false;

src/main.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -301,13 +301,6 @@ DEMUX_PACKET* CInputStreamAdaptive::DemuxRead(void)
301301
// since it can cause to reopen all streams, reset the check just before
302302
m_checkCoreReopen = false;
303303

304-
if (~m_failedSeekTime)
305-
{
306-
LOG::Log(LOGDEBUG, "Seeking to last failed seek position (%d)", m_failedSeekTime);
307-
m_session->SeekTime(static_cast<double>(m_failedSeekTime) * 0.001f, false);
308-
m_failedSeekTime = ~0;
309-
}
310-
311304
ISampleReader* sr{nullptr};
312305

313306
if (m_session->GetNextSample(sr))
@@ -425,15 +418,36 @@ void CInputStreamAdaptive::SetVideoResolution(unsigned int width,
425418

426419
bool CInputStreamAdaptive::PosTime(int ms)
427420
{
421+
// Note: VP may require a seek (ms) even beyond the total duration of the media.
422+
// Note: When you return false VP will continue to request packets with DemuxRead callbacks
423+
// VP should expect to continue playback from the last PTS fed (as if the seek had not occurred)
424+
// or you can stop playback by forcibly stop the packet feed from DemuxRead callbacks.
428425
if (!m_session)
429426
return false;
430427

431428
LOG::Log(LOGINFO, "PosTime (%d)", ms);
432429

433-
bool ret = m_session->SeekTime(static_cast<double>(ms) * 0.001f, false);
434-
m_failedSeekTime = ret ? ~0 : ms;
430+
const uint64_t currentTimeMs = m_session->GetElapsedTimeMs();
431+
bool isError{false};
432+
433+
if (m_session->SeekTime(static_cast<double>(ms) * 0.001f, isError, false))
434+
return true;
435+
436+
if (!isError)
437+
{
438+
// If for some reason the seek operation fails without errors
439+
// try to restore the streams/readers to previous (current) position
440+
LOG::Log(LOGWARNING, "PosTime - Seek failed. Attempt to restore previous %llu ms position",
441+
currentTimeMs);
435442

436-
return ret;
443+
if (m_session->SeekTime(static_cast<double>(currentTimeMs) * 0.001f, isError, false))
444+
return false; // returns false because the initially requested seek was unsuccessful
445+
}
446+
447+
// A problem has occurred or EOS, force stop playback
448+
LOG::Log(LOGDEBUG, "PosTime - Cannot seek at %d ms position.", ms);
449+
m_session->DeleteStreams();
450+
return false;
437451
}
438452

439453
int CInputStreamAdaptive::GetTotalTime()

src/main.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ class ATTR_DLL_LOCAL CInputStreamAdaptive : public kodi::addon::CInstanceInputSt
5757

5858
private:
5959
std::shared_ptr<SESSION::CSession> m_session;
60-
int m_failedSeekTime = ~0;
6160

6261
// The last PTS of the segment package fed to kodi.
6362
// NO_PTS_VALUE only when playback starts or a new period starts

src/samplereader/FragmentedSampleReader.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ bool CFragmentedSampleReader::TimeSeek(uint64_t pts, bool preceeding)
311311
AP4_Result result = m_lReader->SeekSample(m_track->GetId(), seekPos, sampleIndex, preceeding);
312312
if (AP4_FAILED(result))
313313
{
314-
LOG::LogF(LOGERROR, "Cannot seek track id %u, error %i", m_track->GetId(), result);
314+
if (result != AP4_ERROR_EOS)
315+
LOG::LogF(LOGERROR, "Cannot seek track id %u, error %i", m_track->GetId(), result);
316+
315317
return false;
316318
}
317319

0 commit comments

Comments
 (0)