From fd1d8006f09a341662bcf02d99bd6ad10c33a391 Mon Sep 17 00:00:00 2001 From: matthewjheaney Date: Mon, 22 Nov 2010 15:57:25 -0500 Subject: [PATCH] moved seek function from segment to track Change-Id: Ie34549cea4c5d961b6cc04ef229a3eadc1f0ee3b --- mkvparser.cpp | 180 +++++++++++++++++++++++++++++++++++++++++++++++++- mkvparser.hpp | 7 +- 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/mkvparser.cpp b/mkvparser.cpp index 38e1f4c..77d5fe6 100644 --- a/mkvparser.cpp +++ b/mkvparser.cpp @@ -2666,6 +2666,7 @@ const Cluster* Segment::FindCluster(long long time_ns) const } +#if 0 const BlockEntry* Segment::Seek( long long time_ns, const Track* pTrack) const @@ -2808,6 +2809,7 @@ const BlockEntry* Segment::Seek( return pTrack->GetEOS(); } +#endif #if 0 @@ -3107,7 +3109,9 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const const Block* const pBlock = pBlockEntry->GetBlock(); assert(pBlock); - if (pBlock->GetTrackNumber() == m_info.number) + const long long tn = pBlock->GetTrackNumber(); + + if ((tn == m_info.number) && VetEntry(pBlockEntry)) return 0; pBlockEntry = pCluster->GetNext(pBlockEntry); @@ -3322,6 +3326,98 @@ bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const } +long VideoTrack::Seek( + long long time_ns, + const BlockEntry*& pResult) const +{ + const long status = GetFirst(pResult); + + if (status < 0) //buffer underflow, etc + return status; + + assert(pResult); + + if (pResult->EOS()) + return 0; + + const long count = m_pSegment->GetCount(); + assert(count > 0); + + const Cluster* pCluster = pResult->GetCluster(); + assert(pCluster); + assert(pCluster->m_index >= 0); + assert(pCluster->m_index < count); + + if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) + return 0; + + Cluster** const i = m_pSegment->m_clusters + pCluster->m_index; + assert(i); + assert(*i == pCluster); + assert(pCluster->GetTime() <= time_ns); + + Cluster** const j = i + count; + + Cluster** lo = i; + Cluster** hi = j; + + while (lo < hi) + { + //INVARIANT: + //[i, lo) <= time_ns + //[lo, hi) ? + //[hi, j) > time_ns + + Cluster** const mid = lo + (hi - lo) / 2; + assert(mid < hi); + + pCluster = *mid; + assert(pCluster); + assert(pCluster->m_index == long(mid - m_pSegment->m_clusters)); + + const long long t = pCluster->GetTime(); + + if (t <= time_ns) + lo = mid + 1; + else + hi = mid; + + assert(lo <= hi); + } + + assert(lo == hi); + assert(lo > i); + assert(lo <= j); + + pCluster = *--lo; + assert(pCluster); + assert(pCluster->GetTime() <= time_ns); + + pResult = pCluster->GetEntry(this, time_ns); + + if ((pResult != 0) && !pResult->EOS()) //found a keyframe + return 0; + + while (lo != i) + { + pCluster = *--lo; + assert(pCluster); + assert(pCluster->GetTime() <= time_ns); + + pResult = pCluster->GetMaxKey(this); + + if ((pResult != 0) && !pResult->EOS()) + return 0; + } + + //weird: we're on the first cluster, but no keyframe found + //should never happen but we must return something anyway + + pResult = GetEOS(); + return 0; +} + + long long VideoTrack::GetWidth() const { return m_width; @@ -3413,6 +3509,88 @@ bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const } +long AudioTrack::Seek( + long long time_ns, + const BlockEntry*& pResult) const +{ + const long status = GetFirst(pResult); + + if (status < 0) //buffer underflow, etc + return status; + + assert(pResult); + + if (pResult->EOS()) + return 0; + + const long count = m_pSegment->GetCount(); + assert(count > 0); + + const Cluster* pCluster = pResult->GetCluster(); + assert(pCluster); + assert(pCluster->m_index >= 0); + assert(pCluster->m_index < count); + + if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) + return 0; + + Cluster** const i = m_pSegment->m_clusters + pCluster->m_index; + assert(i); + assert(*i == pCluster); + assert(pCluster->GetTime() <= time_ns); + + Cluster** const j = i + count; + + Cluster** lo = i; + Cluster** hi = j; + + while (lo < hi) + { + //INVARIANT: + //[i, lo) <= time_ns + //[lo, hi) ? + //[hi, j) > time_ns + + Cluster** const mid = lo + (hi - lo) / 2; + assert(mid < hi); + + pCluster = *mid; + assert(pCluster); + assert(pCluster->m_index == long(mid - m_pSegment->m_clusters)); + + const long long t = pCluster->GetTime(); + + if (t <= time_ns) + lo = mid + 1; + else + hi = mid; + + assert(lo <= hi); + } + + assert(lo == hi); + assert(lo > i); + assert(lo <= j); + + while (lo > i) + { + pCluster = *--lo; + assert(pCluster); + assert(pCluster->GetTime() <= time_ns); + + pResult = pCluster->GetEntry(this); + + if ((pResult != 0) && !pResult->EOS()) + return 0; + + //landed on empty cluster (no entries) + } + + pResult = GetEOS(); //weird + return 0; +} + + double AudioTrack::GetSamplingRate() const { return m_rate; diff --git a/mkvparser.hpp b/mkvparser.hpp index 87979bb..57f6ac3 100644 --- a/mkvparser.hpp +++ b/mkvparser.hpp @@ -244,6 +244,7 @@ public: long GetFirst(const BlockEntry*&) const; long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const; virtual bool VetEntry(const BlockEntry*) const = 0; + virtual long Seek(long long time_ns, const BlockEntry*&) const = 0; protected: Track(Segment*, const Info&); @@ -278,6 +279,7 @@ public: double GetFrameRate() const; bool VetEntry(const BlockEntry*) const; + long Seek(long long time_ns, const BlockEntry*&) const; private: long long m_width; @@ -298,6 +300,7 @@ public: long long GetChannels() const; long long GetBitDepth() const; bool VetEntry(const BlockEntry*) const; + long Seek(long long time_ns, const BlockEntry*&) const; private: double m_rate; @@ -506,6 +509,8 @@ private: class Segment { friend class Cues; + friend class VideoTrack; + friend class AudioTrack; Segment(const Segment&); Segment& operator=(const Segment&); @@ -546,7 +551,7 @@ public: const Cluster* GetNext(const Cluster*); const Cluster* FindCluster(long long time_nanoseconds) const; - const BlockEntry* Seek(long long time_nanoseconds, const Track*) const; + //const BlockEntry* Seek(long long time_nanoseconds, const Track*) const; private: