Skip to content

Commit 1f60930

Browse files
committed
[FragmentedSampleReader] Rework method to find the sample index
1 parent 195161a commit 1f60930

File tree

3 files changed

+82
-23
lines changed

3 files changed

+82
-23
lines changed

src/Session.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,13 @@ bool SESSION::CSession::SeekTime(double seekTime, bool preceeding)
10361036
seekTimeCorrected += ptsDiff;
10371037
}
10381038

1039+
// Note: At the end of the seek operations, you may notice on Kodi debug log "dropping packets" prints
1040+
// this happens because we cannot always guarantee a precise seek, for example
1041+
// with FragmentedSampleReader (MP4 samples/packets)
1042+
// we need to start feeding the Kodi demuxer with a synchronization sample/packet
1043+
// but the sync sample (packet) at least for the video track is usually not available for all PTS
1044+
// so we try choose the sample/package closest to the requested "seek" PTS, causing "dropping packets"
1045+
10391046
for (auto& stream : m_streams)
10401047
{
10411048
ISampleReader* streamReader{stream->GetReader()};

src/samplereader/FragmentedSampleReader.cpp

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
#include <bento4/Ap4SencAtom.h>
3030

31+
#include <limits>
32+
3133
using namespace UTILS;
3234

3335
namespace
@@ -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
}

src/samplereader/FragmentedSampleReader.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,7 @@ class ATTR_DLL_LOCAL CLinearReader : public AP4_LinearReader
7070
// \brief Get AP4_LinearReader::m_Movie
7171
AP4_Movie& GetMovie();
7272

73-
AP4_Result SeekSample(AP4_UI32 track_id,
74-
AP4_UI64 ts,
75-
AP4_Ordinal& sample_index,
76-
bool preceedingSync);
73+
AP4_Result SeekSample(AP4_UI32 track_id, AP4_UI64 ts, AP4_Ordinal& sample_index);
7774

7875
protected:
7976
// AP4_LinearReader implementations

0 commit comments

Comments
 (0)