Compare commits
9 Commits
libwebm-1.
...
libwebm-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6623441ee8 | ||
|
|
3ba8df9a64 | ||
|
|
bebe4accb8 | ||
|
|
93263f0b4a | ||
|
|
e1e757f919 | ||
|
|
6c45ab2d4c | ||
|
|
cb7b24880f | ||
|
|
157775ac74 | ||
|
|
fd1d8006f0 |
455
mkvparser.cpp
455
mkvparser.cpp
@@ -21,7 +21,7 @@ void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)
|
|||||||
major = 1;
|
major = 1;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
build = 0;
|
build = 0;
|
||||||
revision = 8;
|
revision = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
||||||
@@ -29,75 +29,56 @@ long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
|||||||
assert(pReader);
|
assert(pReader);
|
||||||
assert(pos >= 0);
|
assert(pos >= 0);
|
||||||
|
|
||||||
long long total, available;
|
int status;
|
||||||
|
|
||||||
long hr = pReader->Length(&total, &available);
|
#ifdef _DEBUG
|
||||||
assert(hr >= 0);
|
long long total, available;
|
||||||
|
status = pReader->Length(&total, &available);
|
||||||
|
assert(status >= 0);
|
||||||
|
assert(total > 0);
|
||||||
|
assert(available <= total);
|
||||||
assert(pos < available);
|
assert(pos < available);
|
||||||
assert((available - pos) >= 1); //assume here max u-int len is 8
|
assert((available - pos) >= 1); //assume here max u-int len is 8
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
|
|
||||||
hr = pReader->Read(pos, 1, &b);
|
status = pReader->Read(pos, 1, &b);
|
||||||
if (hr < 0)
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
assert(hr == 0L);
|
if (status < 0) //error
|
||||||
|
return status;
|
||||||
|
|
||||||
if (b & 0x80) //1000 0000
|
if (status > 0) //interpreted as "underflow"
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
|
if (b == 0) //we can't handle u-int values larger than 8 bytes
|
||||||
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
|
unsigned char m = 0x80;
|
||||||
|
len = 1;
|
||||||
|
|
||||||
|
while (!(b & m))
|
||||||
{
|
{
|
||||||
len = 1;
|
m >>= 1;
|
||||||
b &= 0x7F; //0111 1111
|
++len;
|
||||||
}
|
|
||||||
else if (b & 0x40) //0100 0000
|
|
||||||
{
|
|
||||||
len = 2;
|
|
||||||
b &= 0x3F; //0011 1111
|
|
||||||
}
|
|
||||||
else if (b & 0x20) //0010 0000
|
|
||||||
{
|
|
||||||
len = 3;
|
|
||||||
b &= 0x1F; //0001 1111
|
|
||||||
}
|
|
||||||
else if (b & 0x10) //0001 0000
|
|
||||||
{
|
|
||||||
len = 4;
|
|
||||||
b &= 0x0F; //0000 1111
|
|
||||||
}
|
|
||||||
else if (b & 0x08) //0000 1000
|
|
||||||
{
|
|
||||||
len = 5;
|
|
||||||
b &= 0x07; //0000 0111
|
|
||||||
}
|
|
||||||
else if (b & 0x04) //0000 0100
|
|
||||||
{
|
|
||||||
len = 6;
|
|
||||||
b &= 0x03; //0000 0011
|
|
||||||
}
|
|
||||||
else if (b & 0x02) //0000 0010
|
|
||||||
{
|
|
||||||
len = 7;
|
|
||||||
b &= 0x01; //0000 0001
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(b & 0x01); //0000 0001
|
|
||||||
len = 8;
|
|
||||||
b = 0; //0000 0000
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
assert((available - pos) >= len);
|
assert((available - pos) >= len);
|
||||||
|
#endif
|
||||||
|
|
||||||
long long result = b;
|
long long result = b & (~m);
|
||||||
++pos;
|
++pos;
|
||||||
for (long i = 1; i < len; ++i)
|
|
||||||
|
for (int i = 1; i < len; ++i)
|
||||||
{
|
{
|
||||||
hr = pReader->Read(pos, 1, &b);
|
status = pReader->Read(pos, 1, &b);
|
||||||
|
|
||||||
if (hr < 0)
|
if (status < 0)
|
||||||
return hr;
|
return status;
|
||||||
|
|
||||||
assert(hr == 0L);
|
if (status > 0)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
result <<= 8;
|
result <<= 8;
|
||||||
result |= b;
|
result |= b;
|
||||||
@@ -118,8 +99,9 @@ long long mkvparser::GetUIntLength(
|
|||||||
|
|
||||||
long long total, available;
|
long long total, available;
|
||||||
|
|
||||||
long hr = pReader->Length(&total, &available);
|
int status = pReader->Length(&total, &available);
|
||||||
assert(hr >= 0);
|
assert(status >= 0);
|
||||||
|
assert(total >= 0);
|
||||||
assert(available <= total);
|
assert(available <= total);
|
||||||
|
|
||||||
if (pos >= available)
|
if (pos >= available)
|
||||||
@@ -127,12 +109,12 @@ long long mkvparser::GetUIntLength(
|
|||||||
|
|
||||||
unsigned char b;
|
unsigned char b;
|
||||||
|
|
||||||
hr = pReader->Read(pos, 1, &b);
|
status = pReader->Read(pos, 1, &b);
|
||||||
|
|
||||||
if (hr < 0)
|
if (status < 0)
|
||||||
return hr;
|
return status;
|
||||||
|
|
||||||
assert(hr == 0L);
|
assert(status == 0);
|
||||||
|
|
||||||
if (b == 0) //we can't handle u-int values larger than 8 bytes
|
if (b == 0) //we can't handle u-int values larger than 8 bytes
|
||||||
return E_FILE_FORMAT_INVALID;
|
return E_FILE_FORMAT_INVALID;
|
||||||
@@ -892,8 +874,10 @@ long long Segment::CreateInstance(
|
|||||||
else if ((pos + size) > total)
|
else if ((pos + size) > total)
|
||||||
return E_FILE_FORMAT_INVALID;
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
pSegment = new Segment(pReader, pos, size);
|
pSegment = new (std::nothrow) Segment(pReader, pos, size);
|
||||||
assert(pSegment); //TODO
|
|
||||||
|
if (pSegment == 0)
|
||||||
|
return -1; //generic error
|
||||||
|
|
||||||
return 0; //success
|
return 0; //success
|
||||||
}
|
}
|
||||||
@@ -904,12 +888,7 @@ long long Segment::CreateInstance(
|
|||||||
pos += size; //consume payload
|
pos += size; //consume payload
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(pos == total);
|
return E_FILE_FORMAT_INVALID; //there is no segment
|
||||||
|
|
||||||
pSegment = new Segment(pReader, pos, 0);
|
|
||||||
assert(pSegment); //TODO
|
|
||||||
|
|
||||||
return 0; //success (sort of)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -920,17 +899,16 @@ long long Segment::ParseHeaders()
|
|||||||
//inner (level 1) elements.
|
//inner (level 1) elements.
|
||||||
long long total, available;
|
long long total, available;
|
||||||
|
|
||||||
long hr = m_pReader->Length(&total, &available);
|
const int status = m_pReader->Length(&total, &available);
|
||||||
assert(hr >= 0);
|
assert(status == 0);
|
||||||
|
assert(total >= 0);
|
||||||
assert(available <= total);
|
assert(available <= total);
|
||||||
|
|
||||||
const long long stop = m_start + m_size;
|
const long long stop = m_start + m_size;
|
||||||
assert(stop <= total);
|
assert(stop <= total);
|
||||||
assert(m_pos <= stop);
|
assert(m_pos <= stop);
|
||||||
|
|
||||||
bool bQuit = false;
|
while (m_pos < stop)
|
||||||
|
|
||||||
while ((m_pos < stop) && !bQuit)
|
|
||||||
{
|
{
|
||||||
long long pos = m_pos;
|
long long pos = m_pos;
|
||||||
|
|
||||||
@@ -952,6 +930,9 @@ long long Segment::ParseHeaders()
|
|||||||
if (id < 0) //error
|
if (id < 0) //error
|
||||||
return id;
|
return id;
|
||||||
|
|
||||||
|
if (id == 0x0F43B675) //Cluster ID
|
||||||
|
break;
|
||||||
|
|
||||||
pos += len; //consume ID
|
pos += len; //consume ID
|
||||||
|
|
||||||
//Read Size
|
//Read Size
|
||||||
@@ -1007,15 +988,11 @@ long long Segment::ParseHeaders()
|
|||||||
}
|
}
|
||||||
else if (id == 0x014D9B74) //SeekHead ID
|
else if (id == 0x014D9B74) //SeekHead ID
|
||||||
{
|
{
|
||||||
ParseSeekHead(pos, size);
|
if (available >= total)
|
||||||
}
|
ParseSeekHead(pos, size);
|
||||||
else if (id == 0x0F43B675) //Cluster ID
|
|
||||||
{
|
|
||||||
bQuit = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bQuit)
|
m_pos = pos + size; //consume payload
|
||||||
m_pos = pos + size; //consume payload
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(m_pos <= stop);
|
assert(m_pos <= stop);
|
||||||
@@ -1030,6 +1007,93 @@ long long Segment::ParseHeaders()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
long Segment::FindNextCluster(long long& pos, size& len) const
|
||||||
|
{
|
||||||
|
//Outermost (level 0) segment object has been constructed,
|
||||||
|
//and pos designates start of payload. We need to find the
|
||||||
|
//inner (level 1) elements.
|
||||||
|
long long total, available;
|
||||||
|
|
||||||
|
const int status = m_pReader->Length(&total, &available);
|
||||||
|
assert(status == 0);
|
||||||
|
assert(total >= 0);
|
||||||
|
assert(available <= total);
|
||||||
|
|
||||||
|
const long long stop = m_start + m_size;
|
||||||
|
assert(stop <= total);
|
||||||
|
assert(m_pos <= stop);
|
||||||
|
|
||||||
|
pos = m_pos;
|
||||||
|
|
||||||
|
while (pos < stop)
|
||||||
|
{
|
||||||
|
long long result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
|
||||||
|
if (result < 0)
|
||||||
|
return static_cast<long>(result);
|
||||||
|
|
||||||
|
if (result > 0)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
|
if ((pos + len) > stop)
|
||||||
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
|
if ((pos + len) > available)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
|
const long long idpos = pos;
|
||||||
|
const long long id = ReadUInt(m_pReader, idpos, len);
|
||||||
|
|
||||||
|
if (id < 0) //error
|
||||||
|
return static_cast<long>(id);
|
||||||
|
|
||||||
|
pos += len; //consume ID
|
||||||
|
|
||||||
|
//Read Size
|
||||||
|
result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
|
||||||
|
if (result < 0) //error
|
||||||
|
return static_cast<long>(result);
|
||||||
|
|
||||||
|
if (result > 0)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
|
if ((pos + len) > stop)
|
||||||
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
|
if ((pos + len) > available)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
|
const long long size = ReadUInt(m_pReader, pos, len);
|
||||||
|
|
||||||
|
if (size < 0) //error
|
||||||
|
return static_cast<long>(size);
|
||||||
|
|
||||||
|
pos += len; //consume length of size of element
|
||||||
|
|
||||||
|
//Pos now points to start of payload
|
||||||
|
|
||||||
|
if ((pos + size) > stop)
|
||||||
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
|
if ((pos + size) > available)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
|
if (id == 0x0F43B675) //Cluster ID
|
||||||
|
{
|
||||||
|
len = static_cast<long>(size);
|
||||||
|
return 0; //success
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += size; //consume payload
|
||||||
|
}
|
||||||
|
|
||||||
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
long Segment::ParseCluster(long long& off, long long& new_pos) const
|
long Segment::ParseCluster(long long& off, long long& new_pos) const
|
||||||
{
|
{
|
||||||
off = -1;
|
off = -1;
|
||||||
@@ -1179,21 +1243,26 @@ bool Segment::AddCluster(long long off, long long pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long Segment::LoadCluster()
|
long Segment::LoadCluster(
|
||||||
|
long long& pos,
|
||||||
|
long& len)
|
||||||
{
|
{
|
||||||
const long long stop = m_start + m_size;
|
const long long stop = m_start + m_size;
|
||||||
|
|
||||||
while (m_pos < stop)
|
while (m_pos < stop)
|
||||||
{
|
{
|
||||||
long long pos = m_pos;
|
pos = m_pos;
|
||||||
|
|
||||||
long len;
|
//Read ID
|
||||||
|
|
||||||
long long result = GetUIntLength(m_pReader, pos, len);
|
long long result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
|
||||||
if (result < 0) //error
|
if (result < 0) //error
|
||||||
return static_cast<long>(result);
|
return static_cast<long>(result);
|
||||||
|
|
||||||
|
if (result > 0)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
if ((pos + len) > stop)
|
if ((pos + len) > stop)
|
||||||
return E_FILE_FORMAT_INVALID;
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
@@ -1206,11 +1275,15 @@ long Segment::LoadCluster()
|
|||||||
pos += len; //consume ID
|
pos += len; //consume ID
|
||||||
|
|
||||||
//Read Size
|
//Read Size
|
||||||
|
|
||||||
result = GetUIntLength(m_pReader, pos, len);
|
result = GetUIntLength(m_pReader, pos, len);
|
||||||
|
|
||||||
if (result < 0) //error
|
if (result < 0) //error
|
||||||
return static_cast<long>(result);
|
return static_cast<long>(result);
|
||||||
|
|
||||||
|
if (result > 0)
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
|
||||||
if ((pos + len) > stop)
|
if ((pos + len) > stop)
|
||||||
return E_FILE_FORMAT_INVALID;
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
@@ -1232,6 +1305,19 @@ long Segment::LoadCluster()
|
|||||||
if ((pos + size) > stop)
|
if ((pos + size) > stop)
|
||||||
return E_FILE_FORMAT_INVALID;
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
|
long long total, avail;
|
||||||
|
|
||||||
|
const int status = m_pReader->Length(&total, &avail);
|
||||||
|
assert(status == 0);
|
||||||
|
assert(total >= 0);
|
||||||
|
assert(avail <= total);
|
||||||
|
|
||||||
|
if ((pos + size) > avail)
|
||||||
|
{
|
||||||
|
len = static_cast<long>(size);
|
||||||
|
return E_BUFFER_NOT_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (id == 0x0C53BB6B) //Cues ID
|
if (id == 0x0C53BB6B) //Cues ID
|
||||||
{
|
{
|
||||||
if (m_pCues == NULL)
|
if (m_pCues == NULL)
|
||||||
@@ -2666,6 +2752,7 @@ const Cluster* Segment::FindCluster(long long time_ns) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
const BlockEntry* Segment::Seek(
|
const BlockEntry* Segment::Seek(
|
||||||
long long time_ns,
|
long long time_ns,
|
||||||
const Track* pTrack) const
|
const Track* pTrack) const
|
||||||
@@ -2808,6 +2895,7 @@ const BlockEntry* Segment::Seek(
|
|||||||
|
|
||||||
return pTrack->GetEOS();
|
return pTrack->GetEOS();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
@@ -3107,7 +3195,9 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
|||||||
const Block* const pBlock = pBlockEntry->GetBlock();
|
const Block* const pBlock = pBlockEntry->GetBlock();
|
||||||
assert(pBlock);
|
assert(pBlock);
|
||||||
|
|
||||||
if (pBlock->GetTrackNumber() == m_info.number)
|
const long long tn = pBlock->GetTrackNumber();
|
||||||
|
|
||||||
|
if ((tn == m_info.number) && VetEntry(pBlockEntry))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
||||||
@@ -3322,6 +3412,99 @@ bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long VideoTrack::Seek(
|
||||||
|
long long time_ns,
|
||||||
|
const BlockEntry*& pResult) const
|
||||||
|
{
|
||||||
|
const long status = GetFirst(pResult);
|
||||||
|
|
||||||
|
if (status < 0) //buffer underflow, etc
|
||||||
|
return status;
|
||||||
|
|
||||||
|
assert(pResult);
|
||||||
|
|
||||||
|
if (pResult->EOS())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const Cluster* pCluster = pResult->GetCluster();
|
||||||
|
assert(pCluster);
|
||||||
|
|
||||||
|
if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Cluster** const clusters = m_pSegment->m_clusters;
|
||||||
|
assert(clusters);
|
||||||
|
|
||||||
|
const long count = m_pSegment->GetCount();
|
||||||
|
assert(count > 0);
|
||||||
|
|
||||||
|
Cluster** const i = clusters + pCluster->m_index;
|
||||||
|
assert(i);
|
||||||
|
assert(*i == pCluster);
|
||||||
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
|
||||||
|
Cluster** const j = clusters + count;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
pCluster = *mid;
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->m_index == long(mid - m_pSegment->m_clusters));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
pResult = pCluster->GetEntry(this, time_ns);
|
||||||
|
|
||||||
|
if ((pResult != 0) && !pResult->EOS()) //found a keyframe
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while (lo != i)
|
||||||
|
{
|
||||||
|
pCluster = *--lo;
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
|
||||||
|
pResult = pCluster->GetMaxKey(this);
|
||||||
|
|
||||||
|
if ((pResult != 0) && !pResult->EOS())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//weird: we're on the first cluster, but no keyframe found
|
||||||
|
//should never happen but we must return something anyway
|
||||||
|
|
||||||
|
pResult = GetEOS();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
long long VideoTrack::GetWidth() const
|
long long VideoTrack::GetWidth() const
|
||||||
{
|
{
|
||||||
return m_width;
|
return m_width;
|
||||||
@@ -3413,6 +3596,89 @@ bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long AudioTrack::Seek(
|
||||||
|
long long time_ns,
|
||||||
|
const BlockEntry*& pResult) const
|
||||||
|
{
|
||||||
|
const long status = GetFirst(pResult);
|
||||||
|
|
||||||
|
if (status < 0) //buffer underflow, etc
|
||||||
|
return status;
|
||||||
|
|
||||||
|
assert(pResult);
|
||||||
|
|
||||||
|
if (pResult->EOS())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const Cluster* pCluster = pResult->GetCluster();
|
||||||
|
assert(pCluster);
|
||||||
|
|
||||||
|
if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Cluster** const clusters = m_pSegment->m_clusters;
|
||||||
|
assert(clusters);
|
||||||
|
|
||||||
|
const long count = m_pSegment->GetCount();
|
||||||
|
assert(count > 0);
|
||||||
|
|
||||||
|
Cluster** const i = clusters + pCluster->m_index;
|
||||||
|
assert(i);
|
||||||
|
assert(*i == pCluster);
|
||||||
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
|
||||||
|
Cluster** const j = clusters + count;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
pCluster = *mid;
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->m_index == long(mid - m_pSegment->m_clusters));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
while (lo > i)
|
||||||
|
{
|
||||||
|
pCluster = *--lo;
|
||||||
|
assert(pCluster);
|
||||||
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
|
||||||
|
pResult = pCluster->GetEntry(this);
|
||||||
|
|
||||||
|
if ((pResult != 0) && !pResult->EOS())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//landed on empty cluster (no entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
pResult = GetEOS(); //weird
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
double AudioTrack::GetSamplingRate() const
|
double AudioTrack::GetSamplingRate() const
|
||||||
{
|
{
|
||||||
return m_rate;
|
return m_rate;
|
||||||
@@ -4587,9 +4853,11 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
|||||||
long status = pReader->Read(pos, 1, &m_flags);
|
long status = pReader->Read(pos, 1, &m_flags);
|
||||||
assert(status == 0);
|
assert(status == 0);
|
||||||
|
|
||||||
|
#if 0
|
||||||
const int invisible = int(m_flags & 0x08) >> 3;
|
const int invisible = int(m_flags & 0x08) >> 3;
|
||||||
invisible;
|
invisible;
|
||||||
assert(!invisible); //TODO
|
assert(!invisible); //TODO
|
||||||
|
#endif
|
||||||
|
|
||||||
const int lacing = int(m_flags & 0x06) >> 1;
|
const int lacing = int(m_flags & 0x06) >> 1;
|
||||||
|
|
||||||
@@ -4869,28 +5137,12 @@ void Block::SetKey(bool bKey)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
bool Block::IsInvisible() const
|
||||||
long long Block::GetOffset() const
|
|
||||||
{
|
{
|
||||||
return m_frameOff;
|
return bool(int(m_flags & 0x08) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long Block::GetSize() const
|
|
||||||
{
|
|
||||||
return m_frameSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
long Block::Read(IMkvReader* pReader, unsigned char* buf) const
|
|
||||||
{
|
|
||||||
assert(pReader);
|
|
||||||
assert(buf);
|
|
||||||
|
|
||||||
const long hr = pReader->Read(m_frameOff, m_frameSize, buf);
|
|
||||||
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
int Block::GetFrameCount() const
|
int Block::GetFrameCount() const
|
||||||
{
|
{
|
||||||
return m_frame_count;
|
return m_frame_count;
|
||||||
@@ -4918,7 +5170,6 @@ long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const
|
|||||||
const long status = pReader->Read(pos, len, buf);
|
const long status = pReader->Read(pos, len, buf);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
} //end namespace mkvparser
|
} //end namespace mkvparser
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ public:
|
|||||||
long long GetTime(const Cluster*) const; //absolute, and scaled (ns)
|
long long GetTime(const Cluster*) const; //absolute, and scaled (ns)
|
||||||
bool IsKey() const;
|
bool IsKey() const;
|
||||||
void SetKey(bool);
|
void SetKey(bool);
|
||||||
|
bool IsInvisible() const;
|
||||||
|
|
||||||
int GetFrameCount() const; //to index frames: [0, count)
|
int GetFrameCount() const; //to index frames: [0, count)
|
||||||
|
|
||||||
@@ -91,26 +92,15 @@ public:
|
|||||||
long Read(IMkvReader*, unsigned char*) const;
|
long Read(IMkvReader*, unsigned char*) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
|
||||||
long long GetOffset() const;
|
|
||||||
long GetSize() const;
|
|
||||||
long Read(IMkvReader*, unsigned char*) const;
|
|
||||||
#else
|
|
||||||
const Frame& GetFrame(int frame_index) const;
|
const Frame& GetFrame(int frame_index) const;
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
long long m_track; //Track::Number()
|
long long m_track; //Track::Number()
|
||||||
short m_timecode; //relative to cluster
|
short m_timecode; //relative to cluster
|
||||||
unsigned char m_flags;
|
unsigned char m_flags;
|
||||||
|
|
||||||
#if 0
|
|
||||||
long long m_frameOff;
|
|
||||||
long m_frameSize;
|
|
||||||
#else
|
|
||||||
Frame* m_frames;
|
Frame* m_frames;
|
||||||
int m_frame_count;
|
int m_frame_count;
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -244,6 +234,7 @@ public:
|
|||||||
long GetFirst(const BlockEntry*&) const;
|
long GetFirst(const BlockEntry*&) const;
|
||||||
long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
|
long GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const;
|
||||||
virtual bool VetEntry(const BlockEntry*) const = 0;
|
virtual bool VetEntry(const BlockEntry*) const = 0;
|
||||||
|
virtual long Seek(long long time_ns, const BlockEntry*&) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Track(Segment*, const Info&);
|
Track(Segment*, const Info&);
|
||||||
@@ -278,6 +269,7 @@ public:
|
|||||||
double GetFrameRate() const;
|
double GetFrameRate() const;
|
||||||
|
|
||||||
bool VetEntry(const BlockEntry*) const;
|
bool VetEntry(const BlockEntry*) const;
|
||||||
|
long Seek(long long time_ns, const BlockEntry*&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
long long m_width;
|
long long m_width;
|
||||||
@@ -298,6 +290,7 @@ public:
|
|||||||
long long GetChannels() const;
|
long long GetChannels() const;
|
||||||
long long GetBitDepth() const;
|
long long GetBitDepth() const;
|
||||||
bool VetEntry(const BlockEntry*) const;
|
bool VetEntry(const BlockEntry*) const;
|
||||||
|
long Seek(long long time_ns, const BlockEntry*&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_rate;
|
double m_rate;
|
||||||
@@ -506,6 +499,8 @@ private:
|
|||||||
class Segment
|
class Segment
|
||||||
{
|
{
|
||||||
friend class Cues;
|
friend class Cues;
|
||||||
|
friend class VideoTrack;
|
||||||
|
friend class AudioTrack;
|
||||||
|
|
||||||
Segment(const Segment&);
|
Segment(const Segment&);
|
||||||
Segment& operator=(const Segment&);
|
Segment& operator=(const Segment&);
|
||||||
@@ -524,10 +519,12 @@ public:
|
|||||||
|
|
||||||
long Load(); //loads headers and all clusters
|
long Load(); //loads headers and all clusters
|
||||||
|
|
||||||
//for incremental loading (splitter)
|
//for incremental loading
|
||||||
long long Unparsed() const;
|
long long Unparsed() const;
|
||||||
long long ParseHeaders(); //stops when first cluster is found
|
long long ParseHeaders(); //stops when first cluster is found
|
||||||
long LoadCluster(); //loads one cluster
|
//long FindNextCluster(long long& pos, long& size) const;
|
||||||
|
long LoadCluster(long long& pos, long& size); //load one cluster
|
||||||
|
long LoadCluster();
|
||||||
|
|
||||||
//This pair parses one cluster, but only changes the state of the
|
//This pair parses one cluster, but only changes the state of the
|
||||||
//segment object when the cluster is actually added to the index.
|
//segment object when the cluster is actually added to the index.
|
||||||
@@ -546,7 +543,7 @@ public:
|
|||||||
const Cluster* GetNext(const Cluster*);
|
const Cluster* GetNext(const Cluster*);
|
||||||
|
|
||||||
const Cluster* FindCluster(long long time_nanoseconds) const;
|
const Cluster* FindCluster(long long time_nanoseconds) const;
|
||||||
const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
|
//const BlockEntry* Seek(long long time_nanoseconds, const Track*) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -572,7 +569,14 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} //end namespace mkvparser
|
} //end namespace mkvparser
|
||||||
|
|
||||||
|
inline long mkvparser::Segment::LoadCluster()
|
||||||
|
{
|
||||||
|
long long pos;
|
||||||
|
long size;
|
||||||
|
|
||||||
|
return LoadCluster(pos, size);
|
||||||
|
}
|
||||||
|
|
||||||
#endif //MKVPARSER_HPP
|
#endif //MKVPARSER_HPP
|
||||||
|
|||||||
Reference in New Issue
Block a user