Skip to content

Commit c42ade4

Browse files
authored
Merge pull request #1986 from CastagnaIT/cleanup_seek2
[Session] Rework part of SeekTime method
2 parents 194e2dd + 92dfa92 commit c42ade4

File tree

8 files changed

+204
-154
lines changed

8 files changed

+204
-154
lines changed

src/Session.cpp

Lines changed: 93 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,14 @@ bool SESSION::CSession::PrepareStream(CStream& stream, uint64_t startPts)
717717
}
718718
}
719719

720+
//! @todo: when the stream will be opened (OpenStream) while you change chapter/period during video seek,
721+
//! triggered by DEMUX_SPECIALID_STREAMCHANGE (chapter changed)
722+
//! the adaptive stream start to download segments from the start of period, for nothing,
723+
//! because when CInputStreamAdaptive::DemuxRead call CSession::OnDemuxRead
724+
//! will call Session::SeekTime method that cause to delete and cancel current downloads/buffer,
725+
//! and re-start downloads from the appropriate PTS,
726+
//! this wastes time for the video seek and resources due to unnecessary downloads
727+
//! more likely its more easy to see also cancelled downloads on log with TS streams
720728
stream.m_adStream.start_stream(startPts);
721729
stream.SetAdByteStream(std::make_unique<CAdaptiveByteStream>(&stream.m_adStream));
722730

@@ -839,35 +847,6 @@ uint64_t SESSION::CSession::GetTimeshiftBufferStart()
839847
return 0ULL;
840848
}
841849

842-
// TODO: clean this up along with seektime
843-
void SESSION::CSession::StartReader(
844-
CStream* stream, uint64_t seekTime, int64_t ptsDiff, bool preceeding, bool timing)
845-
{
846-
ISampleReader* streamReader = stream->GetReader();
847-
if (!streamReader)
848-
{
849-
LOG::LogF(LOGERROR, "Cannot get the stream reader");
850-
return;
851-
}
852-
853-
bool bReset = true;
854-
if (timing)
855-
seekTime += stream->m_adStream.GetAbsolutePTSOffset();
856-
else
857-
seekTime -= ptsDiff;
858-
859-
stream->m_adStream.seek_time(static_cast<double>(seekTime / STREAM_TIME_BASE), preceeding,
860-
bReset);
861-
862-
if (bReset)
863-
streamReader->Reset(false);
864-
865-
bool bStarted = false;
866-
streamReader->Start(bStarted);
867-
if (bStarted && (streamReader->GetInformation(stream->m_info)))
868-
m_changed = true;
869-
}
870-
871850
void SESSION::CSession::OnScreenResChange()
872851
{
873852
m_reprChooser->OnUpdateScreenRes();
@@ -992,25 +971,64 @@ bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
992971
seekTime = maxSeek;
993972
}
994973

974+
// Helper lambda to check if reader is started,
975+
// since after seeking across chapters/periods the reader is not started yet
976+
auto CheckReaderRunning = [this](CStream& stream) -> bool
977+
{
978+
auto reader = stream.GetReader();
979+
if (!reader->IsStarted())
980+
{
981+
bool isStarted = false;
982+
if (AP4_FAILED(reader->Start(isStarted)))
983+
return false;
984+
985+
if (isStarted && reader->GetInformation(stream.m_info))
986+
m_changed = true;
987+
}
988+
return true;
989+
};
990+
991+
// Helper lambda to perform seek on adaptive stream segment buffer
992+
auto SeekAdStream = [](CStream& stream, double seekSecs, bool preceeding) -> bool
993+
{
994+
if (!stream.m_adStream.seek_time(seekSecs))
995+
{
996+
stream.GetReader()->Reset(true);
997+
return false;
998+
}
999+
if (!preceeding)
1000+
stream.GetReader()->Reset(false);
1001+
1002+
return true;
1003+
};
1004+
9951005
// correct for starting segment pts value of chapter and chapter offset within program
9961006
uint64_t seekTimeCorrected{static_cast<uint64_t>(seekTime * STREAM_TIME_BASE)};
9971007
int64_t ptsDiff{0};
1008+
1009+
// If we have a timing stream, ensure it is started first and compute ptsDiff /
1010+
// corrected seek base that will be used by all other streams.
9981011
if (m_timingStream)
9991012
{
1000-
// after seeking across chapters with fmp4 streams the reader will not have started
1001-
// so we start here to ensure that we have the required information to correctly
1002-
// seek with proper stream alignment
10031013
ISampleReader* timingReader{m_timingStream->GetReader()};
10041014
if (!timingReader)
10051015
{
1006-
LOG::LogF(LOGERROR, "Cannot get the stream sample reader");
1016+
LOG::LogF(LOGERROR, "Cannot get the stream sample reader of timing stream");
10071017
return false;
10081018
}
1019+
10091020
timingReader->WaitReadSampleAsyncComplete();
1010-
if (!timingReader->IsStarted())
1011-
StartReader(m_timingStream.get(), seekTimeCorrected, ptsDiff, preceeding, true);
10121021

10131022
seekTimeCorrected += m_timingStream->m_adStream.GetAbsolutePTSOffset();
1023+
1024+
const double seekSecs = static_cast<double>(seekTimeCorrected) / STREAM_TIME_BASE;
1025+
1026+
if (!SeekAdStream(*m_timingStream, seekSecs, preceeding))
1027+
return false;
1028+
1029+
if (!CheckReaderRunning(*m_timingStream))
1030+
return false;
1031+
10141032
ptsDiff = timingReader->GetPTSDiff();
10151033
if (ptsDiff < 0 && seekTimeCorrected + ptsDiff > seekTimeCorrected)
10161034
seekTimeCorrected = 0;
@@ -1025,54 +1043,49 @@ bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
10251043
continue;
10261044

10271045
streamReader->WaitReadSampleAsyncComplete();
1028-
if (stream->IsEnabled())
1046+
if (!stream->IsEnabled())
1047+
continue;
1048+
1049+
// With FMP4 audio stream included to video stream you must not seek with AdaptiveStream
1050+
// segments are managed by AdaptiveStream of the video stream
1051+
// so CFragmentedSampleReader read data from the reader of the video stream
1052+
const bool hasAdStream = !(streamReader->GetType() == ISampleReader::Type::FMP4 &&
1053+
stream->m_adStream.getRepresentation()->IsIncludedStream());
1054+
1055+
if (hasAdStream && m_timingStream != stream) // Do not "seek time" on "timing stream" already done above
10291056
{
1030-
bool reset{false};
1031-
// all streams must be started before seeking to ensure cross chapter seeks
1032-
// will seek to the correct location/segment
1033-
if (!streamReader->IsStarted())
1034-
StartReader(stream.get(), seekTimeCorrected, ptsDiff, preceeding, false);
1035-
1036-
streamReader->SetPTSDiff(ptsDiff);
1037-
1038-
double seekSecs{static_cast<double>(seekTimeCorrected - ptsDiff) /
1039-
STREAM_TIME_BASE};
1040-
1041-
// With FMP4 audio stream included to video stream you must not seek with AdaptiveStream
1042-
// segments are managed by AdaptiveStream of the video stream
1043-
// so CFragmentedSampleReader read data from the reader of the video stream
1044-
const bool noAdStream = streamReader->GetType() == ISampleReader::Type::FMP4 &&
1045-
stream->m_adStream.getRepresentation()->IsIncludedStream();
1046-
1047-
if (noAdStream || stream->m_adStream.seek_time(seekSecs, preceeding, reset))
1057+
const double seekSecs{static_cast<double>(seekTimeCorrected - ptsDiff) / STREAM_TIME_BASE};
1058+
1059+
if (!SeekAdStream(*stream, seekSecs, preceeding))
1060+
continue;
1061+
}
1062+
1063+
if (!CheckReaderRunning(*stream))
1064+
continue;
1065+
1066+
streamReader->SetPTSDiff(ptsDiff);
1067+
1068+
if (!streamReader->TimeSeek(seekTimeCorrected, preceeding))
1069+
{
1070+
streamReader->Reset(true);
1071+
}
1072+
else
1073+
{
1074+
double destTime{static_cast<double>(PTSToElapsed(streamReader->PTS())) / STREAM_TIME_BASE};
1075+
1076+
// Note: TS sample reader with included streams have a dynamic streamId,
1077+
// so could be that will be printed on log stream id referred to audio or video,
1078+
// maybe this could be improved on sample reader to always start the seek from a video packet
1079+
LOG::Log(LOGINFO, "Seek time %0.1lf for stream: %i continues at %0.1lf (PTS: %llu)", seekTime,
1080+
streamReader->GetStreamId(), destTime, streamReader->PTS());
1081+
1082+
if (stream->m_info.GetStreamType() == INPUTSTREAM_TYPE_VIDEO)
10481083
{
1049-
if (reset)
1050-
streamReader->Reset(false);
1051-
// advance reader to requested time
1052-
if (!streamReader->TimeSeek(seekTimeCorrected, preceeding))
1053-
{
1054-
streamReader->Reset(true);
1055-
}
1056-
else
1057-
{
1058-
double destTime{static_cast<double>(PTSToElapsed(streamReader->PTS())) /
1059-
STREAM_TIME_BASE};
1060-
LOG::Log(LOGINFO,
1061-
"Seek time %0.1lf for stream: %i (physical index %u) continues at %0.1lf "
1062-
"(PTS: %llu)",
1063-
seekTime, streamReader->GetStreamId(), stream->m_info.GetPhysicalIndex(),
1064-
destTime, streamReader->PTS());
1065-
if (stream->m_info.GetStreamType() == INPUTSTREAM_TYPE_VIDEO)
1066-
{
1067-
seekTime = destTime;
1068-
seekTimeCorrected = streamReader->PTS();
1069-
preceeding = false;
1070-
}
1071-
ret = true;
1072-
}
1084+
seekTime = destTime;
1085+
seekTimeCorrected = streamReader->PTS();
1086+
preceeding = false;
10731087
}
1074-
else
1075-
streamReader->Reset(true);
1088+
ret = true;
10761089
}
10771090
}
10781091

src/Session.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,6 @@ class ATTR_DLL_LOCAL CSession : public adaptive::AdaptiveStreamObserver
131131
*/
132132
uint64_t GetTimeshiftBufferStart();
133133

134-
/*! \brief Align adaptiveStream and start stream reader
135-
* \param stream The stream to start
136-
* \param seekTime The pts value to start the stream at
137-
* \param ptsDiff The pts difference to adjust seekTime by
138-
* \param preceeding True to ask reader to seek to preceeding sync point
139-
* \param timing True if this is the initial starting stream
140-
*/
141-
void StartReader(
142-
CStream* stream, uint64_t seekTime, int64_t ptsDiff, bool preceeding, bool timing);
143-
144134
/*! \brief Check if the stream has changed, reset changed status
145135
* \param bSet True to keep m_changed value true
146136
* \return True if stream has changed

0 commit comments

Comments
 (0)