|
|
|
|
@@ -21,7 +21,7 @@ void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)
|
|
|
|
|
major = 1;
|
|
|
|
|
minor = 0;
|
|
|
|
|
build = 0;
|
|
|
|
|
revision = 12;
|
|
|
|
|
revision = 14;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
|
|
|
|
@@ -228,13 +228,16 @@ float mkvparser::Unserialize4Float(
|
|
|
|
|
assert(pReader);
|
|
|
|
|
assert(pos >= 0);
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
long long total, available;
|
|
|
|
|
|
|
|
|
|
long hr = pReader->Length(&total, &available);
|
|
|
|
|
assert(hr >= 0);
|
|
|
|
|
assert(available <= total);
|
|
|
|
|
assert((pos + 4) <= available);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
float result;
|
|
|
|
|
|
|
|
|
|
unsigned char* const p = (unsigned char*)&result;
|
|
|
|
|
@@ -250,6 +253,32 @@ float mkvparser::Unserialize4Float(
|
|
|
|
|
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
float result;
|
|
|
|
|
unsigned long buf;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
buf = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0;;)
|
|
|
|
|
{
|
|
|
|
|
unsigned char b;
|
|
|
|
|
|
|
|
|
|
const int status = pReader->Read(pos++, 1, &b);
|
|
|
|
|
|
|
|
|
|
if (status < 0) //error
|
|
|
|
|
return static_cast<float>(status);
|
|
|
|
|
|
|
|
|
|
buf |= b;
|
|
|
|
|
|
|
|
|
|
if (++i >= 4)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
buf <<= 8;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
@@ -262,6 +291,7 @@ double mkvparser::Unserialize8Double(
|
|
|
|
|
assert(pReader);
|
|
|
|
|
assert(pos >= 0);
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
double result;
|
|
|
|
|
|
|
|
|
|
unsigned char* const p = (unsigned char*)&result;
|
|
|
|
|
@@ -277,6 +307,32 @@ double mkvparser::Unserialize8Double(
|
|
|
|
|
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
double result;
|
|
|
|
|
long long buf;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
buf = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0;;)
|
|
|
|
|
{
|
|
|
|
|
unsigned char b;
|
|
|
|
|
|
|
|
|
|
const int status = pReader->Read(pos++, 1, &b);
|
|
|
|
|
|
|
|
|
|
if (status < 0) //error
|
|
|
|
|
return static_cast<double>(status);
|
|
|
|
|
|
|
|
|
|
buf |= b;
|
|
|
|
|
|
|
|
|
|
if (++i >= 8)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
buf <<= 8;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
@@ -288,17 +344,20 @@ signed char mkvparser::Unserialize1SInt(
|
|
|
|
|
assert(pReader);
|
|
|
|
|
assert(pos >= 0);
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
long long total, available;
|
|
|
|
|
|
|
|
|
|
long hr = pReader->Length(&total, &available);
|
|
|
|
|
assert(hr == 0);
|
|
|
|
|
assert(available <= total);
|
|
|
|
|
assert(pos < available);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
signed char result;
|
|
|
|
|
unsigned char& b = reinterpret_cast<unsigned char&>(result);
|
|
|
|
|
|
|
|
|
|
hr = pReader->Read(pos, 1, (unsigned char*)&result);
|
|
|
|
|
assert(hr == 0);
|
|
|
|
|
const int status = pReader->Read(pos, 1, &b);
|
|
|
|
|
assert(status == 0); //TODO: must be handled somehow
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
@@ -310,13 +369,16 @@ short mkvparser::Unserialize2SInt(
|
|
|
|
|
assert(pReader);
|
|
|
|
|
assert(pos >= 0);
|
|
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
long long total, available;
|
|
|
|
|
|
|
|
|
|
long hr = pReader->Length(&total, &available);
|
|
|
|
|
assert(hr >= 0);
|
|
|
|
|
assert(available <= total);
|
|
|
|
|
assert((pos + 2) <= available);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
short result;
|
|
|
|
|
|
|
|
|
|
unsigned char* const p = (unsigned char*)&result;
|
|
|
|
|
@@ -332,6 +394,24 @@ short mkvparser::Unserialize2SInt(
|
|
|
|
|
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
short result = 0;
|
|
|
|
|
|
|
|
|
|
for (int i = 0;;)
|
|
|
|
|
{
|
|
|
|
|
unsigned char b;
|
|
|
|
|
|
|
|
|
|
const int status = pReader->Read(pos++, 1, &b);
|
|
|
|
|
assert(status == 0); //TODO: must be handled somehow
|
|
|
|
|
|
|
|
|
|
result |= b;
|
|
|
|
|
|
|
|
|
|
if (++i >= 2)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
result <<= 8;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
@@ -1308,7 +1388,7 @@ long Segment::LoadCluster(
|
|
|
|
|
{
|
|
|
|
|
long long total, avail;
|
|
|
|
|
|
|
|
|
|
const int status = m_pReader->Length(&total, &avail);
|
|
|
|
|
long status = m_pReader->Length(&total, &avail);
|
|
|
|
|
|
|
|
|
|
if (status < 0) //error
|
|
|
|
|
return status;
|
|
|
|
|
@@ -1450,11 +1530,12 @@ long Segment::LoadCluster(
|
|
|
|
|
++m_clusterCount;
|
|
|
|
|
--m_clusterPreloadCount;
|
|
|
|
|
|
|
|
|
|
pCluster->Load(); //establish invariant
|
|
|
|
|
|
|
|
|
|
m_pos = pos + size; //consume payload
|
|
|
|
|
assert(m_pos <= stop);
|
|
|
|
|
|
|
|
|
|
status = pCluster->LoadBlockEntries(pos, len);
|
|
|
|
|
assert(status == 0); //TODO
|
|
|
|
|
|
|
|
|
|
return 0; //we have a new cluster
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -1476,7 +1557,8 @@ long Segment::LoadCluster(
|
|
|
|
|
assert(idx < m_clusterSize);
|
|
|
|
|
assert(m_clusters[idx] == pCluster);
|
|
|
|
|
|
|
|
|
|
pCluster->Load(); //establish invariant
|
|
|
|
|
status = pCluster->LoadBlockEntries(pos, len);
|
|
|
|
|
assert(status == 0); //TODO
|
|
|
|
|
|
|
|
|
|
return 0; //we have a new cluster
|
|
|
|
|
}
|
|
|
|
|
@@ -1824,6 +1906,8 @@ SeekHead::SeekHead(
|
|
|
|
|
|
|
|
|
|
//first count the seek head entries
|
|
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
while (pos < stop)
|
|
|
|
|
{
|
|
|
|
|
long len;
|
|
|
|
|
@@ -1842,7 +1926,7 @@ SeekHead::SeekHead(
|
|
|
|
|
assert((pos + size) <= stop);
|
|
|
|
|
|
|
|
|
|
if (id == 0x0DBB) //SeekEntry ID
|
|
|
|
|
++m_count;
|
|
|
|
|
++count;
|
|
|
|
|
|
|
|
|
|
pos += size; //consume payload
|
|
|
|
|
assert(pos <= stop);
|
|
|
|
|
@@ -1850,10 +1934,10 @@ SeekHead::SeekHead(
|
|
|
|
|
|
|
|
|
|
assert(pos == stop);
|
|
|
|
|
|
|
|
|
|
if (m_count <= 0)
|
|
|
|
|
if (count <= 0)
|
|
|
|
|
return; //nothing else for us to do
|
|
|
|
|
|
|
|
|
|
m_entries = new (std::nothrow) Entry[m_count];
|
|
|
|
|
m_entries = new (std::nothrow) Entry[count];
|
|
|
|
|
assert(m_entries); //TODO
|
|
|
|
|
|
|
|
|
|
//now parse the entries
|
|
|
|
|
@@ -1879,14 +1963,19 @@ SeekHead::SeekHead(
|
|
|
|
|
assert((pos + size) <= stop);
|
|
|
|
|
|
|
|
|
|
if (id == 0x0DBB) //SeekEntry ID
|
|
|
|
|
ParseEntry(pReader, pos, size, pEntry++);
|
|
|
|
|
ParseEntry(pReader, pos, size, pEntry);
|
|
|
|
|
|
|
|
|
|
pos += size; //consume payload
|
|
|
|
|
assert(pos <= stop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(pos == stop);
|
|
|
|
|
assert(ptrdiff_t(pEntry - m_entries) == m_count);
|
|
|
|
|
|
|
|
|
|
const ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
|
|
|
|
|
assert(count_ >= 0);
|
|
|
|
|
assert(count_ <= count);
|
|
|
|
|
|
|
|
|
|
m_count = static_cast<int>(count_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SeekHead::~SeekHead()
|
|
|
|
|
@@ -2153,7 +2242,7 @@ void SeekHead::ParseEntry(
|
|
|
|
|
IMkvReader* pReader,
|
|
|
|
|
long long start,
|
|
|
|
|
long long size_,
|
|
|
|
|
Entry* pEntry)
|
|
|
|
|
Entry*& pEntry)
|
|
|
|
|
{
|
|
|
|
|
long long pos = start;
|
|
|
|
|
const long long stop = start + size_;
|
|
|
|
|
@@ -2164,16 +2253,27 @@ void SeekHead::ParseEntry(
|
|
|
|
|
|
|
|
|
|
const long long seekIdId = ReadUInt(pReader, pos, len);
|
|
|
|
|
//seekIdId;
|
|
|
|
|
assert(seekIdId == 0x13AB); //SeekID ID
|
|
|
|
|
assert((pos + len) <= stop);
|
|
|
|
|
|
|
|
|
|
pos += len; //consume id
|
|
|
|
|
if (seekIdId != 0x13AB) //SeekID ID
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((pos + len) > stop)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pos += len; //consume SeekID id
|
|
|
|
|
|
|
|
|
|
const long long seekIdSize = ReadUInt(pReader, pos, len);
|
|
|
|
|
assert(seekIdSize >= 0);
|
|
|
|
|
assert((pos + len) <= stop);
|
|
|
|
|
|
|
|
|
|
pos += len; //consume size
|
|
|
|
|
if (seekIdSize <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((pos + len) > stop)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pos += len; //consume size of field
|
|
|
|
|
|
|
|
|
|
if ((pos + seekIdSize) > stop)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//TODO: it's not clear whether this is correct
|
|
|
|
|
//It seems as if the payload here is "binary" which
|
|
|
|
|
@@ -2181,31 +2281,49 @@ void SeekHead::ParseEntry(
|
|
|
|
|
//not parsed as an uint.
|
|
|
|
|
//
|
|
|
|
|
pEntry->id = ReadUInt(pReader, pos, len); //payload
|
|
|
|
|
assert(pEntry->id >= 0);
|
|
|
|
|
assert(len == seekIdSize);
|
|
|
|
|
assert((pos + len) <= stop);
|
|
|
|
|
|
|
|
|
|
pos += seekIdSize; //consume payload
|
|
|
|
|
if (pEntry->id <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (len != seekIdSize)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pos += seekIdSize; //consume SeekID payload
|
|
|
|
|
|
|
|
|
|
const long long seekPosId = ReadUInt(pReader, pos, len);
|
|
|
|
|
//seekPosId;
|
|
|
|
|
assert(seekPosId == 0x13AC); //SeekPos ID
|
|
|
|
|
assert((pos + len) <= stop);
|
|
|
|
|
|
|
|
|
|
if (seekPosId != 0x13AC) //SeekPos ID
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((pos + len) > stop)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pos += len; //consume id
|
|
|
|
|
|
|
|
|
|
const long long seekPosSize = ReadUInt(pReader, pos, len);
|
|
|
|
|
assert(seekPosSize >= 0);
|
|
|
|
|
assert((pos + len) <= stop);
|
|
|
|
|
|
|
|
|
|
if (seekPosSize <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if ((pos + len) > stop)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pos += len; //consume size
|
|
|
|
|
assert((pos + seekPosSize) <= stop);
|
|
|
|
|
|
|
|
|
|
if ((pos + seekPosSize) > stop)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
|
|
|
|
|
assert(pEntry->pos >= 0);
|
|
|
|
|
|
|
|
|
|
if (pEntry->pos < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
pos += seekPosSize; //consume payload
|
|
|
|
|
assert(pos == stop);
|
|
|
|
|
|
|
|
|
|
if (pos != stop)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
++pEntry; //success
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
@@ -3225,7 +3343,7 @@ long Segment::ParseNext(
|
|
|
|
|
|
|
|
|
|
long long total, avail;
|
|
|
|
|
|
|
|
|
|
const int status = m_pReader->Length(&total, &avail);
|
|
|
|
|
long status = m_pReader->Length(&total, &avail);
|
|
|
|
|
|
|
|
|
|
if (status < 0) //error
|
|
|
|
|
return status;
|
|
|
|
|
@@ -3437,10 +3555,8 @@ long Segment::ParseNext(
|
|
|
|
|
|
|
|
|
|
len = static_cast<long>(size);
|
|
|
|
|
|
|
|
|
|
#if 1 //TODO: get rid of this
|
|
|
|
|
if (element_stop > avail)
|
|
|
|
|
return E_BUFFER_NOT_FULL;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (Cluster::HasBlockEntries(this, idoff)) //relative
|
|
|
|
|
{
|
|
|
|
|
@@ -3491,6 +3607,9 @@ long Segment::ParseNext(
|
|
|
|
|
j = k;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
status = pNext->LoadBlockEntries(pos, len);
|
|
|
|
|
assert(status == 0);
|
|
|
|
|
|
|
|
|
|
pResult = pNext;
|
|
|
|
|
return 0; //success
|
|
|
|
|
}
|
|
|
|
|
@@ -3512,7 +3631,8 @@ long Segment::ParseNext(
|
|
|
|
|
assert(idx_next < m_clusterSize);
|
|
|
|
|
assert(m_clusters[idx_next] == pNext);
|
|
|
|
|
|
|
|
|
|
pNext->Load(); //because we need this now
|
|
|
|
|
status = pNext->LoadBlockEntries(pos, len);
|
|
|
|
|
assert(status == 0); //TODO
|
|
|
|
|
|
|
|
|
|
pResult = pNext;
|
|
|
|
|
return 0; //success
|
|
|
|
|
@@ -4930,23 +5050,24 @@ void Cluster::Load() const
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long Cluster::Load(long long& pos, long& len) const
|
|
|
|
|
long Cluster::LoadBlockEntries(long long& pos, long& len) const
|
|
|
|
|
{
|
|
|
|
|
assert(m_pSegment);
|
|
|
|
|
assert(m_pos);
|
|
|
|
|
assert(m_size);
|
|
|
|
|
|
|
|
|
|
if (m_pos > 0) //loaded
|
|
|
|
|
{
|
|
|
|
|
assert(m_size > 0);
|
|
|
|
|
assert(m_timecode >= 0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(m_pos < 0); //not loaded yet
|
|
|
|
|
assert(m_size < 0);
|
|
|
|
|
assert(m_timecode < 0);
|
|
|
|
|
//if (m_pos > 0) //loaded
|
|
|
|
|
//{
|
|
|
|
|
// assert(m_size > 0);
|
|
|
|
|
// assert(m_timecode >= 0);
|
|
|
|
|
// assert(m_entries_count >= 0);
|
|
|
|
|
//
|
|
|
|
|
// return 0;
|
|
|
|
|
//}
|
|
|
|
|
//
|
|
|
|
|
//assert(m_pos < 0); //not loaded yet
|
|
|
|
|
//assert(m_size < 0);
|
|
|
|
|
//assert(m_timecode < 0);
|
|
|
|
|
|
|
|
|
|
IMkvReader* const pReader = m_pSegment->m_pReader;
|
|
|
|
|
|
|
|
|
|
@@ -4962,6 +5083,28 @@ long Cluster::Load(long long& pos, long& len) const
|
|
|
|
|
|
|
|
|
|
const long long segment_stop = m_pSegment->m_start + m_pSegment->m_size;
|
|
|
|
|
|
|
|
|
|
if (m_pos > 0) //at least partially loaded
|
|
|
|
|
{
|
|
|
|
|
assert(m_size > 0);
|
|
|
|
|
|
|
|
|
|
if (m_entries_count >= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
pos = m_pSegment->m_start + m_pos; //absolute pos of payload
|
|
|
|
|
|
|
|
|
|
const long long cluster_stop = pos + m_size;
|
|
|
|
|
|
|
|
|
|
len = static_cast<long>(m_size);
|
|
|
|
|
|
|
|
|
|
if (cluster_stop > avail)
|
|
|
|
|
return E_BUFFER_NOT_FULL;
|
|
|
|
|
|
|
|
|
|
LoadBlockEntries(); //TODO
|
|
|
|
|
assert(m_entries_count >= 0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//m_pos *= -1; //relative to segment
|
|
|
|
|
pos = m_pSegment->m_start - m_pos; //absolute
|
|
|
|
|
|
|
|
|
|
@@ -5115,6 +5258,8 @@ long Cluster::Load(long long& pos, long& len) const
|
|
|
|
|
m_size = size_; // m_size > 0 means we're partially loaded
|
|
|
|
|
m_timecode = timecode; // m_timecode >= 0 means we're partially loaded
|
|
|
|
|
|
|
|
|
|
LoadBlockEntries(); //TODO
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -5528,6 +5673,12 @@ const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long Cluster::GetEntryCount() const
|
|
|
|
|
{
|
|
|
|
|
return m_entries_count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const BlockEntry* Cluster::GetEntry(
|
|
|
|
|
const Track* pTrack,
|
|
|
|
|
long long time_ns) const
|
|
|
|
|
|