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
|
#endif
|
||||||
long long index = m_pos;
|
long long index = m_pos;
|
||||||
|
|
||||||
|
//TODO: we don't want to count clusters here.
|
||||||
|
//Just do a lazy init.
|
||||||
|
|
||||||
m_clusterCount = 0;
|
m_clusterCount = 0;
|
||||||
|
|
||||||
long long* fileposition_of_clusters = NULL;
|
long long* fileposition_of_clusters = NULL;
|
||||||
long long size_of_cluster_pos = 0;
|
size_t size_of_cluster_pos = 0;
|
||||||
|
|
||||||
while (index < stop)
|
while (index < stop)
|
||||||
{
|
{
|
||||||
@ -1211,14 +1214,19 @@ long Segment::Load()
|
|||||||
if (id == 0x0F43B675) // Cluster ID
|
if (id == 0x0F43B675) // Cluster ID
|
||||||
{
|
{
|
||||||
assert(fileposition_of_clusters);
|
assert(fileposition_of_clusters);
|
||||||
|
|
||||||
if (m_clusterCount >= size_of_cluster_pos)
|
if (m_clusterCount >= size_of_cluster_pos)
|
||||||
{
|
{
|
||||||
|
assert(size_of_cluster_pos > 0);
|
||||||
size_of_cluster_pos *= 2;
|
size_of_cluster_pos *= 2;
|
||||||
|
|
||||||
long long* const temp = new long long[size_of_cluster_pos];
|
long long* const temp = new long long[size_of_cluster_pos];
|
||||||
memset(temp, 0, sizeof(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);
|
const size_t size = sizeof(long long) * m_clusterCount;
|
||||||
delete [] fileposition_of_clusters;
|
memcpy(temp, fileposition_of_clusters, size);
|
||||||
|
|
||||||
|
delete[] fileposition_of_clusters;
|
||||||
fileposition_of_clusters = temp;
|
fileposition_of_clusters = temp;
|
||||||
}
|
}
|
||||||
fileposition_of_clusters[m_clusterCount] = idpos;
|
fileposition_of_clusters[m_clusterCount] = idpos;
|
||||||
@ -1232,7 +1240,11 @@ long Segment::Load()
|
|||||||
assert(m_clusterCount == 0);
|
assert(m_clusterCount == 0);
|
||||||
|
|
||||||
const long long duration = m_pInfo->GetDuration();
|
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];
|
fileposition_of_clusters = new long long[size_of_cluster_pos];
|
||||||
memset(fileposition_of_clusters, 0, 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];
|
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]);
|
m_clusters[i] = Cluster::Parse(this, i, fileposition_of_clusters[i]);
|
||||||
|
|
||||||
delete [] fileposition_of_clusters;
|
delete[] fileposition_of_clusters;
|
||||||
|
|
||||||
while (m_pos < stop)
|
while (m_pos < stop)
|
||||||
{
|
{
|
||||||
@ -1813,8 +1825,7 @@ const BlockEntry* Track::GetEOS() const
|
|||||||
|
|
||||||
long long Track::GetType() const
|
long long Track::GetType() const
|
||||||
{
|
{
|
||||||
const unsigned long result = static_cast<unsigned long>(m_info.type);
|
return m_info.type;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long Track::GetNumber() const
|
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
|
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
|
//If Segment::GetFirst returns NULL, then this must be a network
|
||||||
//download, and we haven't loaded any clusters yet. In this case,
|
//download, and we haven't loaded any clusters yet. In this case,
|
||||||
//returning NULL from Track::GetFirst means the same thing.
|
//returning NULL from Track::GetFirst means the same thing.
|
||||||
|
|
||||||
|
#if 0
|
||||||
if ((pCluster == NULL) || pCluster->EOS())
|
if ((pCluster == NULL) || pCluster->EOS())
|
||||||
{
|
{
|
||||||
pBlockEntry = NULL;
|
pBlockEntry = NULL;
|
||||||
@ -1874,6 +1886,37 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
|||||||
|
|
||||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
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
|
//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
|
//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);
|
||||||
assert(!pCurrEntry->EOS()); //?
|
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();
|
const Cluster* const pCurrCluster = pCurrEntry->GetCluster();
|
||||||
assert(pCurrCluster);
|
assert(pCurrCluster);
|
||||||
assert(!pCurrCluster->EOS());
|
assert(!pCurrCluster->EOS());
|
||||||
@ -1988,6 +2034,62 @@ long Track::GetNext(const BlockEntry* pCurrEntry, const BlockEntry*& pNextEntry)
|
|||||||
//return E_FAIL;
|
//return E_FAIL;
|
||||||
pNextEntry = GetEOS();
|
pNextEntry = GetEOS();
|
||||||
return 1L;
|
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);
|
assert(i.nameAsUTF8);
|
||||||
else if (Match(pReader, pos, 0x06, i.codecId))
|
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))
|
else if (Match(pReader, pos, 0x058688, i.codecNameAsUTF8))
|
||||||
assert(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)
|
void Cluster::ParseBlockGroup(long long start, long long size, size_t index)
|
||||||
{
|
{
|
||||||
assert(m_pEntries);
|
assert(m_pEntries);
|
||||||
@ -2732,7 +2853,8 @@ void Cluster::ParseSimpleBlock(long long start, long long size, size_t index)
|
|||||||
assert(m_entriesCount);
|
assert(m_entriesCount);
|
||||||
assert(index < 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
|
assert(pSimpleBlock); //TODO
|
||||||
|
|
||||||
m_pEntries[index] = pSimpleBlock;
|
m_pEntries[index] = pSimpleBlock;
|
||||||
|
@ -21,7 +21,7 @@ const int E_BUFFER_NOT_FULL = -3;
|
|||||||
class IMkvReader
|
class IMkvReader
|
||||||
{
|
{
|
||||||
public:
|
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;
|
virtual int Length(long long* total, long long* available) = 0;
|
||||||
protected:
|
protected:
|
||||||
virtual ~IMkvReader();
|
virtual ~IMkvReader();
|
||||||
@ -77,7 +77,7 @@ public:
|
|||||||
unsigned long GetTrackNumber() const;
|
unsigned long GetTrackNumber() const;
|
||||||
|
|
||||||
long long GetTimeCode(Cluster*) const; //absolute, but not scaled
|
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;
|
bool IsKey() const;
|
||||||
void SetKey(bool);
|
void SetKey(bool);
|
||||||
|
|
||||||
@ -352,8 +352,9 @@ public:
|
|||||||
|
|
||||||
bool EOS() const;
|
bool EOS() const;
|
||||||
|
|
||||||
long long GetTimeCode(); //absolute, but not scaled
|
long long GetTimeCode(); //absolute, but not scaled
|
||||||
long long GetTime(); //absolute, and scaled (nanosecond units)
|
long long GetTime(); //absolute, and scaled (nanosecond units)
|
||||||
|
long long GetFirstTime(); //time (ns) of first (earliest) block
|
||||||
|
|
||||||
const BlockEntry* GetFirst();
|
const BlockEntry* GetFirst();
|
||||||
const BlockEntry* GetLast();
|
const BlockEntry* GetLast();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user