2828
2929#include < bento4/Ap4SencAtom.h>
3030
31+ #include < limits>
32+
3133using namespace UTILS ;
3234
3335namespace
@@ -308,7 +310,7 @@ bool CFragmentedSampleReader::TimeSeek(uint64_t pts, bool preceeding)
308310 AP4_Ordinal sampleIndex;
309311 AP4_UI64 seekPos (static_cast <AP4_UI64>((pts * m_timeBaseInt) / m_timeBaseExt));
310312
311- AP4_Result result = m_lReader->SeekSample (m_track->GetId (), seekPos, sampleIndex, preceeding );
313+ AP4_Result result = m_lReader->SeekSample (m_track->GetId (), seekPos, sampleIndex);
312314 if (AP4_FAILED (result))
313315 {
314316 LOG::LogF (LOGERROR, " Cannot seek track id %u, error %i" , m_track->GetId (), result);
@@ -813,10 +815,7 @@ AP4_Movie& CLinearReader::GetMovie()
813815 return AP4_LinearReader::m_Movie;
814816}
815817
816- AP4_Result CLinearReader::SeekSample (AP4_UI32 track_id,
817- AP4_UI64 ts,
818- AP4_Ordinal& sample_index,
819- bool preceedingSync)
818+ AP4_Result CLinearReader::SeekSample (AP4_UI32 track_id, AP4_UI64 ts, AP4_Ordinal& sample_index)
820819{
821820 // we only support fragmented sources for now
822821 if (!m_HasFragments)
@@ -838,24 +837,23 @@ AP4_Result CLinearReader::SeekSample(AP4_UI32 track_id,
838837
839838 AP4_Result result;
840839
841- if (!tracker->m_SampleTable && AP4_FAILED (result = Advance ()))
842- return result;
843-
844- while (AP4_FAILED (result = tracker->m_SampleTable ->GetSampleIndexForTimeStamp (ts, sample_index)))
840+ if (!tracker->m_SampleTable )
845841 {
846- if (result == AP4_ERROR_NOT_ENOUGH_DATA)
842+ if (AP4_FAILED (result = Advance ()))
843+ return result;
844+ // Ensure that Advance has populated the sample table
845+ if (!tracker->m_SampleTable )
847846 {
848- tracker->m_NextSampleIndex = tracker->m_SampleTable ->GetSampleCount ();
849- if (AP4_FAILED (result = Advance ()))
850- return result;
851- continue ;
847+ LOG::LogF (LOGERROR, " No sample table" );
848+ return AP4_ERROR_INVALID_STATE;
852849 }
853- return result;
854850 }
855851
856- sample_index = tracker->m_SampleTable ->GetNearestSyncSampleIndex (sample_index, preceedingSync);
857- // we have reached the end -> go for the first sample of the next segment
858- if (sample_index == tracker->m_SampleTable ->GetSampleCount ())
852+ // ! @todo: remove our custom GetNearestSyncSampleIndex from Bento4
853+ AP4_Cardinal samplesCount = tracker->m_SampleTable ->GetSampleCount ();
854+
855+ // No samples, attempt advance to (download/read) next segment
856+ if (samplesCount == 0 )
859857 {
860858 tracker->m_NextSampleIndex = tracker->m_SampleTable ->GetSampleCount ();
861859
@@ -869,13 +867,70 @@ AP4_Result CLinearReader::SeekSample(AP4_UI32 track_id,
869867 tracker->m_SampleTableIsOwned = isOwned;
870868 return result;
871869 }
870+ // Ensure that Advance has populated the sample table
871+ if (!tracker->m_SampleTable )
872+ {
873+ LOG::LogF (LOGERROR, " No sample table" );
874+ return AP4_ERROR_INVALID_STATE;
875+ }
872876
873877 tracker->m_SampleTableIsOwned = isOwned;
874- sample_index = 0 ;
878+ samplesCount = tracker->m_SampleTable ->GetSampleCount ();
879+
880+ if (samplesCount == 0 )
881+ {
882+ LOG::LogF (LOGERROR, " No samples found in the segment packet" );
883+ return AP4_ERROR_INVALID_STATE;
884+ }
885+ }
886+
887+ constexpr AP4_Cardinal indexNoValue{std::numeric_limits<AP4_Cardinal>::max ()};
888+ AP4_Cardinal syncIndex{indexNoValue};
889+ AP4_UI64 syncCts{0 };
890+ AP4_Cardinal sampleIndex{indexNoValue};
891+
892+ // Try find a sample "sync", when possible, with equal or higher ts than the target ts
893+ // or, fallback to the sample (without sync) with nearest ts
894+ // NOTE: search exclusively within this segment,
895+ // avoiding requesting (download/read) other segments to speedup the seek operation
896+ for (AP4_Cardinal index{0 }; index < samplesCount; ++index)
897+ {
898+ AP4_Sample sample;
899+ if (AP4_FAILED (tracker->m_SampleTable ->GetSample (index, sample)))
900+ continue ;
901+
902+ const AP4_UI64 cts = sample.GetCts ();
903+ if (sample.IsSync ())
904+ {
905+ if (syncIndex == indexNoValue || syncCts < ts && cts > syncCts)
906+ {
907+ syncCts = cts;
908+ syncIndex = index;
909+ }
910+ }
911+ // Find any sample (no sync) closer to the target ts
912+ if (cts <= ts)
913+ sampleIndex = index;
914+ }
915+
916+ if (syncIndex != indexNoValue)
917+ sample_index = syncIndex;
918+ else if (sampleIndex != indexNoValue)
919+ {
920+ LOG::LogF (LOGDEBUG, " No sample sync found, fallback to sample with nearest timestamp" );
921+ sample_index = sampleIndex;
922+ }
923+ else
924+ {
925+ LOG::LogF (LOGERROR, " Cannot determine the sample index" );
926+ return AP4_ERROR_INVALID_STATE;
875927 }
876928
877929 if (!tracker->m_SampleTable ) // Required for SetSampleIndex
930+ {
931+ LOG::LogF (LOGERROR, " Missing sample table, cannot set the sample index" );
878932 return AP4_ERROR_INVALID_STATE;
933+ }
879934
880935 return SetSampleIndex (tracker->m_Track ->GetId (), sample_index);
881936}
0 commit comments