allow seeking beyond end of cluster cache
Change-Id: I254039af3cb72039b5204f52d0dd613f7a47782d
This commit is contained in:
parent
6efbd56948
commit
1cf3a81c78
317
mkvparser.cpp
317
mkvparser.cpp
@ -1305,14 +1305,14 @@ void Segment::AppendCluster(Cluster* pCluster)
|
|||||||
assert(pCluster);
|
assert(pCluster);
|
||||||
assert(pCluster->m_index >= 0);
|
assert(pCluster->m_index >= 0);
|
||||||
|
|
||||||
|
const long count = m_clusterCount + m_clusterPreloadCount;
|
||||||
|
|
||||||
long& size = m_clusterSize;
|
long& size = m_clusterSize;
|
||||||
assert(size >= m_clusterCount);
|
assert(size >= count);
|
||||||
|
|
||||||
const long idx = pCluster->m_index;
|
const long idx = pCluster->m_index;
|
||||||
assert(idx == m_clusterCount);
|
assert(idx == m_clusterCount);
|
||||||
|
|
||||||
const long count = m_clusterCount + m_clusterPreloadCount;
|
|
||||||
|
|
||||||
if (count >= size)
|
if (count >= size)
|
||||||
{
|
{
|
||||||
long n;
|
long n;
|
||||||
@ -1377,6 +1377,76 @@ void Segment::AppendCluster(Cluster* pCluster)
|
|||||||
++m_clusterCount;
|
++m_clusterCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx)
|
||||||
|
{
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->m_index < 0);
|
||||||
|
assert(idx >= m_clusterCount);
|
||||||
|
|
||||||
|
const long count = m_clusterCount + m_clusterPreloadCount;
|
||||||
|
|
||||||
|
long& size = m_clusterSize;
|
||||||
|
assert(size >= count);
|
||||||
|
|
||||||
|
if (count >= size)
|
||||||
|
{
|
||||||
|
long n;
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
n = 2 * size;
|
||||||
|
else if (m_pInfo == 0)
|
||||||
|
n = 2048;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const long long ns = m_pInfo->GetDuration();
|
||||||
|
|
||||||
|
if (ns <= 0)
|
||||||
|
n = 2048;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const long long sec = (ns + 999999999LL) / 1000000000LL;
|
||||||
|
n = static_cast<long>(sec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cluster** const qq = new Cluster*[n];
|
||||||
|
Cluster** q = qq;
|
||||||
|
|
||||||
|
Cluster** p = m_clusters;
|
||||||
|
Cluster** const pp = p + count;
|
||||||
|
|
||||||
|
while (p != pp)
|
||||||
|
*q++ = *p++;
|
||||||
|
|
||||||
|
delete[] m_clusters;
|
||||||
|
|
||||||
|
m_clusters = qq;
|
||||||
|
size = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_clusters);
|
||||||
|
|
||||||
|
Cluster** const p = m_clusters + idx;
|
||||||
|
|
||||||
|
Cluster** q = m_clusters + count;
|
||||||
|
assert(q >= p);
|
||||||
|
assert(q < (m_clusters + size));
|
||||||
|
|
||||||
|
while (q > p)
|
||||||
|
{
|
||||||
|
Cluster** const qq = q - 1;
|
||||||
|
assert((*qq)->m_index < 0);
|
||||||
|
|
||||||
|
*q = *qq;
|
||||||
|
q = qq;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_clusters[idx] = pCluster;
|
||||||
|
++m_clusterPreloadCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
long Segment::Load()
|
long Segment::Load()
|
||||||
{
|
{
|
||||||
assert(m_clusters == NULL);
|
assert(m_clusters == NULL);
|
||||||
@ -2069,6 +2139,7 @@ Cluster* Segment::GetLast()
|
|||||||
return &m_eos;
|
return &m_eos;
|
||||||
|
|
||||||
const long idx = m_clusterCount - 1;
|
const long idx = m_clusterCount - 1;
|
||||||
|
|
||||||
Cluster* const pCluster = m_clusters[idx];
|
Cluster* const pCluster = m_clusters[idx];
|
||||||
assert(pCluster);
|
assert(pCluster);
|
||||||
|
|
||||||
@ -2087,19 +2158,152 @@ Cluster* Segment::GetNext(const Cluster* pCurr)
|
|||||||
assert(pCurr);
|
assert(pCurr);
|
||||||
assert(pCurr != &m_eos);
|
assert(pCurr != &m_eos);
|
||||||
assert(m_clusters);
|
assert(m_clusters);
|
||||||
assert(m_clusterCount > 0);
|
|
||||||
|
|
||||||
long idx = pCurr->m_index;
|
long idx = pCurr->m_index;
|
||||||
|
|
||||||
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
assert(m_clusterCount > 0);
|
||||||
assert(idx < m_clusterCount);
|
assert(idx < m_clusterCount);
|
||||||
assert(pCurr == m_clusters[idx]);
|
assert(pCurr == m_clusters[idx]);
|
||||||
|
|
||||||
++idx;
|
++idx;
|
||||||
|
|
||||||
if (idx >= m_clusterCount)
|
if (idx >= m_clusterCount)
|
||||||
return &m_eos;
|
return &m_eos; //caller will LoadCluster as desired
|
||||||
|
|
||||||
Cluster* const pNext = m_clusters[idx];
|
Cluster* const pNext = m_clusters[idx];
|
||||||
assert(pNext);
|
assert(pNext);
|
||||||
|
assert(pNext->m_index >= 0);
|
||||||
|
assert(pNext->m_index == idx);
|
||||||
|
|
||||||
|
return pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(m_clusterPreloadCount > 0);
|
||||||
|
|
||||||
|
const long long off_ = pCurr->m_pos;
|
||||||
|
const long long off = off_ * ((off_ < 0) ? -1 : 1);
|
||||||
|
|
||||||
|
long long pos = m_start + off;
|
||||||
|
const long long stop = m_start + m_size; //end of segment
|
||||||
|
|
||||||
|
{
|
||||||
|
long len;
|
||||||
|
|
||||||
|
long long result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
assert(result == 0); //TODO
|
||||||
|
assert((pos + len) <= stop); //TODO
|
||||||
|
|
||||||
|
const long long id = ReadUInt(m_pReader, pos, len);
|
||||||
|
assert(id == 0x0F43B675); //Cluster ID //TODO
|
||||||
|
|
||||||
|
pos += len; //consume ID
|
||||||
|
|
||||||
|
//Read Size
|
||||||
|
result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
assert(result == 0); //TODO
|
||||||
|
assert((pos + len) <= stop); //TODO
|
||||||
|
|
||||||
|
const long long size = ReadUInt(m_pReader, pos, len);
|
||||||
|
assert(size > 0); //TODO
|
||||||
|
assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
|
||||||
|
|
||||||
|
pos += len; //consume length of size of element
|
||||||
|
assert((pos + size) <= stop); //TODO
|
||||||
|
|
||||||
|
//Pos now points to start of payload
|
||||||
|
|
||||||
|
pos += size; //consume payload
|
||||||
|
}
|
||||||
|
|
||||||
|
long long off_next = 0;
|
||||||
|
|
||||||
|
while (pos < stop)
|
||||||
|
{
|
||||||
|
long len;
|
||||||
|
|
||||||
|
long long result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
assert(result == 0); //TODO
|
||||||
|
assert((pos + len) <= stop); //TODO
|
||||||
|
|
||||||
|
const long long idpos = pos; //pos of next (potential) cluster
|
||||||
|
|
||||||
|
const long long id = ReadUInt(m_pReader, idpos, len);
|
||||||
|
assert(id > 0); //TODO
|
||||||
|
|
||||||
|
pos += len; //consume ID
|
||||||
|
|
||||||
|
//Read Size
|
||||||
|
result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
assert(result == 0); //TODO
|
||||||
|
assert((pos + len) <= stop); //TODO
|
||||||
|
|
||||||
|
const long long size = ReadUInt(m_pReader, pos, len);
|
||||||
|
assert(size >= 0); //TODO
|
||||||
|
|
||||||
|
pos += len; //consume length of size of element
|
||||||
|
assert((pos + size) <= stop); //TODO
|
||||||
|
|
||||||
|
//Pos now points to start of payload
|
||||||
|
|
||||||
|
if (size == 0) //weird
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (id == 0x0F43B675) //Cluster ID
|
||||||
|
{
|
||||||
|
off_next = idpos - m_start;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += size; //consume payload
|
||||||
|
}
|
||||||
|
|
||||||
|
if (off_next <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Cluster** const ii = m_clusters + m_clusterCount;
|
||||||
|
Cluster** i = ii;
|
||||||
|
|
||||||
|
Cluster** const jj = ii + m_clusterPreloadCount;
|
||||||
|
Cluster** j = jj;
|
||||||
|
|
||||||
|
while (i < j)
|
||||||
|
{
|
||||||
|
//INVARIANT:
|
||||||
|
//[0, i) < pos_next
|
||||||
|
//[i, j) ?
|
||||||
|
//[j, jj) > pos_next
|
||||||
|
|
||||||
|
Cluster** const k = i + (j - i) / 2;
|
||||||
|
assert(k < jj);
|
||||||
|
|
||||||
|
Cluster* const pNext = *k;
|
||||||
|
assert(pNext);
|
||||||
|
assert(pNext->m_index < 0);
|
||||||
|
|
||||||
|
const long long pos_ = pNext->m_pos;
|
||||||
|
assert(pos_);
|
||||||
|
|
||||||
|
pos = pos_ * ((pos_ < 0) ? -1 : 1);
|
||||||
|
|
||||||
|
if (pos < off_next)
|
||||||
|
i = k + 1;
|
||||||
|
else if (pos > off_next)
|
||||||
|
j = k;
|
||||||
|
else
|
||||||
|
return pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(i == j);
|
||||||
|
|
||||||
|
Cluster* const pNext = Cluster::Parse(this, -1, off_next);
|
||||||
|
const ptrdiff_t idx_next = i - m_clusters; //insertion position
|
||||||
|
|
||||||
|
PreloadCluster(pNext, idx_next);
|
||||||
|
assert(m_clusters);
|
||||||
|
assert(idx_next < m_clusterSize);
|
||||||
|
assert(m_clusters[idx_next] == pNext);
|
||||||
|
|
||||||
return pNext;
|
return pNext;
|
||||||
}
|
}
|
||||||
@ -2327,7 +2531,7 @@ void Segment::GetCluster(
|
|||||||
|
|
||||||
|
|
||||||
bool Segment::SearchCues(
|
bool Segment::SearchCues(
|
||||||
long long time_ns_,
|
long long time_ns,
|
||||||
Track* pTrack,
|
Track* pTrack,
|
||||||
Cluster*& pCluster,
|
Cluster*& pCluster,
|
||||||
const BlockEntry*& pBlockEntry)
|
const BlockEntry*& pBlockEntry)
|
||||||
@ -2338,21 +2542,10 @@ bool Segment::SearchCues(
|
|||||||
if (pTrack->GetType() != 1) //not video
|
if (pTrack->GetType() != 1) //not video
|
||||||
return false; //TODO: for now, just handle video stream
|
return false; //TODO: for now, just handle video stream
|
||||||
|
|
||||||
|
#if 0
|
||||||
if ((m_clusters == NULL) || (m_clusterCount <= 0))
|
if ((m_clusters == NULL) || (m_clusterCount <= 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//TODO:
|
|
||||||
//search among cuepoints for time
|
|
||||||
//if time is less then what's already loaded then
|
|
||||||
// return that cluster and we're done
|
|
||||||
//else (time is greater than what's loaded)
|
|
||||||
// if time isn't "too far into the future" then
|
|
||||||
// pre-load the necessary clusters
|
|
||||||
// return that cluster and we're done
|
|
||||||
// else
|
|
||||||
// find (earlier) cue point corresponding to something
|
|
||||||
// already loaded in cache, and return that
|
|
||||||
|
|
||||||
const long last_idx = m_clusterCount - 1;
|
const long last_idx = m_clusterCount - 1;
|
||||||
|
|
||||||
Cluster* const pLastCluster = m_clusters[last_idx];
|
Cluster* const pLastCluster = m_clusters[last_idx];
|
||||||
@ -2438,6 +2631,75 @@ bool Segment::SearchCues(
|
|||||||
|
|
||||||
assert(i < j);
|
assert(i < j);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
const CuePoint* pCP;
|
||||||
|
const CuePoint::TrackPosition* pTP;
|
||||||
|
|
||||||
|
if (!m_pCues->Find(time_ns, pTrack, pCP, pTP))
|
||||||
|
return false; //weird
|
||||||
|
|
||||||
|
assert(pCP);
|
||||||
|
assert(pTP);
|
||||||
|
assert(pTP->m_track == pTrack->GetNumber());
|
||||||
|
|
||||||
|
//We have the cue point and track position we want,
|
||||||
|
//so we now need to search for the cluster having
|
||||||
|
//the indicated position.
|
||||||
|
|
||||||
|
Cluster** const ii = m_clusters;
|
||||||
|
Cluster** i = ii;
|
||||||
|
|
||||||
|
const long count = m_clusterCount + m_clusterPreloadCount;
|
||||||
|
|
||||||
|
Cluster** const jj = ii + count;
|
||||||
|
Cluster** j = jj;
|
||||||
|
|
||||||
|
while (i < j)
|
||||||
|
{
|
||||||
|
//INVARIANT:
|
||||||
|
//[0, i) < pTP->m_pos
|
||||||
|
//[i, j) ?
|
||||||
|
//[j, jj) > pTP->m_pos
|
||||||
|
|
||||||
|
Cluster** const k = i + (j - i) / 2;
|
||||||
|
assert(k < jj);
|
||||||
|
|
||||||
|
pCluster = *k;
|
||||||
|
assert(pCluster);
|
||||||
|
|
||||||
|
const long long pos_ = pCluster->m_pos;
|
||||||
|
assert(pos_);
|
||||||
|
|
||||||
|
const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
|
||||||
|
|
||||||
|
if (pos < pTP->m_pos)
|
||||||
|
i = k + 1;
|
||||||
|
else if (pos > pTP->m_pos)
|
||||||
|
j = k;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pBlockEntry = pCluster->GetEntry(*pCP, *pTP);
|
||||||
|
assert(pBlockEntry);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(i == j);
|
||||||
|
|
||||||
|
pCluster = Cluster::Parse(this, -1, pTP->m_pos);
|
||||||
|
const ptrdiff_t idx = i - m_clusters;
|
||||||
|
|
||||||
|
PreloadCluster(pCluster, idx);
|
||||||
|
assert(m_clusters);
|
||||||
|
assert(m_clusterPreloadCount > 0);
|
||||||
|
assert(m_clusters[idx] == pCluster);
|
||||||
|
|
||||||
|
pBlockEntry = pCluster->GetEntry(*pCP, *pTP);
|
||||||
|
assert(pBlockEntry);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2660,7 +2922,13 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
|||||||
|
|
||||||
for (int i = 0; i < 100; ++i) //arbitrary upper bound
|
for (int i = 0; i < 100; ++i) //arbitrary upper bound
|
||||||
{
|
{
|
||||||
if ((pCluster == NULL) || pCluster->EOS())
|
if (pCluster == NULL)
|
||||||
|
{
|
||||||
|
pBlockEntry = GetEOS();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pCluster->EOS())
|
||||||
{
|
{
|
||||||
if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
|
if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
|
||||||
{
|
{
|
||||||
@ -2693,7 +2961,7 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
|||||||
//might be too conservative).
|
//might be too conservative).
|
||||||
|
|
||||||
pBlockEntry = GetEOS(); //so we can return a non-NULL value
|
pBlockEntry = GetEOS(); //so we can return a non-NULL value
|
||||||
return 1L;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2728,7 +2996,13 @@ long Track::GetNext(
|
|||||||
|
|
||||||
pCluster = m_pSegment->GetNext(pCluster);
|
pCluster = m_pSegment->GetNext(pCluster);
|
||||||
|
|
||||||
if ((pCluster == NULL) || pCluster->EOS())
|
if (pCluster == NULL)
|
||||||
|
{
|
||||||
|
pNextEntry = GetEOS();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pCluster->EOS())
|
||||||
{
|
{
|
||||||
if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
|
if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
|
||||||
{
|
{
|
||||||
@ -3308,7 +3582,6 @@ Cluster* Cluster::Parse(
|
|||||||
long long off)
|
long long off)
|
||||||
{
|
{
|
||||||
assert(pSegment);
|
assert(pSegment);
|
||||||
assert(idx >= 0);
|
|
||||||
assert(off >= 0);
|
assert(off >= 0);
|
||||||
assert(off < pSegment->m_size);
|
assert(off < pSegment->m_size);
|
||||||
|
|
||||||
|
@ -512,6 +512,7 @@ private:
|
|||||||
long m_clusterSize; //array size
|
long m_clusterSize; //array size
|
||||||
|
|
||||||
void AppendCluster(Cluster*);
|
void AppendCluster(Cluster*);
|
||||||
|
void PreloadCluster(Cluster*, ptrdiff_t);
|
||||||
|
|
||||||
void ParseSeekHead(long long pos, long long size);
|
void ParseSeekHead(long long pos, long long size);
|
||||||
void ParseSeekEntry(long long pos, long long size);
|
void ParseSeekEntry(long long pos, long long size);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user