smarter method for finding cluster, given a time
Change-Id: Ia727cc60deba87ab0a8da5d0576e7aeb7b273f74
This commit is contained in:
231
mkvparser.cpp
231
mkvparser.cpp
@@ -1648,6 +1648,186 @@ Cluster* Segment::GetCluster(long long time_ns)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Segment::GetCluster(
|
||||||
|
__int64 time_ns,
|
||||||
|
Track* pTrack,
|
||||||
|
Cluster*& pCluster,
|
||||||
|
const BlockEntry*& pBlockEntry)
|
||||||
|
{
|
||||||
|
assert(pTrack);
|
||||||
|
|
||||||
|
if ((m_clusters == NULL) || (m_clusterCount <= 0))
|
||||||
|
{
|
||||||
|
pCluster = &m_eos;
|
||||||
|
pBlockEntry = pTrack->GetEOS();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cluster** const i = m_clusters;
|
||||||
|
assert(i);
|
||||||
|
|
||||||
|
{
|
||||||
|
pCluster = *i;
|
||||||
|
assert(pCluster);
|
||||||
|
|
||||||
|
if (time_ns <= pCluster->GetTime())
|
||||||
|
{
|
||||||
|
pBlockEntry = pCluster->GetEntry(pTrack);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cluster** const j = i + m_clusterCount;
|
||||||
|
|
||||||
|
if (pTrack->GetType() == 2) //audio
|
||||||
|
{
|
||||||
|
//TODO: we could decide to use cues for this, as we do for video.
|
||||||
|
//But we only use it for video because looking around for a keyframe
|
||||||
|
//can get expensive. Audio doesn't require anything special we a
|
||||||
|
//straight cluster search is good enough (we assume).
|
||||||
|
#if 0
|
||||||
|
iter_t k = std::upper_bound(i, j, time_ns, Cluster::CompareTime());
|
||||||
|
assert(k != i);
|
||||||
|
|
||||||
|
pCluster = *--k;
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
#else
|
||||||
|
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);
|
||||||
|
|
||||||
|
Cluster* const pCluster = *mid;
|
||||||
|
assert(pCluster);
|
||||||
|
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pBlockEntry = pCluster->GetEntry(pTrack);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(pTrack->GetType() == 1); //video
|
||||||
|
|
||||||
|
#if 0 //TODO: add cues support
|
||||||
|
if (SearchCues(time_ns, pTrack, pCluster, pBlockEntry))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
iter_t k = std::upper_bound(i, j, time_ns, Cluster::CompareTime());
|
||||||
|
assert(k != i);
|
||||||
|
|
||||||
|
pCluster = *--k;
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
#else
|
||||||
|
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);
|
||||||
|
|
||||||
|
Cluster* const pCluster = *mid;
|
||||||
|
assert(pCluster);
|
||||||
|
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{
|
||||||
|
pBlockEntry = pCluster->GetEntry(pTrack);
|
||||||
|
assert(pBlockEntry);
|
||||||
|
|
||||||
|
if (!pBlockEntry->EOS()) //found a keyframe
|
||||||
|
{
|
||||||
|
const Block* const pBlock = pBlockEntry->GetBlock();
|
||||||
|
assert(pBlock);
|
||||||
|
|
||||||
|
//TODO: this isn't necessarily the keyframe we want,
|
||||||
|
//since there might another keyframe on this same
|
||||||
|
//cluster with a greater timecode that but that is
|
||||||
|
//still less than the requested time. For now we
|
||||||
|
//simply return the first keyframe we find.
|
||||||
|
|
||||||
|
if (pBlock->GetTime(pCluster) <= time_ns)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VideoTrack* const pVideo = static_cast<VideoTrack*>(pTrack);
|
||||||
|
|
||||||
|
while (lo != i)
|
||||||
|
{
|
||||||
|
pCluster = *--lo;
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
|
||||||
|
pBlockEntry = pCluster->GetMaxKey(pVideo);
|
||||||
|
assert(pBlockEntry);
|
||||||
|
|
||||||
|
if (!pBlockEntry->EOS())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//weird: we're on the first cluster, but no keyframe found
|
||||||
|
//should never happen but we must return something anyway
|
||||||
|
|
||||||
|
pCluster = &m_eos;
|
||||||
|
pBlockEntry = pTrack->GetEOS();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Tracks* Segment::GetTracks() const
|
Tracks* Segment::GetTracks() const
|
||||||
{
|
{
|
||||||
return m_pTracks;
|
return m_pTracks;
|
||||||
@@ -2897,16 +3077,19 @@ const BlockEntry* Cluster::GetLast()
|
|||||||
const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
|
const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
|
||||||
{
|
{
|
||||||
assert(pEntry);
|
assert(pEntry);
|
||||||
|
assert(m_pEntries);
|
||||||
|
assert(m_entriesCount);
|
||||||
|
|
||||||
size_t idx = pEntry->GetIndex();
|
size_t idx = pEntry->GetIndex();
|
||||||
|
assert(idx < m_entriesCount);
|
||||||
|
assert(m_pEntries[idx] == pEntry);
|
||||||
|
|
||||||
++idx;
|
++idx;
|
||||||
|
|
||||||
if (idx == m_entriesCount)
|
if (idx >= m_entriesCount)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return m_pEntries[idx];
|
return m_pEntries[idx];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2919,12 +3102,14 @@ const BlockEntry* Cluster::GetEntry(const Track* pTrack)
|
|||||||
|
|
||||||
LoadBlockEntries();
|
LoadBlockEntries();
|
||||||
|
|
||||||
BlockEntry* i = *m_pEntries;
|
BlockEntry** i = m_pEntries;
|
||||||
BlockEntry* j = *m_pEntries + m_entriesCount;
|
assert(i);
|
||||||
|
|
||||||
|
BlockEntry** const j = i + m_entriesCount;
|
||||||
|
|
||||||
while (i != j)
|
while (i != j)
|
||||||
{
|
{
|
||||||
BlockEntry* pEntry = i;
|
const BlockEntry* const pEntry = *i++;
|
||||||
i++;
|
|
||||||
assert(pEntry);
|
assert(pEntry);
|
||||||
assert(!pEntry->EOS());
|
assert(!pEntry->EOS());
|
||||||
|
|
||||||
@@ -2942,6 +3127,40 @@ const BlockEntry* Cluster::GetEntry(const Track* pTrack)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack)
|
||||||
|
{
|
||||||
|
assert(pTrack);
|
||||||
|
|
||||||
|
if (m_pSegment == 0) //EOS
|
||||||
|
return pTrack->GetEOS();
|
||||||
|
|
||||||
|
LoadBlockEntries();
|
||||||
|
assert(m_pEntries);
|
||||||
|
|
||||||
|
BlockEntry** i = m_pEntries + m_entriesCount;
|
||||||
|
BlockEntry** const j = m_pEntries;
|
||||||
|
|
||||||
|
while (i != j)
|
||||||
|
{
|
||||||
|
const BlockEntry* const pEntry = *--i;
|
||||||
|
assert(pEntry);
|
||||||
|
assert(!pEntry->EOS());
|
||||||
|
|
||||||
|
const Block* const pBlock = pEntry->GetBlock();
|
||||||
|
assert(pBlock);
|
||||||
|
|
||||||
|
if (pBlock->GetTrackNumber() != pTrack->GetNumber())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pBlock->IsKey())
|
||||||
|
return pEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTrack->GetEOS(); //no satisfactory block found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BlockEntry::BlockEntry()
|
BlockEntry::BlockEntry()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,6 +360,8 @@ public:
|
|||||||
const BlockEntry* GetLast();
|
const BlockEntry* GetLast();
|
||||||
const BlockEntry* GetNext(const BlockEntry*) const;
|
const BlockEntry* GetNext(const BlockEntry*) const;
|
||||||
const BlockEntry* GetEntry(const Track*);
|
const BlockEntry* GetEntry(const Track*);
|
||||||
|
const BlockEntry* GetMaxKey(const VideoTrack*);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Cluster(Segment*, size_t, long long off);
|
Cluster(Segment*, size_t, long long off);
|
||||||
|
|
||||||
@@ -418,6 +420,12 @@ public:
|
|||||||
Cluster* GetNext(const Cluster*);
|
Cluster* GetNext(const Cluster*);
|
||||||
Cluster* GetCluster(long long time_nanoseconds);
|
Cluster* GetCluster(long long time_nanoseconds);
|
||||||
|
|
||||||
|
void GetCluster(
|
||||||
|
__int64 time_nanoseconds,
|
||||||
|
Track*,
|
||||||
|
Cluster*&,
|
||||||
|
const BlockEntry*&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
long long m_pos; //absolute file posn; what has been consumed so far
|
long long m_pos; //absolute file posn; what has been consumed so far
|
||||||
SegmentInfo* m_pInfo;
|
SegmentInfo* m_pInfo;
|
||||||
|
|||||||
Reference in New Issue
Block a user