search multiple clusters for first (or next) frame
Change-Id: Ib4d50b89f1e3abe7b59d4adabc272faeb2b429a2
This commit is contained in:
parent
02679abae5
commit
276009d78a
150
mkvparser.cpp
150
mkvparser.cpp
@ -1167,10 +1167,13 @@ long Segment::Load()
|
||||
#endif
|
||||
long long index = m_pos;
|
||||
|
||||
//TODO: we don't want to count clusters here.
|
||||
//Just do a lazy init.
|
||||
|
||||
m_clusterCount = 0;
|
||||
|
||||
long long* fileposition_of_clusters = NULL;
|
||||
long long size_of_cluster_pos = 0;
|
||||
size_t size_of_cluster_pos = 0;
|
||||
|
||||
while (index < stop)
|
||||
{
|
||||
@ -1211,14 +1214,19 @@ long Segment::Load()
|
||||
if (id == 0x0F43B675) // Cluster ID
|
||||
{
|
||||
assert(fileposition_of_clusters);
|
||||
|
||||
if (m_clusterCount >= size_of_cluster_pos)
|
||||
{
|
||||
assert(size_of_cluster_pos > 0);
|
||||
size_of_cluster_pos *= 2;
|
||||
|
||||
long long* const temp = new long long[size_of_cluster_pos];
|
||||
memset(temp, 0, sizeof(long long) * size_of_cluster_pos);
|
||||
memcpy(temp, fileposition_of_clusters, sizeof(long long) \
|
||||
* m_clusterCount);
|
||||
delete [] fileposition_of_clusters;
|
||||
|
||||
const size_t size = sizeof(long long) * m_clusterCount;
|
||||
memcpy(temp, fileposition_of_clusters, size);
|
||||
|
||||
delete[] fileposition_of_clusters;
|
||||
fileposition_of_clusters = temp;
|
||||
}
|
||||
fileposition_of_clusters[m_clusterCount] = idpos;
|
||||
@ -1232,7 +1240,11 @@ long Segment::Load()
|
||||
assert(m_clusterCount == 0);
|
||||
|
||||
const long long duration = m_pInfo->GetDuration();
|
||||
size_of_cluster_pos = duration / 1000000000 + 1;
|
||||
assert(duration >= 0);
|
||||
|
||||
const long long size_of_cluster_pos_ = duration / 1000000000 + 1;
|
||||
size_of_cluster_pos = static_cast<size_t>(size_of_cluster_pos_);
|
||||
|
||||
fileposition_of_clusters = new long long[size_of_cluster_pos];
|
||||
memset(fileposition_of_clusters, 0, size_of_cluster_pos);
|
||||
}
|
||||
@ -1244,10 +1256,10 @@ long Segment::Load()
|
||||
|
||||
m_clusters = new Cluster*[m_clusterCount];
|
||||
|
||||
for (int i = 0; i < m_clusterCount; ++i)
|
||||
for (size_t i = 0; i < m_clusterCount; ++i)
|
||||
m_clusters[i] = Cluster::Parse(this, i, fileposition_of_clusters[i]);
|
||||
|
||||
delete [] fileposition_of_clusters;
|
||||
delete[] fileposition_of_clusters;
|
||||
|
||||
while (m_pos < stop)
|
||||
{
|
||||
@ -1813,8 +1825,7 @@ const BlockEntry* Track::GetEOS() const
|
||||
|
||||
long long Track::GetType() const
|
||||
{
|
||||
const unsigned long result = static_cast<unsigned long>(m_info.type);
|
||||
return result;
|
||||
return m_info.type;
|
||||
}
|
||||
|
||||
unsigned long Track::GetNumber() const
|
||||
@ -1850,12 +1861,13 @@ const unsigned char* Track::GetCodecPrivate(size_t& size) const
|
||||
|
||||
long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
||||
{
|
||||
Cluster* const pCluster = m_pSegment->GetFirst();
|
||||
Cluster* pCluster = m_pSegment->GetFirst();
|
||||
|
||||
//If Segment::GetFirst returns NULL, then this must be a network
|
||||
//download, and we haven't loaded any clusters yet. In this case,
|
||||
//returning NULL from Track::GetFirst means the same thing.
|
||||
|
||||
#if 0
|
||||
if ((pCluster == NULL) || pCluster->EOS())
|
||||
{
|
||||
pBlockEntry = NULL;
|
||||
@ -1874,6 +1886,37 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
||||
|
||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < 100; ++i) //arbitrary upper bound
|
||||
{
|
||||
if ((pCluster == NULL) || pCluster->EOS())
|
||||
{
|
||||
if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
|
||||
{
|
||||
pBlockEntry = GetEOS();
|
||||
return 1;
|
||||
}
|
||||
|
||||
pBlockEntry = 0;
|
||||
return E_BUFFER_NOT_FULL;
|
||||
}
|
||||
|
||||
pBlockEntry = pCluster->GetFirst();
|
||||
|
||||
while (pBlockEntry)
|
||||
{
|
||||
const Block* const pBlock = pBlockEntry->GetBlock();
|
||||
assert(pBlock);
|
||||
|
||||
if (pBlock->GetTrackNumber() == m_info.number)
|
||||
return 0;
|
||||
|
||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
||||
}
|
||||
|
||||
pCluster = m_pSegment->GetNext(pCluster);
|
||||
}
|
||||
#endif
|
||||
|
||||
//NOTE: if we get here, it means that we didn't find a block with
|
||||
//a matching track number. We interpret that as an error (which
|
||||
@ -1884,12 +1927,15 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
||||
}
|
||||
|
||||
|
||||
long Track::GetNext(const BlockEntry* pCurrEntry, const BlockEntry*& pNextEntry) const
|
||||
long Track::GetNext(
|
||||
const BlockEntry* pCurrEntry,
|
||||
const BlockEntry*& pNextEntry) const
|
||||
{
|
||||
assert(pCurrEntry);
|
||||
assert(!pCurrEntry->EOS()); //?
|
||||
assert(pCurrEntry->GetBlock()->GetTrackNumber() == (unsigned long)m_info.number);
|
||||
assert(pCurrEntry->GetBlock()->GetTrackNumber() == m_info.number);
|
||||
|
||||
#if 0
|
||||
const Cluster* const pCurrCluster = pCurrEntry->GetCluster();
|
||||
assert(pCurrCluster);
|
||||
assert(!pCurrCluster->EOS());
|
||||
@ -1988,6 +2034,62 @@ long Track::GetNext(const BlockEntry* pCurrEntry, const BlockEntry*& pNextEntry)
|
||||
//return E_FAIL;
|
||||
pNextEntry = GetEOS();
|
||||
return 1L;
|
||||
#else
|
||||
Cluster* pCluster = pCurrEntry->GetCluster();
|
||||
assert(pCluster);
|
||||
assert(!pCluster->EOS());
|
||||
|
||||
pNextEntry = pCluster->GetNext(pCurrEntry);
|
||||
|
||||
for (int i = 0; i < 100; ++i) //arbitrary upper bound to search
|
||||
{
|
||||
while (pNextEntry)
|
||||
{
|
||||
const Block* const pNextBlock = pNextEntry->GetBlock();
|
||||
assert(pNextBlock);
|
||||
|
||||
if (pNextBlock->GetTrackNumber() == m_info.number)
|
||||
return 0;
|
||||
|
||||
pNextEntry = pCluster->GetNext(pNextEntry);
|
||||
}
|
||||
|
||||
pCluster = m_pSegment->GetNext(pCluster);
|
||||
|
||||
if ((pCluster == NULL) || pCluster->EOS())
|
||||
{
|
||||
if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
|
||||
{
|
||||
pNextEntry = GetEOS();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//TODO: there is a potential O(n^2) problem here: we tell the
|
||||
//caller to (pre)load another cluster, which he does, but then he
|
||||
//calls GetNext again, which repeats the same search. This is
|
||||
//a pathological case, since the only way it can happen is if
|
||||
//there exists a long sequence of clusters none of which contain a
|
||||
// block from this track. One way around this problem is for the
|
||||
//caller to be smarter when he loads another cluster: don't call
|
||||
//us back until you have a cluster that contains a block from this
|
||||
//track. (Of course, that's not cheap either, since our caller
|
||||
//would have to scan the each cluster as it's loaded, so that
|
||||
//would just push back the problem.)
|
||||
|
||||
pNextEntry = NULL;
|
||||
return E_BUFFER_NOT_FULL;
|
||||
}
|
||||
|
||||
pNextEntry = pCluster->GetFirst();
|
||||
}
|
||||
|
||||
//NOTE: if we get here, it means that we didn't find a block with
|
||||
//a matching track number after lots of searching, so we give
|
||||
//up trying.
|
||||
|
||||
pNextEntry = GetEOS(); //so we can return a non-NULL value
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -2320,7 +2422,11 @@ void Tracks::ParseTrackEntry(
|
||||
assert(i.nameAsUTF8);
|
||||
else if (Match(pReader, pos, 0x06, i.codecId))
|
||||
;
|
||||
else if (Match(pReader, pos, 0x23A2, i.codecPrivate, i.codecPrivateSize))
|
||||
else if (Match(pReader,
|
||||
pos,
|
||||
0x23A2,
|
||||
i.codecPrivate,
|
||||
i.codecPrivateSize))
|
||||
;
|
||||
else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8))
|
||||
assert(i.codecNameAsUTF8);
|
||||
@ -2712,6 +2818,21 @@ long long Cluster::GetTime()
|
||||
}
|
||||
|
||||
|
||||
__int64 Cluster::GetFirstTime()
|
||||
{
|
||||
const BlockEntry* const pEntry = GetFirst();
|
||||
|
||||
if (pEntry == 0) //empty cluster
|
||||
return GetTime();
|
||||
|
||||
const Block* const pBlock = pEntry->GetBlock();
|
||||
assert(pBlock);
|
||||
|
||||
return pBlock->GetTime(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Cluster::ParseBlockGroup(long long start, long long size, size_t index)
|
||||
{
|
||||
assert(m_pEntries);
|
||||
@ -2732,7 +2853,8 @@ void Cluster::ParseSimpleBlock(long long start, long long size, size_t index)
|
||||
assert(m_entriesCount);
|
||||
assert(index < m_entriesCount);
|
||||
|
||||
SimpleBlock* const pSimpleBlock = new SimpleBlock(this, index, start, size);
|
||||
SimpleBlock* const pSimpleBlock =
|
||||
new (std::nothrow) SimpleBlock(this, index, start, size);
|
||||
assert(pSimpleBlock); //TODO
|
||||
|
||||
m_pEntries[index] = pSimpleBlock;
|
||||
|
@ -21,7 +21,7 @@ const int E_BUFFER_NOT_FULL = -3;
|
||||
class IMkvReader
|
||||
{
|
||||
public:
|
||||
virtual int Read(long long position, long length, unsigned char* buffer) = 0;
|
||||
virtual int Read(long long pos, long len, unsigned char* buf) = 0;
|
||||
virtual int Length(long long* total, long long* available) = 0;
|
||||
protected:
|
||||
virtual ~IMkvReader();
|
||||
@ -77,7 +77,7 @@ public:
|
||||
unsigned long GetTrackNumber() const;
|
||||
|
||||
long long GetTimeCode(Cluster*) const; //absolute, but not scaled
|
||||
long long GetTime(Cluster*) const; //absolute, and scaled (nanosecond units)
|
||||
long long GetTime(Cluster*) const; //absolute, and scaled (ns units)
|
||||
bool IsKey() const;
|
||||
void SetKey(bool);
|
||||
|
||||
@ -352,8 +352,9 @@ public:
|
||||
|
||||
bool EOS() const;
|
||||
|
||||
long long GetTimeCode(); //absolute, but not scaled
|
||||
long long GetTime(); //absolute, and scaled (nanosecond units)
|
||||
long long GetTimeCode(); //absolute, but not scaled
|
||||
long long GetTime(); //absolute, and scaled (nanosecond units)
|
||||
long long GetFirstTime(); //time (ns) of first (earliest) block
|
||||
|
||||
const BlockEntry* GetFirst();
|
||||
const BlockEntry* GetLast();
|
||||
|
Loading…
x
Reference in New Issue
Block a user