Compare commits
8 Commits
libwebm-1.
...
libwebm-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9203d2dcd1 | ||
|
|
be2f81abca | ||
|
|
cb5414a42a | ||
|
|
2ce6965b2d | ||
|
|
8db600e1c9 | ||
|
|
85353469f8 | ||
|
|
d97f236f81 | ||
|
|
790f639f2f |
301
mkvparser.cpp
301
mkvparser.cpp
@@ -11,24 +11,19 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
//#include <windows.h>
|
|
||||||
//#include "odbgstream.hpp"
|
|
||||||
//using std::endl;
|
|
||||||
|
|
||||||
mkvparser::IMkvReader::~IMkvReader()
|
mkvparser::IMkvReader::~IMkvReader()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)
|
void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)
|
||||||
{
|
{
|
||||||
major = 1;
|
major = 1;
|
||||||
minor = 0;
|
minor = 0;
|
||||||
build = 0;
|
build = 0;
|
||||||
revision = 7;
|
revision = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
||||||
{
|
{
|
||||||
assert(pReader);
|
assert(pReader);
|
||||||
@@ -113,7 +108,6 @@ long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long long mkvparser::GetUIntLength(
|
long long mkvparser::GetUIntLength(
|
||||||
IMkvReader* pReader,
|
IMkvReader* pReader,
|
||||||
long long pos,
|
long long pos,
|
||||||
@@ -155,7 +149,6 @@ long long mkvparser::GetUIntLength(
|
|||||||
return 0; //success
|
return 0; //success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long long mkvparser::SyncReadUInt(
|
long long mkvparser::SyncReadUInt(
|
||||||
IMkvReader* pReader,
|
IMkvReader* pReader,
|
||||||
long long pos,
|
long long pos,
|
||||||
@@ -235,6 +228,7 @@ long long mkvparser::UnserializeUInt(
|
|||||||
|
|
||||||
if (hr < 0)
|
if (hr < 0)
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
result <<= 8;
|
result <<= 8;
|
||||||
result |= b;
|
result |= b;
|
||||||
|
|
||||||
@@ -366,7 +360,6 @@ bool mkvparser::Match(
|
|||||||
long long& pos,
|
long long& pos,
|
||||||
unsigned long id_,
|
unsigned long id_,
|
||||||
long long& val)
|
long long& val)
|
||||||
|
|
||||||
{
|
{
|
||||||
assert(pReader);
|
assert(pReader);
|
||||||
assert(pos >= 0);
|
assert(pos >= 0);
|
||||||
@@ -880,7 +873,7 @@ long long Segment::CreateInstance(
|
|||||||
|
|
||||||
//TODO: if we liberalize the behavior of ReadUInt, we can
|
//TODO: if we liberalize the behavior of ReadUInt, we can
|
||||||
//probably eliminate having to use GetUIntLength here.
|
//probably eliminate having to use GetUIntLength here.
|
||||||
const long long size = ReadUInt(pReader, pos, len);
|
long long size = ReadUInt(pReader, pos, len);
|
||||||
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
return size;
|
return size;
|
||||||
@@ -889,17 +882,25 @@ long long Segment::CreateInstance(
|
|||||||
|
|
||||||
//Pos now points to start of payload
|
//Pos now points to start of payload
|
||||||
|
|
||||||
if ((pos + size) > total)
|
|
||||||
return E_FILE_FORMAT_INVALID;
|
|
||||||
|
|
||||||
if (id == 0x08538067) //Segment ID
|
if (id == 0x08538067) //Segment ID
|
||||||
{
|
{
|
||||||
|
//Handle "unknown size" for live streaming of webm files.
|
||||||
|
const long long unknown_size = (1LL << (7 * len)) - 1;
|
||||||
|
|
||||||
|
if (size == unknown_size)
|
||||||
|
size = total - pos;
|
||||||
|
else if ((pos + size) > total)
|
||||||
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
pSegment = new Segment(pReader, pos, size);
|
pSegment = new Segment(pReader, pos, size);
|
||||||
assert(pSegment); //TODO
|
assert(pSegment); //TODO
|
||||||
|
|
||||||
return 0; //success
|
return 0; //success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((pos + size) > total)
|
||||||
|
return E_FILE_FORMAT_INVALID;
|
||||||
|
|
||||||
pos += size; //consume payload
|
pos += size; //consume payload
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,10 +1074,15 @@ long Segment::ParseCluster(long long& off, long long& new_pos) const
|
|||||||
|
|
||||||
if (id == 0x0F43B675) //Cluster ID
|
if (id == 0x0F43B675) //Cluster ID
|
||||||
{
|
{
|
||||||
off = idpos - m_start; // >= 0 means we found a cluster
|
const long long off_ = idpos - m_start;
|
||||||
|
|
||||||
|
if (Cluster::HasBlockEntries(this, off_))
|
||||||
|
{
|
||||||
|
off = off_; // >= 0 means we found a cluster
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert(pos <= stop);
|
assert(pos <= stop);
|
||||||
|
|
||||||
@@ -1161,7 +1167,6 @@ bool Segment::AddCluster(long long off, long long pos)
|
|||||||
{
|
{
|
||||||
Cluster* const pCluster = Cluster::Parse(this, m_clusterCount, off);
|
Cluster* const pCluster = Cluster::Parse(this, m_clusterCount, off);
|
||||||
assert(pCluster);
|
assert(pCluster);
|
||||||
assert(pCluster->m_index == m_clusterCount);
|
|
||||||
|
|
||||||
AppendCluster(pCluster);
|
AppendCluster(pCluster);
|
||||||
assert(m_clusters);
|
assert(m_clusters);
|
||||||
@@ -1170,7 +1175,6 @@ bool Segment::AddCluster(long long off, long long pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_pos = pos; //m_pos >= stop is now we know we have all clusters
|
m_pos = pos; //m_pos >= stop is now we know we have all clusters
|
||||||
|
|
||||||
return (pos >= stop);
|
return (pos >= stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1270,21 +1274,27 @@ long Segment::LoadCluster()
|
|||||||
--m_clusterPreloadCount;
|
--m_clusterPreloadCount;
|
||||||
|
|
||||||
m_pos = pos + size; //consume payload
|
m_pos = pos + size; //consume payload
|
||||||
break;
|
assert(m_pos <= stop);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_pos = pos + size; //consume payload
|
||||||
|
assert(m_pos <= stop);
|
||||||
|
|
||||||
|
if (Cluster::HasBlockEntries(this, idoff))
|
||||||
|
{
|
||||||
Cluster* const pCluster = Cluster::Parse(this, idx, idoff);
|
Cluster* const pCluster = Cluster::Parse(this, idx, idoff);
|
||||||
assert(pCluster);
|
assert(pCluster);
|
||||||
assert(pCluster->m_index == idx);
|
|
||||||
|
|
||||||
AppendCluster(pCluster);
|
AppendCluster(pCluster);
|
||||||
assert(m_clusters);
|
assert(m_clusters);
|
||||||
assert(idx < m_clusterSize);
|
assert(idx < m_clusterSize);
|
||||||
assert(m_clusters[idx] == pCluster);
|
assert(m_clusters[idx] == pCluster);
|
||||||
|
|
||||||
m_pos = pos + size; //consume payload
|
return 0;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(m_pos <= stop);
|
assert(m_pos <= stop);
|
||||||
@@ -1509,15 +1519,17 @@ long Segment::Load()
|
|||||||
const long idx = m_clusterCount;
|
const long idx = m_clusterCount;
|
||||||
const long long off = idpos - m_start;
|
const long long off = idpos - m_start;
|
||||||
|
|
||||||
|
if (Cluster::HasBlockEntries(this, off))
|
||||||
|
{
|
||||||
Cluster* const pCluster = Cluster::Parse(this, idx, off);
|
Cluster* const pCluster = Cluster::Parse(this, idx, off);
|
||||||
assert(pCluster);
|
assert(pCluster);
|
||||||
assert(pCluster->m_index == idx);
|
|
||||||
|
|
||||||
AppendCluster(pCluster);
|
AppendCluster(pCluster);
|
||||||
assert(m_clusters);
|
assert(m_clusters);
|
||||||
assert(m_clusterSize > idx);
|
assert(m_clusterSize > idx);
|
||||||
assert(m_clusters[idx] == pCluster);
|
assert(m_clusters[idx] == pCluster);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (id == 0x0C53BB6B) //Cues ID
|
else if (id == 0x0C53BB6B) //Cues ID
|
||||||
{
|
{
|
||||||
assert(m_pCues == NULL);
|
assert(m_pCues == NULL);
|
||||||
@@ -2153,8 +2165,11 @@ const BlockEntry* Segment::GetBlock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(i == j);
|
assert(i == j);
|
||||||
|
assert(Cluster::HasBlockEntries(this, tp.m_pos));
|
||||||
|
|
||||||
Cluster* const pCluster = Cluster::Parse(this, -1, tp.m_pos);
|
Cluster* const pCluster = Cluster::Parse(this, -1, tp.m_pos);
|
||||||
|
assert(pCluster);
|
||||||
|
|
||||||
const ptrdiff_t idx = i - m_clusters;
|
const ptrdiff_t idx = i - m_clusters;
|
||||||
|
|
||||||
PreloadCluster(pCluster, idx);
|
PreloadCluster(pCluster, idx);
|
||||||
@@ -2529,9 +2544,14 @@ const Cluster* Segment::GetNext(const Cluster* pCurr)
|
|||||||
|
|
||||||
if (id == 0x0F43B675) //Cluster ID
|
if (id == 0x0F43B675) //Cluster ID
|
||||||
{
|
{
|
||||||
off_next = idpos - m_start;
|
const long long off_next_ = idpos - m_start;
|
||||||
|
|
||||||
|
if (Cluster::HasBlockEntries(this, off_next_))
|
||||||
|
{
|
||||||
|
off_next = off_next_;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pos += size; //consume payload
|
pos += size; //consume payload
|
||||||
}
|
}
|
||||||
@@ -2575,6 +2595,8 @@ const Cluster* Segment::GetNext(const Cluster* pCurr)
|
|||||||
assert(i == j);
|
assert(i == j);
|
||||||
|
|
||||||
Cluster* const pNext = Cluster::Parse(this, -1, off_next);
|
Cluster* const pNext = Cluster::Parse(this, -1, off_next);
|
||||||
|
assert(pNext);
|
||||||
|
|
||||||
const ptrdiff_t idx_next = i - m_clusters; //insertion position
|
const ptrdiff_t idx_next = i - m_clusters; //insertion position
|
||||||
|
|
||||||
PreloadCluster(pNext, idx_next);
|
PreloadCluster(pNext, idx_next);
|
||||||
@@ -2761,22 +2783,10 @@ const BlockEntry* Segment::Seek(
|
|||||||
assert(pCluster->GetTime() <= time_ns);
|
assert(pCluster->GetTime() <= time_ns);
|
||||||
|
|
||||||
{
|
{
|
||||||
const BlockEntry* const pBlockEntry = pCluster->GetEntry(pTrack);
|
const BlockEntry* const pBE = pCluster->GetEntry(pTrack, time_ns);
|
||||||
|
|
||||||
if ((pBlockEntry != 0) && !pBlockEntry->EOS()) //found a keyframe
|
if ((pBE != 0) && !pBE->EOS()) //found a keyframe
|
||||||
{
|
return pBE;
|
||||||
const Block* const pBlock = pBlockEntry->GetBlock();
|
|
||||||
assert(pBlock);
|
|
||||||
|
|
||||||
//NOTE: this isn't necessarily the keyframe we want,
|
|
||||||
//since there might another keyframe on this same
|
|
||||||
//cluster with a greater timecode, that is still
|
|
||||||
//less than the requested time. For now we
|
|
||||||
//simply return the first keyframe we find.
|
|
||||||
|
|
||||||
if (pBlock->GetTime(pCluster) <= time_ns)
|
|
||||||
return pBlockEntry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack);
|
const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack);
|
||||||
@@ -2984,13 +2994,12 @@ Track::~Track()
|
|||||||
Track::Info::Info():
|
Track::Info::Info():
|
||||||
type(-1),
|
type(-1),
|
||||||
number(-1),
|
number(-1),
|
||||||
uid(-1),
|
uid(ULLONG_MAX),
|
||||||
nameAsUTF8(NULL),
|
nameAsUTF8(NULL),
|
||||||
codecId(NULL),
|
codecId(NULL),
|
||||||
codecPrivate(NULL),
|
codecPrivate(NULL),
|
||||||
codecPrivateSize(0),
|
codecPrivateSize(0),
|
||||||
codecNameAsUTF8(NULL)
|
codecNameAsUTF8(NULL)
|
||||||
//lacing(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3027,6 +3036,11 @@ long long Track::GetNumber() const
|
|||||||
return m_info.number;
|
return m_info.number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long long Track::GetUid() const
|
||||||
|
{
|
||||||
|
return m_info.uid;
|
||||||
|
}
|
||||||
|
|
||||||
const char* Track::GetNameAsUTF8() const
|
const char* Track::GetNameAsUTF8() const
|
||||||
{
|
{
|
||||||
return m_info.nameAsUTF8;
|
return m_info.nameAsUTF8;
|
||||||
@@ -3060,11 +3074,7 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
|||||||
{
|
{
|
||||||
const Cluster* pCluster = m_pSegment->GetFirst();
|
const Cluster* pCluster = m_pSegment->GetFirst();
|
||||||
|
|
||||||
//If Segment::GetFirst returns NULL, then this must be a network
|
for (int i = 0; ; )
|
||||||
//download, and we haven't loaded any clusters yet. In this case,
|
|
||||||
//returning NULL from Track::GetFirst means the same thing.
|
|
||||||
|
|
||||||
for (int i = 0; i < 100; ++i) //arbitrary upper bound
|
|
||||||
{
|
{
|
||||||
if (pCluster == NULL)
|
if (pCluster == NULL)
|
||||||
{
|
{
|
||||||
@@ -3086,7 +3096,13 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
|||||||
|
|
||||||
pBlockEntry = pCluster->GetFirst();
|
pBlockEntry = pCluster->GetFirst();
|
||||||
|
|
||||||
while (pBlockEntry)
|
if (pBlockEntry == 0) //empty cluster
|
||||||
|
{
|
||||||
|
pCluster = m_pSegment->GetNext(pCluster);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
const Block* const pBlock = pBlockEntry->GetBlock();
|
const Block* const pBlock = pBlockEntry->GetBlock();
|
||||||
assert(pBlock);
|
assert(pBlock);
|
||||||
@@ -3095,8 +3111,16 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
||||||
|
|
||||||
|
if (pBlockEntry == 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
|
||||||
|
if (i >= 100)
|
||||||
|
break;
|
||||||
|
|
||||||
pCluster = m_pSegment->GetNext(pCluster);
|
pCluster = m_pSegment->GetNext(pCluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3520,8 +3544,8 @@ void Tracks::ParseTrackEntry(
|
|||||||
#endif
|
#endif
|
||||||
if (Match(pReader, pos, 0x57, i.number))
|
if (Match(pReader, pos, 0x57, i.number))
|
||||||
assert(i.number > 0);
|
assert(i.number > 0);
|
||||||
else if (Match(pReader, pos, 0x33C5, i.uid))
|
//else if (Match(pReader, pos, 0x33C5, i.uid))
|
||||||
;
|
// ;
|
||||||
else if (Match(pReader, pos, 0x03, i.type))
|
else if (Match(pReader, pos, 0x03, i.type))
|
||||||
;
|
;
|
||||||
else if (Match(pReader, pos, 0x136E, i.nameAsUTF8))
|
else if (Match(pReader, pos, 0x136E, i.nameAsUTF8))
|
||||||
@@ -3542,6 +3566,9 @@ void Tracks::ParseTrackEntry(
|
|||||||
{
|
{
|
||||||
long len;
|
long len;
|
||||||
|
|
||||||
|
const long long idpos = pos;
|
||||||
|
idpos;
|
||||||
|
|
||||||
const long long id = ReadUInt(pReader, pos, len);
|
const long long id = ReadUInt(pReader, pos, len);
|
||||||
assert(id >= 0); //TODO: handle error case
|
assert(id >= 0); //TODO: handle error case
|
||||||
assert((pos + len) <= stop);
|
assert((pos + len) <= stop);
|
||||||
@@ -3568,6 +3595,27 @@ void Tracks::ParseTrackEntry(
|
|||||||
audioSettings.start = start;
|
audioSettings.start = start;
|
||||||
audioSettings.size = size;
|
audioSettings.size = size;
|
||||||
}
|
}
|
||||||
|
else if (id == 0x33C5) //Track UID
|
||||||
|
{
|
||||||
|
assert(size <= 8);
|
||||||
|
|
||||||
|
i.uid = 0;
|
||||||
|
long long pos_ = start;
|
||||||
|
const long long pos_end = start + size;
|
||||||
|
|
||||||
|
while (pos_ != pos_end)
|
||||||
|
{
|
||||||
|
unsigned char b;
|
||||||
|
|
||||||
|
const long status = pReader->Read(pos_, 1, &b);
|
||||||
|
assert(status == 0);
|
||||||
|
|
||||||
|
i.uid <<= 8;
|
||||||
|
i.uid |= b;
|
||||||
|
|
||||||
|
++pos_;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3749,6 +3797,9 @@ Cluster* Cluster::Parse(
|
|||||||
assert(off >= 0);
|
assert(off >= 0);
|
||||||
assert(off < pSegment->m_size);
|
assert(off < pSegment->m_size);
|
||||||
|
|
||||||
|
//if (!HasBlockEntries(pSegment, off))
|
||||||
|
// return NULL;
|
||||||
|
|
||||||
Cluster* const pCluster = new Cluster(pSegment, idx, -off);
|
Cluster* const pCluster = new Cluster(pSegment, idx, -off);
|
||||||
assert(pCluster);
|
assert(pCluster);
|
||||||
|
|
||||||
@@ -3763,7 +3814,7 @@ Cluster::Cluster() :
|
|||||||
m_size(0),
|
m_size(0),
|
||||||
m_timecode(0),
|
m_timecode(0),
|
||||||
m_entries(NULL),
|
m_entries(NULL),
|
||||||
m_entriesCount(0)
|
m_entries_count(0) //means "no entries"
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3778,15 +3829,18 @@ Cluster::Cluster(
|
|||||||
m_size(-1),
|
m_size(-1),
|
||||||
m_timecode(-1),
|
m_timecode(-1),
|
||||||
m_entries(NULL),
|
m_entries(NULL),
|
||||||
m_entriesCount(0)
|
m_entries_count(-1) //means "has not been parsed yet"
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Cluster::~Cluster()
|
Cluster::~Cluster()
|
||||||
{
|
{
|
||||||
|
if (m_entries_count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
BlockEntry** i = m_entries;
|
BlockEntry** i = m_entries;
|
||||||
BlockEntry** const j = m_entries + m_entriesCount;
|
BlockEntry** const j = m_entries + m_entries_count;
|
||||||
|
|
||||||
while (i != j)
|
while (i != j)
|
||||||
{
|
{
|
||||||
@@ -3806,15 +3860,80 @@ bool Cluster::EOS() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Cluster::HasBlockEntries(
|
||||||
|
const Segment* pSegment,
|
||||||
|
long long off) //relative to start of segment payload
|
||||||
|
{
|
||||||
|
assert(pSegment);
|
||||||
|
assert(off >= 0); //relative to segment
|
||||||
|
|
||||||
|
IMkvReader* const pReader = pSegment->m_pReader;
|
||||||
|
|
||||||
|
long long pos = pSegment->m_start + off; //absolute
|
||||||
|
long long size;
|
||||||
|
|
||||||
|
{
|
||||||
|
long len;
|
||||||
|
|
||||||
|
const long long id = ReadUInt(pReader, pos, len);
|
||||||
|
id;
|
||||||
|
assert(id >= 0);
|
||||||
|
assert(id == 0x0F43B675); //Cluster ID
|
||||||
|
|
||||||
|
pos += len; //consume id
|
||||||
|
|
||||||
|
size = ReadUInt(pReader, pos, len);
|
||||||
|
assert(size > 0);
|
||||||
|
|
||||||
|
pos += len; //consume size
|
||||||
|
|
||||||
|
//pos now points to start of payload
|
||||||
|
}
|
||||||
|
|
||||||
|
const long long stop = pos + size;
|
||||||
|
|
||||||
|
while (pos < stop)
|
||||||
|
{
|
||||||
|
long len;
|
||||||
|
|
||||||
|
const long long id = ReadUInt(pReader, pos, len);
|
||||||
|
assert(id >= 0); //TODO
|
||||||
|
assert((pos + len) <= stop);
|
||||||
|
|
||||||
|
pos += len; //consume id
|
||||||
|
|
||||||
|
const long long size = ReadUInt(pReader, pos, len);
|
||||||
|
assert(size >= 0); //TODO
|
||||||
|
assert((pos + len) <= stop);
|
||||||
|
|
||||||
|
pos += len; //consume size
|
||||||
|
|
||||||
|
if (id == 0x20) //BlockGroup ID
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (id == 0x23) //SimpleBlock ID
|
||||||
|
return true;
|
||||||
|
|
||||||
|
pos += size; //consume payload
|
||||||
|
assert(pos <= stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Cluster::LoadBlockEntries() const
|
void Cluster::LoadBlockEntries() const
|
||||||
{
|
{
|
||||||
if (m_entries)
|
if (m_entries)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (m_entries_count == 0) //already parsed, and no entries found
|
||||||
|
return;
|
||||||
|
|
||||||
assert(m_pSegment);
|
assert(m_pSegment);
|
||||||
assert(m_pos);
|
assert(m_pos);
|
||||||
assert(m_size);
|
assert(m_size);
|
||||||
assert(m_entriesCount == 0);
|
assert(m_entries_count < 0);
|
||||||
|
|
||||||
IMkvReader* const pReader = m_pSegment->m_pReader;
|
IMkvReader* const pReader = m_pSegment->m_pReader;
|
||||||
|
|
||||||
@@ -3852,7 +3971,7 @@ void Cluster::LoadBlockEntries() const
|
|||||||
//First count the number of entries
|
//First count the number of entries
|
||||||
|
|
||||||
long long idx = pos; //points to start of payload
|
long long idx = pos; //points to start of payload
|
||||||
m_entriesCount = 0;
|
m_entries_count = 0;
|
||||||
|
|
||||||
while (idx < stop)
|
while (idx < stop)
|
||||||
{
|
{
|
||||||
@@ -3880,9 +3999,9 @@ void Cluster::LoadBlockEntries() const
|
|||||||
idx += len; //consume size
|
idx += len; //consume size
|
||||||
|
|
||||||
if (id == 0x20) //BlockGroup ID
|
if (id == 0x20) //BlockGroup ID
|
||||||
++m_entriesCount;
|
++m_entries_count;
|
||||||
else if (id == 0x23) //SimpleBlock ID
|
else if (id == 0x23) //SimpleBlock ID
|
||||||
++m_entriesCount;
|
++m_entries_count;
|
||||||
|
|
||||||
idx += size; //consume payload
|
idx += size; //consume payload
|
||||||
assert(idx <= stop);
|
assert(idx <= stop);
|
||||||
@@ -3892,11 +4011,11 @@ void Cluster::LoadBlockEntries() const
|
|||||||
assert(idx == stop);
|
assert(idx == stop);
|
||||||
assert(m_timecode >= 0);
|
assert(m_timecode >= 0);
|
||||||
|
|
||||||
if (m_entriesCount == 0) //TODO: handle empty clusters
|
if (m_entries_count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_entries = new BlockEntry*[m_entriesCount];
|
m_entries = new BlockEntry*[m_entries_count];
|
||||||
size_t index = 0;
|
long index = 0;
|
||||||
|
|
||||||
while (pos < stop)
|
while (pos < stop)
|
||||||
{
|
{
|
||||||
@@ -3929,7 +4048,7 @@ void Cluster::LoadBlockEntries() const
|
|||||||
|
|
||||||
assert(pos == stop);
|
assert(pos == stop);
|
||||||
assert(timecode >= 0);
|
assert(timecode >= 0);
|
||||||
assert(index == m_entriesCount);
|
assert(index == m_entries_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3988,9 +4107,9 @@ long long Cluster::GetLastTime() const
|
|||||||
|
|
||||||
void Cluster::ParseBlockGroup(long long st, long long sz, size_t idx) const
|
void Cluster::ParseBlockGroup(long long st, long long sz, size_t idx) const
|
||||||
{
|
{
|
||||||
assert(m_entries);
|
assert(m_entries != NULL);
|
||||||
assert(m_entriesCount);
|
assert(m_entries_count > 0);
|
||||||
assert(idx < m_entriesCount);
|
assert(idx < size_t(m_entries_count));
|
||||||
|
|
||||||
Cluster* const this_ = const_cast<Cluster*>(this);
|
Cluster* const this_ = const_cast<Cluster*>(this);
|
||||||
|
|
||||||
@@ -4004,9 +4123,9 @@ void Cluster::ParseBlockGroup(long long st, long long sz, size_t idx) const
|
|||||||
|
|
||||||
void Cluster::ParseSimpleBlock(long long st, long long sz, size_t idx) const
|
void Cluster::ParseSimpleBlock(long long st, long long sz, size_t idx) const
|
||||||
{
|
{
|
||||||
assert(m_entries);
|
assert(m_entries != NULL);
|
||||||
assert(m_entriesCount);
|
assert(m_entries_count > 0);
|
||||||
assert(idx < m_entriesCount);
|
assert(idx < size_t(m_entries_count));
|
||||||
|
|
||||||
Cluster* const this_ = const_cast<Cluster*>(this);
|
Cluster* const this_ = const_cast<Cluster*>(this);
|
||||||
|
|
||||||
@@ -4021,7 +4140,7 @@ const BlockEntry* Cluster::GetFirst() const
|
|||||||
{
|
{
|
||||||
LoadBlockEntries();
|
LoadBlockEntries();
|
||||||
|
|
||||||
if ((m_entries == NULL) || (m_entriesCount == 0))
|
if ((m_entries == NULL) || (m_entries_count <= 0))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
const BlockEntry* const pFirst = m_entries[0];
|
const BlockEntry* const pFirst = m_entries[0];
|
||||||
@@ -4035,10 +4154,10 @@ const BlockEntry* Cluster::GetLast() const
|
|||||||
{
|
{
|
||||||
LoadBlockEntries();
|
LoadBlockEntries();
|
||||||
|
|
||||||
if ((m_entries == NULL) || (m_entriesCount == 0))
|
if ((m_entries == NULL) || (m_entries_count <= 0))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
const size_t idx = m_entriesCount - 1;
|
const long idx = m_entries_count - 1;
|
||||||
|
|
||||||
const BlockEntry* const pLast = m_entries[idx];
|
const BlockEntry* const pLast = m_entries[idx];
|
||||||
assert(pLast);
|
assert(pLast);
|
||||||
@@ -4050,38 +4169,42 @@ const BlockEntry* Cluster::GetLast() const
|
|||||||
const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
|
const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
|
||||||
{
|
{
|
||||||
assert(pEntry);
|
assert(pEntry);
|
||||||
assert(m_entries);
|
assert(m_entries != NULL);
|
||||||
assert(m_entriesCount);
|
assert(m_entries_count > 0);
|
||||||
|
|
||||||
size_t idx = pEntry->GetIndex();
|
size_t idx = pEntry->GetIndex();
|
||||||
assert(idx < m_entriesCount);
|
assert(idx < size_t(m_entries_count));
|
||||||
assert(m_entries[idx] == pEntry);
|
assert(m_entries[idx] == pEntry);
|
||||||
|
|
||||||
++idx;
|
++idx;
|
||||||
|
|
||||||
if (idx >= m_entriesCount)
|
if (idx >= size_t(m_entries_count))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return m_entries[idx];
|
return m_entries[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const BlockEntry* Cluster::GetEntry(const Track* pTrack) const
|
const BlockEntry* Cluster::GetEntry(
|
||||||
|
const Track* pTrack,
|
||||||
|
long long time_ns) const
|
||||||
{
|
{
|
||||||
assert(pTrack);
|
assert(pTrack);
|
||||||
|
|
||||||
if (m_pSegment == NULL) //EOS
|
if (m_pSegment == NULL) //this is the special EOS cluster
|
||||||
return pTrack->GetEOS();
|
return pTrack->GetEOS();
|
||||||
|
|
||||||
LoadBlockEntries();
|
LoadBlockEntries();
|
||||||
|
|
||||||
if ((m_entries == NULL) || (m_entriesCount == 0))
|
if ((m_entries == NULL) || (m_entries_count <= 0))
|
||||||
return NULL;
|
return NULL; //return EOS here?
|
||||||
|
|
||||||
|
const BlockEntry* pResult = pTrack->GetEOS();
|
||||||
|
|
||||||
BlockEntry** i = m_entries;
|
BlockEntry** i = m_entries;
|
||||||
assert(i);
|
assert(i);
|
||||||
|
|
||||||
BlockEntry** const j = i + m_entriesCount;
|
BlockEntry** const j = i + m_entries_count;
|
||||||
|
|
||||||
while (i != j)
|
while (i != j)
|
||||||
{
|
{
|
||||||
@@ -4096,10 +4219,27 @@ const BlockEntry* Cluster::GetEntry(const Track* pTrack) const
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pTrack->VetEntry(pEntry))
|
if (pTrack->VetEntry(pEntry))
|
||||||
|
{
|
||||||
|
if (time_ns < 0) //just want first candidate block
|
||||||
return pEntry;
|
return pEntry;
|
||||||
|
|
||||||
|
const long long ns = pBlock->GetTime(this);
|
||||||
|
|
||||||
|
if (ns > time_ns)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pResult = pEntry;
|
||||||
|
}
|
||||||
|
else if (time_ns >= 0)
|
||||||
|
{
|
||||||
|
const long long ns = pBlock->GetTime(this);
|
||||||
|
|
||||||
|
if (ns > time_ns)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pTrack->GetEOS(); //no satisfactory block found
|
return pResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -4115,7 +4255,7 @@ Cluster::GetEntry(
|
|||||||
if (m_entries == NULL)
|
if (m_entries == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
const long long count = m_entriesCount;
|
const long long count = m_entries_count;
|
||||||
|
|
||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -4205,7 +4345,10 @@ const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const
|
|||||||
|
|
||||||
LoadBlockEntries();
|
LoadBlockEntries();
|
||||||
|
|
||||||
BlockEntry** i = m_entries + m_entriesCount;
|
if ((m_entries == NULL) || (m_entries_count <= 0))
|
||||||
|
return pTrack->GetEOS();
|
||||||
|
|
||||||
|
BlockEntry** i = m_entries + m_entries_count;
|
||||||
BlockEntry** const j = m_entries;
|
BlockEntry** const j = m_entries;
|
||||||
|
|
||||||
while (i != j)
|
while (i != j)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ short Unserialize2SInt(IMkvReader*, long long);
|
|||||||
signed char Unserialize1SInt(IMkvReader*, long long);
|
signed char Unserialize1SInt(IMkvReader*, long long);
|
||||||
bool Match(IMkvReader*, long long&, unsigned long, long long&);
|
bool Match(IMkvReader*, long long&, unsigned long, long long&);
|
||||||
bool Match(IMkvReader*, long long&, unsigned long, char*&);
|
bool Match(IMkvReader*, long long&, unsigned long, char*&);
|
||||||
bool Match(IMkvReader*, long long&, unsigned long,unsigned char*&, size_t&);
|
bool Match(IMkvReader*, long long&, unsigned long, unsigned char*&, size_t&);
|
||||||
bool Match(IMkvReader*, long long&, unsigned long, double&);
|
bool Match(IMkvReader*, long long&, unsigned long, double&);
|
||||||
bool Match(IMkvReader*, long long&, unsigned long, short&);
|
bool Match(IMkvReader*, long long&, unsigned long, short&);
|
||||||
|
|
||||||
@@ -209,6 +209,7 @@ public:
|
|||||||
|
|
||||||
long long GetType() const;
|
long long GetType() const;
|
||||||
long long GetNumber() const;
|
long long GetNumber() const;
|
||||||
|
unsigned long long GetUid() const;
|
||||||
const char* GetNameAsUTF8() const;
|
const char* GetNameAsUTF8() const;
|
||||||
const char* GetCodecNameAsUTF8() const;
|
const char* GetCodecNameAsUTF8() const;
|
||||||
const char* GetCodecId() const;
|
const char* GetCodecId() const;
|
||||||
@@ -227,7 +228,7 @@ public:
|
|||||||
{
|
{
|
||||||
long long type;
|
long long type;
|
||||||
long long number;
|
long long number;
|
||||||
long long uid;
|
unsigned long long uid;
|
||||||
char* nameAsUTF8;
|
char* nameAsUTF8;
|
||||||
char* codecId;
|
char* codecId;
|
||||||
unsigned char* codecPrivate;
|
unsigned char* codecPrivate;
|
||||||
@@ -472,12 +473,14 @@ public:
|
|||||||
const BlockEntry* GetFirst() const;
|
const BlockEntry* GetFirst() const;
|
||||||
const BlockEntry* GetLast() const;
|
const BlockEntry* GetLast() const;
|
||||||
const BlockEntry* GetNext(const BlockEntry*) const;
|
const BlockEntry* GetNext(const BlockEntry*) const;
|
||||||
const BlockEntry* GetEntry(const Track*) const;
|
const BlockEntry* GetEntry(const Track*, long long ns = -1) const;
|
||||||
const BlockEntry* GetEntry(
|
const BlockEntry* GetEntry(
|
||||||
const CuePoint&,
|
const CuePoint&,
|
||||||
const CuePoint::TrackPosition&) const;
|
const CuePoint::TrackPosition&) const;
|
||||||
const BlockEntry* GetMaxKey(const VideoTrack*) const;
|
const BlockEntry* GetMaxKey(const VideoTrack*) const;
|
||||||
|
|
||||||
|
static bool HasBlockEntries(const Segment*, long long);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Cluster(Segment*, long, long long off);
|
Cluster(Segment*, long, long long off);
|
||||||
|
|
||||||
@@ -490,7 +493,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
mutable long long m_timecode;
|
mutable long long m_timecode;
|
||||||
mutable BlockEntry** m_entries;
|
mutable BlockEntry** m_entries;
|
||||||
mutable size_t m_entriesCount;
|
mutable long m_entries_count;
|
||||||
|
|
||||||
void Load() const;
|
void Load() const;
|
||||||
void LoadBlockEntries() const;
|
void LoadBlockEntries() const;
|
||||||
|
|||||||
@@ -43,13 +43,13 @@
|
|||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="false"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="3"
|
RuntimeLibrary="1"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="4"
|
||||||
Detect64BitPortabilityProblems="false"
|
Detect64BitPortabilityProblems="false"
|
||||||
DebugInformationFormat="4"
|
DebugInformationFormat="1"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCManagedResourceCompilerTool"
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
|||||||
15
sample.cpp
15
sample.cpp
@@ -148,14 +148,14 @@ int main(int argc, char* argv[])
|
|||||||
if (pTrack == NULL)
|
if (pTrack == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const long long trackType_ = pTrack->GetType();
|
const long long trackType = pTrack->GetType();
|
||||||
unsigned long trackType = static_cast<unsigned long>(trackType_);
|
const long long trackNumber = pTrack->GetNumber();
|
||||||
|
const unsigned long long trackUid = pTrack->GetUid();
|
||||||
unsigned long trackNumber = pTrack->GetNumber();
|
|
||||||
const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());
|
const wchar_t* const pTrackName = utf8towcs(pTrack->GetNameAsUTF8());
|
||||||
|
|
||||||
printf("\t\tTrack Type\t\t: %ld\n", trackType);
|
printf("\t\tTrack Type\t\t: %ld\n", trackType);
|
||||||
printf("\t\tTrack Number\t\t: %ld\n", trackNumber);
|
printf("\t\tTrack Number\t\t: %ld\n", trackNumber);
|
||||||
|
printf("\t\tTrack Uid\t\t: %lld\n", trackUid);
|
||||||
|
|
||||||
if (pTrackName == NULL)
|
if (pTrackName == NULL)
|
||||||
printf("\t\tTrack Name\t\t: NULL\n");
|
printf("\t\tTrack Name\t\t: NULL\n");
|
||||||
@@ -235,8 +235,9 @@ int main(int argc, char* argv[])
|
|||||||
while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
|
while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
|
||||||
{
|
{
|
||||||
const Block* const pBlock = pBlockEntry->GetBlock();
|
const Block* const pBlock = pBlockEntry->GetBlock();
|
||||||
const unsigned long trackNum = pBlock->GetTrackNumber();
|
const long long trackNum = pBlock->GetTrackNumber();
|
||||||
const Track* const pTrack = pTracks->GetTrackByNumber(trackNum);
|
const unsigned long tn = static_cast<unsigned long>(trackNum);
|
||||||
|
const Track* const pTrack = pTracks->GetTrackByNumber(tn);
|
||||||
const long long trackType = pTrack->GetType();
|
const long long trackType = pTrack->GetType();
|
||||||
const int frameCount = pBlock->GetFrameCount();
|
const int frameCount = pBlock->GetFrameCount();
|
||||||
const long long time_ns = pBlock->GetTime(pCluster);
|
const long long time_ns = pBlock->GetTime(pCluster);
|
||||||
@@ -250,7 +251,7 @@ int main(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
const Block::Frame& theFrame = pBlock->GetFrame(i);
|
const Block::Frame& theFrame = pBlock->GetFrame(i);
|
||||||
const long size = theFrame.len;
|
const long size = theFrame.len;
|
||||||
const long offset = theFrame.pos;
|
const long long offset = theFrame.pos;
|
||||||
printf("\t\t\t %15ld,%15lx\n", size, offset);
|
printf("\t\t\t %15ld,%15lx\n", size, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,13 +43,13 @@
|
|||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories="..\"
|
AdditionalIncludeDirectories="..\"
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="false"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="3"
|
RuntimeLibrary="1"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="3"
|
WarningLevel="4"
|
||||||
Detect64BitPortabilityProblems="false"
|
Detect64BitPortabilityProblems="false"
|
||||||
DebugInformationFormat="4"
|
DebugInformationFormat="1"
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCManagedResourceCompilerTool"
|
Name="VCManagedResourceCompilerTool"
|
||||||
|
|||||||
Reference in New Issue
Block a user