Index: source/libvpx/third_party/libwebm/mkvparser.cpp |
diff --git a/source/libvpx/third_party/libwebm/mkvparser.cpp b/source/libvpx/third_party/libwebm/mkvparser.cpp |
index 441f16596b3d11f87375acb8ad040b5c2ea2afad..fc01be526409dafd5c1b6e4c173f052d5fbf2dab 100644 |
--- a/source/libvpx/third_party/libwebm/mkvparser.cpp |
+++ b/source/libvpx/third_party/libwebm/mkvparser.cpp |
@@ -23,7 +23,7 @@ void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) { |
major = 1; |
minor = 0; |
build = 0; |
- revision = 28; |
+ revision = 30; |
} |
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) { |
@@ -130,6 +130,8 @@ long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos, |
return 0; // success |
} |
+// TODO(vigneshv): This function assumes that unsigned values never have their |
+// high bit set. |
long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos, |
long long size) { |
assert(pReader); |
@@ -217,8 +219,8 @@ long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos, |
return 0; |
} |
-long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, long size, |
- long long& result) { |
+long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, |
+ long long size, long long& result) { |
assert(pReader); |
assert(pos >= 0); |
assert(size > 0); |
@@ -605,6 +607,7 @@ Segment::Segment(IMkvReader* pReader, long long elem_start, |
m_pTracks(NULL), |
m_pCues(NULL), |
m_pChapters(NULL), |
+ m_pTags(NULL), |
m_clusters(NULL), |
m_clusterCount(0), |
m_clusterPreloadCount(0), |
@@ -629,6 +632,7 @@ Segment::~Segment() { |
delete m_pInfo; |
delete m_pCues; |
delete m_pChapters; |
+ delete m_pTags; |
delete m_pSeekHead; |
} |
@@ -907,6 +911,19 @@ long long Segment::ParseHeaders() { |
if (status) |
return status; |
} |
+ } else if (id == 0x0254C367) { // Tags ID |
+ if (m_pTags == NULL) { |
+ m_pTags = new (std::nothrow) |
+ Tags(this, pos, size, element_start, element_size); |
+ |
+ if (m_pTags == NULL) |
+ return -1; |
+ |
+ const long status = m_pTags->Parse(); |
+ |
+ if (status) |
+ return status; |
+ } |
} |
m_pos = pos + size; // consume payload |
@@ -1025,23 +1042,11 @@ long Segment::DoLoadCluster(long long& pos, long& len) { |
const long long unknown_size = (1LL << (7 * len)) - 1; |
-#if 0 // we must handle this to support live webm |
- if (size == unknown_size) |
- return E_FILE_FORMAT_INVALID; //TODO: allow this |
-#endif |
- |
if ((segment_stop >= 0) && (size != unknown_size) && |
((pos + size) > segment_stop)) { |
return E_FILE_FORMAT_INVALID; |
} |
-#if 0 // commented-out, to support incremental cluster parsing |
- len = static_cast<long>(size); |
- |
- if ((pos + size) > avail) |
- return E_BUFFER_NOT_FULL; |
-#endif |
- |
if (id == 0x0C53BB6B) { // Cues ID |
if (size == unknown_size) |
return E_FILE_FORMAT_INVALID; // TODO: liberalize |
@@ -1157,10 +1162,8 @@ long Segment::DoLoadCluster(long long& pos, long& len) { |
} |
if (status == 0) { // no entries found |
- if (cluster_size < 0) |
- return E_FILE_FORMAT_INVALID; // TODO: handle this |
- |
- pos += cluster_size; |
+ if (cluster_size >= 0) |
+ pos += cluster_size; |
if ((total >= 0) && (pos >= total)) { |
m_pos = total; |
@@ -1201,306 +1204,15 @@ long Segment::DoLoadCluster(long long& pos, long& len) { |
return 0; // partial success, since we have a new cluster |
-// status == 0 means "no block entries found" |
- |
-// pos designates start of payload |
-// m_pos has NOT been adjusted yet (in case we need to come back here) |
- |
-#if 0 |
- |
- if (cluster_size < 0) { //unknown size |
- const long long payload_pos = pos; //absolute pos of cluster payload |
- |
- for (;;) { //determine cluster size |
- if ((total >= 0) && (pos >= total)) |
- break; |
- |
- if ((segment_stop >= 0) && (pos >= segment_stop)) |
- break; //no more clusters |
- |
- //Read ID |
- |
- if ((pos + 1) > avail) |
- { |
- len = 1; |
- return E_BUFFER_NOT_FULL; |
- } |
- |
- long long result = GetUIntLength(m_pReader, pos, len); |
- |
- if (result < 0) //error |
- return static_cast<long>(result); |
- |
- if (result > 0) //weird |
- return E_BUFFER_NOT_FULL; |
- |
- if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
- return E_FILE_FORMAT_INVALID; |
- |
- if ((pos + len) > avail) |
- return E_BUFFER_NOT_FULL; |
- |
- const long long idpos = pos; |
- const long long id = ReadUInt(m_pReader, idpos, len); |
- |
- if (id < 0) //error (or underflow) |
- return static_cast<long>(id); |
- |
- //This is the distinguished set of ID's we use to determine |
- //that we have exhausted the sub-element's inside the cluster |
- //whose ID we parsed earlier. |
- |
- if (id == 0x0F43B675) //Cluster ID |
- break; |
- |
- if (id == 0x0C53BB6B) //Cues ID |
- break; |
- |
- switch (id) |
- { |
- case 0x20: //BlockGroup |
- case 0x23: //Simple Block |
- case 0x67: //TimeCode |
- case 0x2B: //PrevSize |
- break; |
- |
- default: |
- assert(false); |
- break; |
- } |
- |
- pos += len; //consume ID (of sub-element) |
- |
- //Read Size |
- |
- if ((pos + 1) > avail) |
- { |
- len = 1; |
- return E_BUFFER_NOT_FULL; |
- } |
- |
- result = GetUIntLength(m_pReader, pos, len); |
- |
- if (result < 0) //error |
- return static_cast<long>(result); |
- |
- if (result > 0) //weird |
- return E_BUFFER_NOT_FULL; |
- |
- if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
- return E_FILE_FORMAT_INVALID; |
- |
- if ((pos + len) > avail) |
- 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 size field of element |
- |
- //pos now points to start of sub-element's payload |
- |
- if (size == 0) //weird |
- continue; |
- |
- const long long unknown_size = (1LL << (7 * len)) - 1; |
- |
- if (size == unknown_size) |
- return E_FILE_FORMAT_INVALID; //not allowed for sub-elements |
- |
- if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird |
- return E_FILE_FORMAT_INVALID; |
- |
- pos += size; //consume payload of sub-element |
- assert((segment_stop < 0) || (pos <= segment_stop)); |
- } //determine cluster size |
- |
- cluster_size = pos - payload_pos; |
- assert(cluster_size >= 0); |
- |
- pos = payload_pos; //reset and re-parse original cluster |
- } |
- |
- if (m_clusterPreloadCount > 0) |
- { |
- assert(idx < m_clusterSize); |
- |
- Cluster* const pCluster = m_clusters[idx]; |
- assert(pCluster); |
- assert(pCluster->m_index < 0); |
- |
- const long long off = pCluster->GetPosition(); |
- assert(off >= 0); |
- |
- if (off == cluster_off) //preloaded already |
- return E_FILE_FORMAT_INVALID; //subtle |
- } |
- |
- m_pos = pos + cluster_size; //consume payload |
- assert((segment_stop < 0) || (m_pos <= segment_stop)); |
- |
- return 2; //try to find another cluster |
- |
-#endif |
+ // status == 0 means "no block entries found" |
+ // pos designates start of payload |
+ // m_pos has NOT been adjusted yet (in case we need to come back here) |
} |
long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) { |
assert(m_pos < 0); |
assert(m_pUnknownSize); |
-#if 0 |
- assert(m_pUnknownSize->GetElementSize() < 0); //TODO: verify this |
- |
- const long long element_start = m_pUnknownSize->m_element_start; |
- |
- pos = -m_pos; |
- assert(pos > element_start); |
- |
- //We have already consumed the (cluster) ID and size fields. |
- //We just need to consume the blocks and other sub-elements |
- //of this cluster, until we discover the boundary. |
- |
- long long total, avail; |
- |
- long status = m_pReader->Length(&total, &avail); |
- |
- if (status < 0) //error |
- return status; |
- |
- assert((total < 0) || (avail <= total)); |
- |
- const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; |
- |
- long long element_size = -1; |
- |
- for (;;) { //determine cluster size |
- if ((total >= 0) && (pos >= total)) |
- { |
- element_size = total - element_start; |
- assert(element_size > 0); |
- |
- break; |
- } |
- |
- if ((segment_stop >= 0) && (pos >= segment_stop)) |
- { |
- element_size = segment_stop - element_start; |
- assert(element_size > 0); |
- |
- break; |
- } |
- |
- //Read ID |
- |
- if ((pos + 1) > avail) |
- { |
- len = 1; |
- return E_BUFFER_NOT_FULL; |
- } |
- |
- long long result = GetUIntLength(m_pReader, pos, len); |
- |
- if (result < 0) //error |
- return static_cast<long>(result); |
- |
- if (result > 0) //weird |
- return E_BUFFER_NOT_FULL; |
- |
- if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
- return E_FILE_FORMAT_INVALID; |
- |
- if ((pos + len) > avail) |
- return E_BUFFER_NOT_FULL; |
- |
- const long long idpos = pos; |
- const long long id = ReadUInt(m_pReader, idpos, len); |
- |
- if (id < 0) //error (or underflow) |
- return static_cast<long>(id); |
- |
- //This is the distinguished set of ID's we use to determine |
- //that we have exhausted the sub-element's inside the cluster |
- //whose ID we parsed earlier. |
- |
- if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { //Cluster ID or Cues ID |
- element_size = pos - element_start; |
- assert(element_size > 0); |
- |
- break; |
- } |
- |
-#ifdef _DEBUG |
- switch (id) |
- { |
- case 0x20: //BlockGroup |
- case 0x23: //Simple Block |
- case 0x67: //TimeCode |
- case 0x2B: //PrevSize |
- break; |
- |
- default: |
- assert(false); |
- break; |
- } |
-#endif |
- |
- pos += len; //consume ID (of sub-element) |
- |
- //Read Size |
- |
- if ((pos + 1) > avail) |
- { |
- len = 1; |
- return E_BUFFER_NOT_FULL; |
- } |
- |
- result = GetUIntLength(m_pReader, pos, len); |
- |
- if (result < 0) //error |
- return static_cast<long>(result); |
- |
- if (result > 0) //weird |
- return E_BUFFER_NOT_FULL; |
- |
- if ((segment_stop >= 0) && ((pos + len) > segment_stop)) |
- return E_FILE_FORMAT_INVALID; |
- |
- if ((pos + len) > avail) |
- 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 size field of element |
- |
- //pos now points to start of sub-element's payload |
- |
- if (size == 0) //weird |
- continue; |
- |
- const long long unknown_size = (1LL << (7 * len)) - 1; |
- |
- if (size == unknown_size) |
- return E_FILE_FORMAT_INVALID; //not allowed for sub-elements |
- |
- if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird |
- return E_FILE_FORMAT_INVALID; |
- |
- pos += size; //consume payload of sub-element |
- assert((segment_stop < 0) || (pos <= segment_stop)); |
- } //determine cluster size |
- |
- assert(element_size >= 0); |
- |
- m_pos = element_start + element_size; |
- m_pUnknownSize = 0; |
- |
- return 2; //continue parsing |
-#else |
const long status = m_pUnknownSize->Parse(pos, len); |
if (status < 0) // error or underflow |
@@ -1522,7 +1234,6 @@ long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) { |
m_pUnknownSize = 0; |
return 2; // continue parsing |
-#endif |
} |
void Segment::AppendCluster(Cluster* pCluster) { |
@@ -1540,7 +1251,7 @@ void Segment::AppendCluster(Cluster* pCluster) { |
if (count >= size) { |
const long n = (size <= 0) ? 2048 : 2 * size; |
- Cluster** const qq = new Cluster* [n]; |
+ Cluster** const qq = new Cluster*[n]; |
Cluster** q = qq; |
Cluster** p = m_clusters; |
@@ -1594,7 +1305,7 @@ void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) { |
if (count >= size) { |
const long n = (size <= 0) ? 2048 : 2 * size; |
- Cluster** const qq = new Cluster* [n]; |
+ Cluster** const qq = new Cluster*[n]; |
Cluster** q = qq; |
Cluster** p = m_clusters; |
@@ -1794,55 +1505,6 @@ const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const { |
return m_void_elements + idx; |
} |
-#if 0 |
-void Segment::ParseCues(long long off) |
-{ |
- if (m_pCues) |
- return; |
- |
- //odbgstream os; |
- //os << "Segment::ParseCues (begin)" << endl; |
- |
- long long pos = m_start + off; |
- const long long element_start = pos; |
- const long long stop = m_start + m_size; |
- |
- long len; |
- |
- long long result = GetUIntLength(m_pReader, pos, len); |
- assert(result == 0); |
- assert((pos + len) <= stop); |
- |
- const long long idpos = pos; |
- |
- const long long id = ReadUInt(m_pReader, idpos, len); |
- assert(id == 0x0C53BB6B); //Cues ID |
- |
- pos += len; //consume ID |
- assert(pos < stop); |
- |
- //Read Size |
- |
- result = GetUIntLength(m_pReader, pos, len); |
- assert(result == 0); |
- assert((pos + len) <= stop); |
- |
- const long long size = ReadUInt(m_pReader, pos, len); |
- assert(size >= 0); |
- |
- pos += len; //consume length of size of element |
- assert((pos + size) <= stop); |
- |
- const long long element_size = size + pos - element_start; |
- |
- //Pos now points to start of payload |
- |
- m_pCues = new Cues(this, pos, size, element_start, element_size); |
- assert(m_pCues); //TODO |
- |
- //os << "Segment::ParseCues (end)" << endl; |
-} |
-#else |
long Segment::ParseCues(long long off, long long& pos, long& len) { |
if (m_pCues) |
return 0; // success |
@@ -1957,67 +1619,7 @@ long Segment::ParseCues(long long off, long long& pos, long& len) { |
return 0; // success |
} |
-#endif |
- |
-#if 0 |
-void Segment::ParseSeekEntry( |
- long long start, |
- long long size_) |
-{ |
- long long pos = start; |
- |
- const long long stop = start + size_; |
- |
- long len; |
- |
- const long long seekIdId = ReadUInt(m_pReader, pos, len); |
- //seekIdId; |
- assert(seekIdId == 0x13AB); //SeekID ID |
- assert((pos + len) <= stop); |
- pos += len; //consume id |
- |
- const long long seekIdSize = ReadUInt(m_pReader, pos, len); |
- assert(seekIdSize >= 0); |
- assert((pos + len) <= stop); |
- |
- pos += len; //consume size |
- |
- const long long seekId = ReadUInt(m_pReader, pos, len); //payload |
- assert(seekId >= 0); |
- assert(len == seekIdSize); |
- assert((pos + len) <= stop); |
- |
- pos += seekIdSize; //consume payload |
- |
- const long long seekPosId = ReadUInt(m_pReader, pos, len); |
- //seekPosId; |
- assert(seekPosId == 0x13AC); //SeekPos ID |
- assert((pos + len) <= stop); |
- |
- pos += len; //consume id |
- |
- const long long seekPosSize = ReadUInt(m_pReader, pos, len); |
- assert(seekPosSize >= 0); |
- assert((pos + len) <= stop); |
- |
- pos += len; //consume size |
- assert((pos + seekPosSize) <= stop); |
- |
- const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize); |
- assert(seekOff >= 0); |
- assert(seekOff < m_size); |
- |
- pos += seekPosSize; //consume payload |
- assert(pos == stop); |
- |
- const long long seekPos = m_start + seekOff; |
- assert(seekPos < (m_start + m_size)); |
- |
- if (seekId == 0x0C53BB6B) //Cues ID |
- ParseCues(seekOff); |
-} |
-#else |
bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, |
Entry* pEntry) { |
if (size_ <= 0) |
@@ -2110,7 +1712,6 @@ bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_, |
return true; |
} |
-#endif |
Cues::Cues(Segment* pSegment, long long start_, long long size_, |
long long element_start, long long element_size) |
@@ -2152,9 +1753,9 @@ bool Cues::DoneParsing() const { |
return (m_pos >= stop); |
} |
-void Cues::Init() const { |
+bool Cues::Init() const { |
if (m_cue_points) |
- return; |
+ return true; |
assert(m_count == 0); |
assert(m_preload_count == 0); |
@@ -2172,24 +1773,28 @@ void Cues::Init() const { |
long len; |
const long long id = ReadUInt(pReader, pos, len); |
- assert(id >= 0); // TODO |
- assert((pos + len) <= stop); |
+ if (id < 0 || (pos + len) > stop) { |
+ return false; |
+ } |
pos += len; // consume ID |
const long long size = ReadUInt(pReader, pos, len); |
- assert(size >= 0); |
- assert((pos + len) <= stop); |
+ if (size < 0 || (pos + len > stop)) { |
+ return false; |
+ } |
pos += len; // consume Size field |
- assert((pos + size) <= stop); |
+ if (pos + size > stop) { |
+ return false; |
+ } |
if (id == 0x3B) // CuePoint ID |
PreloadCuePoint(cue_points_size, idpos); |
- pos += size; // consume payload |
- assert(pos <= stop); |
+ pos += size; // skip payload |
} |
+ return true; |
} |
void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { |
@@ -2198,7 +1803,7 @@ void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const { |
if (m_preload_count >= cue_points_size) { |
const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size; |
- CuePoint** const qq = new CuePoint* [n]; |
+ CuePoint** const qq = new CuePoint*[n]; |
CuePoint** q = qq; // beginning of target |
CuePoint** p = m_cue_points; // beginning of source |
@@ -2226,7 +1831,10 @@ bool Cues::LoadCuePoint() const { |
if (m_pos >= stop) |
return false; // nothing else to do |
- Init(); |
+ if (!Init()) { |
+ m_pos = stop; |
+ return false; |
+ } |
IMkvReader* const pReader = m_pSegment->m_pReader; |
@@ -2263,7 +1871,10 @@ bool Cues::LoadCuePoint() const { |
if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)) |
return false; |
- pCP->Load(pReader); |
+ if (!pCP->Load(pReader)) { |
+ m_pos = stop; |
+ return false; |
+ } |
++m_count; |
--m_preload_count; |
@@ -2282,62 +1893,6 @@ bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP, |
assert(time_ns >= 0); |
assert(pTrack); |
-#if 0 |
- LoadCuePoint(); //establish invariant |
- |
- assert(m_cue_points); |
- assert(m_count > 0); |
- |
- CuePoint** const ii = m_cue_points; |
- CuePoint** i = ii; |
- |
- CuePoint** const jj = ii + m_count + m_preload_count; |
- CuePoint** j = jj; |
- |
- pCP = *i; |
- assert(pCP); |
- |
- if (time_ns <= pCP->GetTime(m_pSegment)) |
- { |
- pTP = pCP->Find(pTrack); |
- return (pTP != NULL); |
- } |
- |
- IMkvReader* const pReader = m_pSegment->m_pReader; |
- |
- while (i < j) |
- { |
- //INVARIANT: |
- //[ii, i) <= time_ns |
- //[i, j) ? |
- //[j, jj) > time_ns |
- |
- CuePoint** const k = i + (j - i) / 2; |
- assert(k < jj); |
- |
- CuePoint* const pCP = *k; |
- assert(pCP); |
- |
- pCP->Load(pReader); |
- |
- const long long t = pCP->GetTime(m_pSegment); |
- |
- if (t <= time_ns) |
- i = k + 1; |
- else |
- j = k; |
- |
- assert(i <= j); |
- } |
- |
- assert(i == j); |
- assert(i <= jj); |
- assert(i > ii); |
- |
- pCP = *--i; |
- assert(pCP); |
- assert(pCP->GetTime(m_pSegment) <= time_ns); |
-#else |
if (m_cue_points == NULL) |
return false; |
@@ -2387,7 +1942,6 @@ bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP, |
pCP = *--i; |
assert(pCP); |
assert(pCP->GetTime(m_pSegment) <= time_ns); |
-#endif |
// TODO: here and elsewhere, it's probably not correct to search |
// for the cue point with this time, and then search for a matching |
@@ -2401,65 +1955,6 @@ bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP, |
return (pTP != NULL); |
} |
-#if 0 |
-bool Cues::FindNext( |
- long long time_ns, |
- const Track* pTrack, |
- const CuePoint*& pCP, |
- const CuePoint::TrackPosition*& pTP) const |
-{ |
- pCP = 0; |
- pTP = 0; |
- |
- if (m_count == 0) |
- return false; |
- |
- assert(m_cue_points); |
- |
- const CuePoint* const* const ii = m_cue_points; |
- const CuePoint* const* i = ii; |
- |
- const CuePoint* const* const jj = ii + m_count; |
- const CuePoint* const* j = jj; |
- |
- while (i < j) |
- { |
- //INVARIANT: |
- //[ii, i) <= time_ns |
- //[i, j) ? |
- //[j, jj) > time_ns |
- |
- const CuePoint* const* const k = i + (j - i) / 2; |
- assert(k < jj); |
- |
- pCP = *k; |
- assert(pCP); |
- |
- const long long t = pCP->GetTime(m_pSegment); |
- |
- if (t <= time_ns) |
- i = k + 1; |
- else |
- j = k; |
- |
- assert(i <= j); |
- } |
- |
- assert(i == j); |
- assert(i <= jj); |
- |
- if (i >= jj) //time_ns is greater than max cue point |
- return false; |
- |
- pCP = *i; |
- assert(pCP); |
- assert(pCP->GetTime(m_pSegment) > time_ns); |
- |
- pTP = pCP->Find(pTrack); |
- return (pTP != NULL); |
-} |
-#endif |
- |
const CuePoint* Cues::GetFirst() const { |
if (m_cue_points == NULL) |
return NULL; |
@@ -2467,15 +1962,6 @@ const CuePoint* Cues::GetFirst() const { |
if (m_count == 0) |
return NULL; |
-#if 0 |
- LoadCuePoint(); //init cues |
- |
- const size_t count = m_count + m_preload_count; |
- |
- if (count == 0) //weird |
- return NULL; |
-#endif |
- |
CuePoint* const* const pp = m_cue_points; |
assert(pp); |
@@ -2493,34 +1979,14 @@ const CuePoint* Cues::GetLast() const { |
if (m_count <= 0) |
return NULL; |
-#if 0 |
- LoadCuePoint(); //init cues |
- |
- const size_t count = m_count + m_preload_count; |
+ const long index = m_count - 1; |
- if (count == 0) //weird |
- return NULL; |
- |
- const size_t index = count - 1; |
- |
- CuePoint* const* const pp = m_cue_points; |
- assert(pp); |
- |
- CuePoint* const pCP = pp[index]; |
- assert(pCP); |
- |
- pCP->Load(m_pSegment->m_pReader); |
- assert(pCP->GetTimeCode() >= 0); |
-#else |
- const long index = m_count - 1; |
- |
- CuePoint* const* const pp = m_cue_points; |
- assert(pp); |
+ CuePoint* const* const pp = m_cue_points; |
+ assert(pp); |
CuePoint* const pCP = pp[index]; |
assert(pCP); |
assert(pCP->GetTimeCode() >= 0); |
-#endif |
return pCP; |
} |
@@ -2533,26 +1999,6 @@ const CuePoint* Cues::GetNext(const CuePoint* pCurr) const { |
assert(m_cue_points); |
assert(m_count >= 1); |
-#if 0 |
- const size_t count = m_count + m_preload_count; |
- |
- size_t index = pCurr->m_index; |
- assert(index < count); |
- |
- CuePoint* const* const pp = m_cue_points; |
- assert(pp); |
- assert(pp[index] == pCurr); |
- |
- ++index; |
- |
- if (index >= count) |
- return NULL; |
- |
- CuePoint* const pNext = pp[index]; |
- assert(pNext); |
- |
- pNext->Load(m_pSegment->m_pReader); |
-#else |
long index = pCurr->m_index; |
assert(index < m_count); |
@@ -2568,7 +2014,6 @@ const CuePoint* Cues::GetNext(const CuePoint* pCurr) const { |
CuePoint* const pNext = pp[index]; |
assert(pNext); |
assert(pNext->GetTimeCode() >= 0); |
-#endif |
return pNext; |
} |
@@ -2705,12 +2150,12 @@ CuePoint::CuePoint(long idx, long long pos) |
CuePoint::~CuePoint() { delete[] m_track_positions; } |
-void CuePoint::Load(IMkvReader* pReader) { |
+bool CuePoint::Load(IMkvReader* pReader) { |
// odbgstream os; |
// os << "CuePoint::Load(begin): timecode=" << m_timecode << endl; |
if (m_timecode >= 0) // already loaded |
- return; |
+ return true; |
assert(m_track_positions == NULL); |
assert(m_track_positions_count == 0); |
@@ -2726,7 +2171,7 @@ void CuePoint::Load(IMkvReader* pReader) { |
const long long id = ReadUInt(pReader, pos_, len); |
assert(id == 0x3B); // CuePoint ID |
if (id != 0x3B) |
- return; |
+ return false; |
pos_ += len; // consume ID |
@@ -2749,17 +2194,21 @@ void CuePoint::Load(IMkvReader* pReader) { |
long len; |
const long long id = ReadUInt(pReader, pos, len); |
- assert(id >= 0); // TODO |
- assert((pos + len) <= stop); |
+ if ((id < 0) || (pos + len > stop)) { |
+ return false; |
+ } |
pos += len; // consume ID |
const long long size = ReadUInt(pReader, pos, len); |
- assert(size >= 0); |
- assert((pos + len) <= stop); |
+ if ((size < 0) || (pos + len > stop)) { |
+ return false; |
+ } |
pos += len; // consume Size field |
- assert((pos + size) <= stop); |
+ if ((pos + size) > stop) { |
+ return false; |
+ } |
if (id == 0x33) // CueTime ID |
m_timecode = UnserializeUInt(pReader, pos, size); |
@@ -2768,11 +2217,11 @@ void CuePoint::Load(IMkvReader* pReader) { |
++m_track_positions_count; |
pos += size; // consume payload |
- assert(pos <= stop); |
} |
- assert(m_timecode >= 0); |
- assert(m_track_positions_count > 0); |
+ if (m_timecode < 0 || m_track_positions_count <= 0) { |
+ return false; |
+ } |
// os << "CuePoint::Load(cont'd): idpos=" << idpos |
// << " timecode=" << m_timecode |
@@ -2789,7 +2238,7 @@ void CuePoint::Load(IMkvReader* pReader) { |
long len; |
const long long id = ReadUInt(pReader, pos, len); |
- assert(id >= 0); // TODO |
+ assert(id >= 0); |
assert((pos + len) <= stop); |
pos += len; // consume ID |
@@ -2803,7 +2252,9 @@ void CuePoint::Load(IMkvReader* pReader) { |
if (id == 0x37) { // CueTrackPosition(s) ID |
TrackPosition& tp = *p++; |
- tp.Parse(pReader, pos, size); |
+ if (!tp.Parse(pReader, pos, size)) { |
+ return false; |
+ } |
} |
pos += size; // consume payload |
@@ -2814,9 +2265,11 @@ void CuePoint::Load(IMkvReader* pReader) { |
m_element_start = element_start; |
m_element_size = element_size; |
+ |
+ return true; |
} |
-void CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, |
+bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, |
long long size_) { |
const long long stop = start_ + size_; |
long long pos = start_; |
@@ -2829,17 +2282,21 @@ void CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, |
long len; |
const long long id = ReadUInt(pReader, pos, len); |
- assert(id >= 0); // TODO |
- assert((pos + len) <= stop); |
+ if ((id < 0) || ((pos + len) > stop)) { |
+ return false; |
+ } |
pos += len; // consume ID |
const long long size = ReadUInt(pReader, pos, len); |
- assert(size >= 0); |
- assert((pos + len) <= stop); |
+ if ((size < 0) || ((pos + len) > stop)) { |
+ return false; |
+ } |
pos += len; // consume Size field |
- assert((pos + size) <= stop); |
+ if ((pos + size) > stop) { |
+ return false; |
+ } |
if (id == 0x77) // CueTrack ID |
m_track = UnserializeUInt(pReader, pos, size); |
@@ -2851,12 +2308,13 @@ void CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_, |
m_block = UnserializeUInt(pReader, pos, size); |
pos += size; // consume payload |
- assert(pos <= stop); |
} |
- assert(m_pos >= 0); |
- assert(m_track > 0); |
- // assert(m_block > 0); |
+ if ((m_pos < 0) || (m_track <= 0)) { |
+ return false; |
+ } |
+ |
+ return true; |
} |
const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const { |
@@ -2894,20 +2352,6 @@ long long CuePoint::GetTime(const Segment* pSegment) const { |
return time; |
} |
-#if 0 |
-long long Segment::Unparsed() const |
-{ |
- if (m_size < 0) |
- return LLONG_MAX; |
- |
- const long long stop = m_start + m_size; |
- |
- const long long result = stop - m_pos; |
- assert(result >= 0); |
- |
- return result; |
-} |
-#else |
bool Segment::DoneParsing() const { |
if (m_size < 0) { |
long long total, avail; |
@@ -2927,7 +2371,6 @@ bool Segment::DoneParsing() const { |
return (m_pos >= stop); |
} |
-#endif |
const Cluster* Segment::GetFirst() const { |
if ((m_clusters == NULL) || (m_clusterCount <= 0)) |
@@ -3395,15 +2838,7 @@ long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) { |
continue; |
} |
-#if 0 // this is commented-out to support incremental cluster parsing |
- len = static_cast<long>(size); |
- |
- if (element_stop > avail) |
- return E_BUFFER_NOT_FULL; |
-#endif |
- |
// We have a cluster. |
- |
off_next = idoff; |
if (size != unknown_size) |
@@ -3647,188 +3082,11 @@ const Cluster* Segment::FindCluster(long long time_ns) const { |
return pCluster; |
} |
-#if 0 |
-const BlockEntry* Segment::Seek( |
- long long time_ns, |
- const Track* pTrack) const |
-{ |
- assert(pTrack); |
- |
- if ((m_clusters == NULL) || (m_clusterCount <= 0)) |
- return pTrack->GetEOS(); |
- |
- Cluster** const i = m_clusters; |
- assert(i); |
- |
- { |
- Cluster* const pCluster = *i; |
- assert(pCluster); |
- assert(pCluster->m_index == 0); //m_clusterCount > 0 |
- assert(pCluster->m_pSegment == this); |
- |
- if (time_ns <= pCluster->GetTime()) |
- return pCluster->GetEntry(pTrack); |
- } |
- |
- Cluster** const j = i + m_clusterCount; |
- |
- if (pTrack->GetType() == 2) { //audio |
- //TODO: we could decide to use cues for this, as we do for video. |
- //But we only use it for video because looking around for a keyframe |
- //can get expensive. Audio doesn't require anything special so a |
- //straight cluster search is good enough (we assume). |
- |
- 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); |
- |
- Cluster* const pCluster = *mid; |
- assert(pCluster); |
- assert(pCluster->m_index == long(mid - m_clusters)); |
- assert(pCluster->m_pSegment == this); |
- |
- 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) |
- { |
- Cluster* const pCluster = *--lo; |
- assert(pCluster); |
- assert(pCluster->GetTime() <= time_ns); |
- |
- const BlockEntry* const pBE = pCluster->GetEntry(pTrack); |
- |
- if ((pBE != 0) && !pBE->EOS()) |
- return pBE; |
- |
- //landed on empty cluster (no entries) |
- } |
- |
- return pTrack->GetEOS(); //weird |
- } |
- |
- assert(pTrack->GetType() == 1); //video |
- |
- 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); |
- |
- Cluster* const pCluster = *mid; |
- assert(pCluster); |
- |
- 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); |
- |
- Cluster* pCluster = *--lo; |
- assert(pCluster); |
- assert(pCluster->GetTime() <= time_ns); |
- |
- { |
- const BlockEntry* const pBE = pCluster->GetEntry(pTrack, time_ns); |
- |
- if ((pBE != 0) && !pBE->EOS()) //found a keyframe |
- return pBE; |
- } |
- |
- const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack); |
- |
- while (lo != i) |
- { |
- pCluster = *--lo; |
- assert(pCluster); |
- assert(pCluster->GetTime() <= time_ns); |
- |
- const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo); |
- |
- if ((pBlockEntry != 0) && !pBlockEntry->EOS()) |
- return pBlockEntry; |
- } |
- |
- //weird: we're on the first cluster, but no keyframe found |
- //should never happen but we must return something anyway |
- |
- return pTrack->GetEOS(); |
-} |
-#endif |
- |
-#if 0 |
-bool Segment::SearchCues( |
- long long time_ns, |
- Track* pTrack, |
- Cluster*& pCluster, |
- const BlockEntry*& pBlockEntry, |
- const CuePoint*& pCP, |
- const CuePoint::TrackPosition*& pTP) |
-{ |
- if (pTrack->GetType() != 1) //not video |
- return false; //TODO: for now, just handle video stream |
- |
- if (m_pCues == NULL) |
- return false; |
- |
- if (!m_pCues->Find(time_ns, pTrack, pCP, pTP)) |
- return false; //weird |
- |
- assert(pCP); |
- assert(pTP); |
- assert(pTP->m_track == pTrack->GetNumber()); |
- |
- //We have the cue point and track position we want, |
- //so we now need to search for the cluster having |
- //the indicated position. |
- |
- return GetCluster(pCP, pTP, pCluster, pBlockEntry); |
-} |
-#endif |
- |
const Tracks* Segment::GetTracks() const { return m_pTracks; } |
- |
const SegmentInfo* Segment::GetInfo() const { return m_pInfo; } |
- |
const Cues* Segment::GetCues() const { return m_pCues; } |
- |
const Chapters* Segment::GetChapters() const { return m_pChapters; } |
- |
+const Tags* Segment::GetTags() const { return m_pTags; } |
const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; } |
long long Segment::GetDuration() const { |
@@ -3853,6 +3111,7 @@ Chapters::~Chapters() { |
Edition& e = m_editions[--m_editions_count]; |
e.Clear(); |
} |
+ delete[] m_editions; |
} |
long Chapters::Parse() { |
@@ -4128,12 +3387,13 @@ long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) { |
if (status < 0) // error |
return status; |
} else if (id == 0x33C4) { // UID ID |
- const long long val = UnserializeUInt(pReader, pos, size); |
+ long long val; |
+ status = UnserializeInt(pReader, pos, size, val); |
- if (val < 0) // error |
- return static_cast<long>(val); |
+ if (status < 0) // error |
+ return status; |
- m_uid = val; |
+ m_uid = static_cast<unsigned long long>(val); |
} else if (id == 0x11) { // TimeStart ID |
const long long val = UnserializeUInt(pReader, pos, size); |
@@ -4181,79 +3441,351 @@ long long Chapters::Atom::GetTime(const Chapters* pChapters, |
if (timecode < 0) |
return -1; |
- const long long result = timecode_scale * timecode; |
+ const long long result = timecode_scale * timecode; |
+ |
+ return result; |
+} |
+ |
+long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos, |
+ long long size) { |
+ if (!ExpandDisplaysArray()) |
+ return -1; |
+ |
+ Display& d = m_displays[m_displays_count++]; |
+ d.Init(); |
+ |
+ return d.Parse(pReader, pos, size); |
+} |
+ |
+bool Chapters::Atom::ExpandDisplaysArray() { |
+ if (m_displays_size > m_displays_count) |
+ return true; // nothing else to do |
+ |
+ const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size; |
+ |
+ Display* const displays = new (std::nothrow) Display[size]; |
+ |
+ if (displays == NULL) |
+ return false; |
+ |
+ for (int idx = 0; idx < m_displays_count; ++idx) { |
+ m_displays[idx].ShallowCopy(displays[idx]); |
+ } |
+ |
+ delete[] m_displays; |
+ m_displays = displays; |
+ |
+ m_displays_size = size; |
+ return true; |
+} |
+ |
+Chapters::Display::Display() {} |
+ |
+Chapters::Display::~Display() {} |
+ |
+const char* Chapters::Display::GetString() const { return m_string; } |
+ |
+const char* Chapters::Display::GetLanguage() const { return m_language; } |
+ |
+const char* Chapters::Display::GetCountry() const { return m_country; } |
+ |
+void Chapters::Display::Init() { |
+ m_string = NULL; |
+ m_language = NULL; |
+ m_country = NULL; |
+} |
+ |
+void Chapters::Display::ShallowCopy(Display& rhs) const { |
+ rhs.m_string = m_string; |
+ rhs.m_language = m_language; |
+ rhs.m_country = m_country; |
+} |
+ |
+void Chapters::Display::Clear() { |
+ delete[] m_string; |
+ m_string = NULL; |
+ |
+ delete[] m_language; |
+ m_language = NULL; |
+ |
+ delete[] m_country; |
+ m_country = NULL; |
+} |
+ |
+long Chapters::Display::Parse(IMkvReader* pReader, long long pos, |
+ long long size) { |
+ const long long stop = pos + size; |
+ |
+ while (pos < stop) { |
+ long long id, size; |
+ |
+ long status = ParseElementHeader(pReader, pos, stop, id, size); |
+ |
+ if (status < 0) // error |
+ return status; |
+ |
+ if (size == 0) // weird |
+ continue; |
+ |
+ if (id == 0x05) { // ChapterString ID |
+ status = UnserializeString(pReader, pos, size, m_string); |
+ |
+ if (status) |
+ return status; |
+ } else if (id == 0x037C) { // ChapterLanguage ID |
+ status = UnserializeString(pReader, pos, size, m_language); |
+ |
+ if (status) |
+ return status; |
+ } else if (id == 0x037E) { // ChapterCountry ID |
+ status = UnserializeString(pReader, pos, size, m_country); |
+ |
+ if (status) |
+ return status; |
+ } |
+ |
+ pos += size; |
+ assert(pos <= stop); |
+ } |
+ |
+ assert(pos == stop); |
+ return 0; |
+} |
+ |
+Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size, |
+ long long element_start, long long element_size) |
+ : m_pSegment(pSegment), |
+ m_start(payload_start), |
+ m_size(payload_size), |
+ m_element_start(element_start), |
+ m_element_size(element_size), |
+ m_tags(NULL), |
+ m_tags_size(0), |
+ m_tags_count(0) {} |
+ |
+Tags::~Tags() { |
+ while (m_tags_count > 0) { |
+ Tag& t = m_tags[--m_tags_count]; |
+ t.Clear(); |
+ } |
+ delete[] m_tags; |
+} |
+ |
+long Tags::Parse() { |
+ IMkvReader* const pReader = m_pSegment->m_pReader; |
+ |
+ long long pos = m_start; // payload start |
+ const long long stop = pos + m_size; // payload stop |
+ |
+ while (pos < stop) { |
+ long long id, size; |
+ |
+ long status = ParseElementHeader(pReader, pos, stop, id, size); |
+ |
+ if (status < 0) |
+ return status; |
+ |
+ if (size == 0) // 0 length tag, read another |
+ continue; |
+ |
+ if (id == 0x3373) { // Tag ID |
+ status = ParseTag(pos, size); |
+ |
+ if (status < 0) |
+ return status; |
+ } |
+ |
+ pos += size; |
+ assert(pos <= stop); |
+ if (pos > stop) |
+ return -1; |
+ } |
+ |
+ assert(pos == stop); |
+ if (pos != stop) |
+ return -1; |
+ |
+ return 0; |
+} |
+ |
+int Tags::GetTagCount() const { return m_tags_count; } |
+ |
+const Tags::Tag* Tags::GetTag(int idx) const { |
+ if (idx < 0) |
+ return NULL; |
+ |
+ if (idx >= m_tags_count) |
+ return NULL; |
+ |
+ return m_tags + idx; |
+} |
+ |
+bool Tags::ExpandTagsArray() { |
+ if (m_tags_size > m_tags_count) |
+ return true; // nothing else to do |
+ |
+ const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size; |
+ |
+ Tag* const tags = new (std::nothrow) Tag[size]; |
+ |
+ if (tags == NULL) |
+ return false; |
+ |
+ for (int idx = 0; idx < m_tags_count; ++idx) { |
+ m_tags[idx].ShallowCopy(tags[idx]); |
+ } |
+ |
+ delete[] m_tags; |
+ m_tags = tags; |
+ |
+ m_tags_size = size; |
+ return true; |
+} |
+ |
+long Tags::ParseTag(long long pos, long long size) { |
+ if (!ExpandTagsArray()) |
+ return -1; |
+ |
+ Tag& t = m_tags[m_tags_count++]; |
+ t.Init(); |
+ |
+ return t.Parse(m_pSegment->m_pReader, pos, size); |
+} |
+ |
+Tags::Tag::Tag() {} |
+ |
+Tags::Tag::~Tag() {} |
+ |
+int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; } |
+ |
+const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const { |
+ if (index < 0) |
+ return NULL; |
+ |
+ if (index >= m_simple_tags_count) |
+ return NULL; |
+ |
+ return m_simple_tags + index; |
+} |
+ |
+void Tags::Tag::Init() { |
+ m_simple_tags = NULL; |
+ m_simple_tags_size = 0; |
+ m_simple_tags_count = 0; |
+} |
+ |
+void Tags::Tag::ShallowCopy(Tag& rhs) const { |
+ rhs.m_simple_tags = m_simple_tags; |
+ rhs.m_simple_tags_size = m_simple_tags_size; |
+ rhs.m_simple_tags_count = m_simple_tags_count; |
+} |
+ |
+void Tags::Tag::Clear() { |
+ while (m_simple_tags_count > 0) { |
+ SimpleTag& d = m_simple_tags[--m_simple_tags_count]; |
+ d.Clear(); |
+ } |
+ |
+ delete[] m_simple_tags; |
+ m_simple_tags = NULL; |
+ |
+ m_simple_tags_size = 0; |
+} |
+ |
+long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) { |
+ const long long stop = pos + size; |
+ |
+ while (pos < stop) { |
+ long long id, size; |
+ |
+ long status = ParseElementHeader(pReader, pos, stop, id, size); |
+ |
+ if (status < 0) |
+ return status; |
+ |
+ if (size == 0) // 0 length tag, read another |
+ continue; |
+ |
+ if (id == 0x27C8) { // SimpleTag ID |
+ status = ParseSimpleTag(pReader, pos, size); |
+ |
+ if (status < 0) |
+ return status; |
+ } |
+ |
+ pos += size; |
+ assert(pos <= stop); |
+ if (pos > stop) |
+ return -1; |
+ } |
- return result; |
+ assert(pos == stop); |
+ if (pos != stop) |
+ return -1; |
+ return 0; |
} |
-long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos, |
- long long size) { |
- if (!ExpandDisplaysArray()) |
+long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos, |
+ long long size) { |
+ if (!ExpandSimpleTagsArray()) |
return -1; |
- Display& d = m_displays[m_displays_count++]; |
- d.Init(); |
+ SimpleTag& st = m_simple_tags[m_simple_tags_count++]; |
+ st.Init(); |
- return d.Parse(pReader, pos, size); |
+ return st.Parse(pReader, pos, size); |
} |
-bool Chapters::Atom::ExpandDisplaysArray() { |
- if (m_displays_size > m_displays_count) |
+bool Tags::Tag::ExpandSimpleTagsArray() { |
+ if (m_simple_tags_size > m_simple_tags_count) |
return true; // nothing else to do |
- const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size; |
+ const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size; |
- Display* const displays = new (std::nothrow) Display[size]; |
+ SimpleTag* const displays = new (std::nothrow) SimpleTag[size]; |
if (displays == NULL) |
return false; |
- for (int idx = 0; idx < m_displays_count; ++idx) { |
- m_displays[idx].ShallowCopy(displays[idx]); |
+ for (int idx = 0; idx < m_simple_tags_count; ++idx) { |
+ m_simple_tags[idx].ShallowCopy(displays[idx]); |
} |
- delete[] m_displays; |
- m_displays = displays; |
+ delete[] m_simple_tags; |
+ m_simple_tags = displays; |
- m_displays_size = size; |
+ m_simple_tags_size = size; |
return true; |
} |
-Chapters::Display::Display() {} |
- |
-Chapters::Display::~Display() {} |
+Tags::SimpleTag::SimpleTag() {} |
-const char* Chapters::Display::GetString() const { return m_string; } |
+Tags::SimpleTag::~SimpleTag() {} |
-const char* Chapters::Display::GetLanguage() const { return m_language; } |
+const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; } |
-const char* Chapters::Display::GetCountry() const { return m_country; } |
+const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; } |
-void Chapters::Display::Init() { |
- m_string = NULL; |
- m_language = NULL; |
- m_country = NULL; |
+void Tags::SimpleTag::Init() { |
+ m_tag_name = NULL; |
+ m_tag_string = NULL; |
} |
-void Chapters::Display::ShallowCopy(Display& rhs) const { |
- rhs.m_string = m_string; |
- rhs.m_language = m_language; |
- rhs.m_country = m_country; |
+void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const { |
+ rhs.m_tag_name = m_tag_name; |
+ rhs.m_tag_string = m_tag_string; |
} |
-void Chapters::Display::Clear() { |
- delete[] m_string; |
- m_string = NULL; |
- |
- delete[] m_language; |
- m_language = NULL; |
+void Tags::SimpleTag::Clear() { |
+ delete[] m_tag_name; |
+ m_tag_name = NULL; |
- delete[] m_country; |
- m_country = NULL; |
+ delete[] m_tag_string; |
+ m_tag_string = NULL; |
} |
-long Chapters::Display::Parse(IMkvReader* pReader, long long pos, |
- long long size) { |
+long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos, |
+ long long size) { |
const long long stop = pos + size; |
while (pos < stop) { |
@@ -4267,18 +3799,13 @@ long Chapters::Display::Parse(IMkvReader* pReader, long long pos, |
if (size == 0) // weird |
continue; |
- if (id == 0x05) { // ChapterString ID |
- status = UnserializeString(pReader, pos, size, m_string); |
- |
- if (status) |
- return status; |
- } else if (id == 0x037C) { // ChapterLanguage ID |
- status = UnserializeString(pReader, pos, size, m_language); |
+ if (id == 0x5A3) { // TagName ID |
+ status = UnserializeString(pReader, pos, size, m_tag_name); |
if (status) |
return status; |
- } else if (id == 0x037E) { // ChapterCountry ID |
- status = UnserializeString(pReader, pos, size, m_country); |
+ } else if (id == 0x487) { // TagString ID |
+ status = UnserializeString(pReader, pos, size, m_tag_string); |
if (status) |
return status; |
@@ -4286,9 +3813,13 @@ long Chapters::Display::Parse(IMkvReader* pReader, long long pos, |
pos += size; |
assert(pos <= stop); |
+ if (pos > stop) |
+ return -1; |
} |
assert(pos == stop); |
+ if (pos != stop) |
+ return -1; |
return 0; |
} |
@@ -4458,7 +3989,7 @@ ContentEncoding::~ContentEncoding() { |
} |
const ContentEncoding::ContentCompression* |
-ContentEncoding::GetCompressionByIndex(unsigned long idx) const { |
+ ContentEncoding::GetCompressionByIndex(unsigned long idx) const { |
const ptrdiff_t count = compression_entries_end_ - compression_entries_; |
assert(count >= 0); |
@@ -4554,7 +4085,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, |
if (compression_count > 0) { |
compression_entries_ = |
- new (std::nothrow) ContentCompression* [compression_count]; |
+ new (std::nothrow) ContentCompression*[compression_count]; |
if (!compression_entries_) |
return -1; |
compression_entries_end_ = compression_entries_; |
@@ -4562,7 +4093,7 @@ long ContentEncoding::ParseContentEncodingEntry(long long start, long long size, |
if (encryption_count > 0) { |
encryption_entries_ = |
- new (std::nothrow) ContentEncryption* [encryption_count]; |
+ new (std::nothrow) ContentEncryption*[encryption_count]; |
if (!encryption_entries_) { |
delete[] compression_entries_; |
return -1; |
@@ -4703,7 +4234,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size, |
return E_FILE_FORMAT_INVALID; |
} else if (id == 0x7E2) { |
// ContentEncKeyID |
- delete[] encryption -> key_id; |
+ delete[] encryption->key_id; |
encryption->key_id = NULL; |
encryption->key_id_len = 0; |
@@ -4727,7 +4258,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size, |
encryption->key_id_len = buflen; |
} else if (id == 0x7E3) { |
// ContentSignature |
- delete[] encryption -> signature; |
+ delete[] encryption->signature; |
encryption->signature = NULL; |
encryption->signature_len = 0; |
@@ -4751,7 +4282,7 @@ long ContentEncoding::ParseEncryptionEntry(long long start, long long size, |
encryption->signature_len = buflen; |
} else if (id == 0x7E4) { |
// ContentSigKeyID |
- delete[] encryption -> sig_key_id; |
+ delete[] encryption->sig_key_id; |
encryption->sig_key_id = NULL; |
encryption->sig_key_id_len = 0; |
@@ -4991,17 +4522,10 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const { |
} |
if (pCluster->EOS()) { |
-#if 0 |
- if (m_pSegment->Unparsed() <= 0) { //all clusters have been loaded |
- pBlockEntry = GetEOS(); |
- return 1; |
- } |
-#else |
if (m_pSegment->DoneParsing()) { |
pBlockEntry = GetEOS(); |
return 1; |
} |
-#endif |
pBlockEntry = 0; |
return E_BUFFER_NOT_FULL; |
@@ -5098,18 +4622,10 @@ long Track::GetNext(const BlockEntry* pCurrEntry, |
} |
if (pCluster->EOS()) { |
-#if 0 |
- if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded |
- { |
- pNextEntry = GetEOS(); |
- return 1; |
- } |
-#else |
if (m_pSegment->DoneParsing()) { |
pNextEntry = GetEOS(); |
return 1; |
} |
-#endif |
// 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 |
@@ -5291,7 +4807,7 @@ long Track::ParseContentEncodingsEntry(long long start, long long size) { |
if (count <= 0) |
return -1; |
- content_encoding_entries_ = new (std::nothrow) ContentEncoding* [count]; |
+ content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count]; |
if (!content_encoding_entries_) |
return -1; |
@@ -5350,6 +4866,11 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, |
long long width = 0; |
long long height = 0; |
+ long long display_width = 0; |
+ long long display_height = 0; |
+ long long display_unit = 0; |
+ long long stereo_mode = 0; |
+ |
double rate = 0.0; |
IMkvReader* const pReader = pSegment->m_pReader; |
@@ -5381,6 +4902,26 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, |
if (height <= 0) |
return E_FILE_FORMAT_INVALID; |
+ } else if (id == 0x14B0) { // display width |
+ display_width = UnserializeUInt(pReader, pos, size); |
+ |
+ if (display_width <= 0) |
+ return E_FILE_FORMAT_INVALID; |
+ } else if (id == 0x14BA) { // display height |
+ display_height = UnserializeUInt(pReader, pos, size); |
+ |
+ if (display_height <= 0) |
+ return E_FILE_FORMAT_INVALID; |
+ } else if (id == 0x14B2) { // display unit |
+ display_unit = UnserializeUInt(pReader, pos, size); |
+ |
+ if (display_unit < 0) |
+ return E_FILE_FORMAT_INVALID; |
+ } else if (id == 0x13B8) { // stereo mode |
+ stereo_mode = UnserializeUInt(pReader, pos, size); |
+ |
+ if (stereo_mode < 0) |
+ return E_FILE_FORMAT_INVALID; |
} else if (id == 0x0383E3) { // frame rate |
const long status = UnserializeFloat(pReader, pos, size, rate); |
@@ -5412,6 +4953,10 @@ long VideoTrack::Parse(Segment* pSegment, const Info& info, |
pTrack->m_width = width; |
pTrack->m_height = height; |
+ pTrack->m_display_width = display_width; |
+ pTrack->m_display_height = display_height; |
+ pTrack->m_display_unit = display_unit; |
+ pTrack->m_stereo_mode = stereo_mode; |
pTrack->m_rate = rate; |
pResult = pTrack; |
@@ -5498,16 +5043,7 @@ long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const { |
assert(pCluster); |
assert(pCluster->GetTime() <= time_ns); |
-#if 0 |
- //TODO: |
- //We need to handle the case when a cluster |
- //contains multiple keyframes. Simply returning |
- //the largest keyframe on the cluster isn't |
- //good enough. |
- pResult = pCluster->GetMaxKey(this); |
-#else |
pResult = pCluster->GetEntry(this, time_ns); |
-#endif |
if ((pResult != 0) && !pResult->EOS()) |
return 0; |
@@ -5524,6 +5060,18 @@ long long VideoTrack::GetWidth() const { return m_width; } |
long long VideoTrack::GetHeight() const { return m_height; } |
+long long VideoTrack::GetDisplayWidth() const { |
+ return m_display_width > 0 ? m_display_width : GetWidth(); |
+} |
+ |
+long long VideoTrack::GetDisplayHeight() const { |
+ return m_display_height > 0 ? m_display_height : GetHeight(); |
+} |
+ |
+long long VideoTrack::GetDisplayUnit() const { return m_display_unit; } |
+ |
+long long VideoTrack::GetStereoMode() const { return m_stereo_mode; } |
+ |
double VideoTrack::GetFrameRate() const { return m_rate; } |
AudioTrack::AudioTrack(Segment* pSegment, long long element_start, |
@@ -5658,7 +5206,7 @@ long Tracks::Parse() { |
if (count <= 0) |
return 0; // success |
- m_trackEntries = new (std::nothrow) Track* [count]; |
+ m_trackEntries = new (std::nothrow) Track*[count]; |
if (m_trackEntries == NULL) |
return -1; |
@@ -5941,7 +5489,7 @@ long Tracks::ParseTrackEntry(long long track_start, long long track_size, |
if (v.start >= 0) |
return E_FILE_FORMAT_INVALID; |
- if (e.start >= 0) |
+ if (info.type == Track::kMetadata && e.start >= 0) |
return E_FILE_FORMAT_INVALID; |
info.settings.start = -1; |
@@ -6003,25 +5551,6 @@ const Track* Tracks::GetTrackByIndex(unsigned long idx) const { |
return m_trackEntries[idx]; |
} |
-#if 0 |
-long long Cluster::Unparsed() const |
-{ |
- if (m_timecode < 0) //not even partially loaded |
- return LLONG_MAX; |
- |
- assert(m_pos >= m_element_start); |
- //assert(m_element_size > m_size); |
- |
- const long long element_stop = m_element_start + m_element_size; |
- assert(m_pos <= element_stop); |
- |
- const long long result = element_stop - m_pos; |
- assert(result >= 0); |
- |
- return result; |
-} |
-#endif |
- |
long Cluster::Load(long long& pos, long& len) const { |
assert(m_pSegment); |
assert(m_pos >= m_element_start); |
@@ -6115,15 +5644,7 @@ long Cluster::Load(long long& pos, long& len) const { |
cluster_size = size; |
} |
-// pos points to start of payload |
- |
-#if 0 |
- len = static_cast<long>(size_); |
- |
- if (cluster_stop > avail) |
- return E_BUFFER_NOT_FULL; |
-#endif |
- |
+ // pos points to start of payload |
long long timecode = -1; |
long long new_pos = -1; |
bool bBlock = false; |
@@ -6495,36 +6016,6 @@ long Cluster::ParseSimpleBlock(long long block_size, long long& pos, |
if (track == 0) |
return E_FILE_FORMAT_INVALID; |
-#if 0 |
- //TODO(matthewjheaney) |
- //This turned out to be too conservative. The problem is that |
- //if we see a track header in the tracks element with an unsupported |
- //track type, we throw that track header away, so it is not present |
- //in the track map. But even though we don't understand the track |
- //header, there are still blocks in the cluster with that track |
- //number. It was our decision to ignore that track header, so it's |
- //up to us to deal with blocks associated with that track -- we |
- //cannot simply report an error since technically there's nothing |
- //wrong with the file. |
- // |
- //For now we go ahead and finish the parse, creating a block entry |
- //for this block. This is somewhat wasteful, because without a |
- //track header there's nothing you can do with the block. What |
- //we really need here is a special return value that indicates to |
- //the caller that he should ignore this particular block, and |
- //continue parsing. |
- |
- const Tracks* const pTracks = m_pSegment->GetTracks(); |
- assert(pTracks); |
- |
- const long tn = static_cast<long>(track); |
- |
- const Track* const pTrack = pTracks->GetTrackByNumber(tn); |
- |
- if (pTrack == NULL) |
- return E_FILE_FORMAT_INVALID; |
-#endif |
- |
pos += len; // consume track number |
if ((pos + 2) > block_stop) |
@@ -6679,12 +6170,7 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos, |
return E_FILE_FORMAT_INVALID; |
if (id == 0x35A2) { // DiscardPadding |
- result = GetUIntLength(pReader, pos, len); |
- |
- if (result < 0) // error |
- return static_cast<long>(result); |
- |
- status = UnserializeInt(pReader, pos, len, discard_padding); |
+ status = UnserializeInt(pReader, pos, size, discard_padding); |
if (status < 0) // error |
return status; |
@@ -6733,36 +6219,6 @@ long Cluster::ParseBlockGroup(long long payload_size, long long& pos, |
if (track == 0) |
return E_FILE_FORMAT_INVALID; |
-#if 0 |
- //TODO(matthewjheaney) |
- //This turned out to be too conservative. The problem is that |
- //if we see a track header in the tracks element with an unsupported |
- //track type, we throw that track header away, so it is not present |
- //in the track map. But even though we don't understand the track |
- //header, there are still blocks in the cluster with that track |
- //number. It was our decision to ignore that track header, so it's |
- //up to us to deal with blocks associated with that track -- we |
- //cannot simply report an error since technically there's nothing |
- //wrong with the file. |
- // |
- //For now we go ahead and finish the parse, creating a block entry |
- //for this block. This is somewhat wasteful, because without a |
- //track header there's nothing you can do with the block. What |
- //we really need here is a special return value that indicates to |
- //the caller that he should ignore this particular block, and |
- //continue parsing. |
- |
- const Tracks* const pTracks = m_pSegment->GetTracks(); |
- assert(pTracks); |
- |
- const long tn = static_cast<long>(track); |
- |
- const Track* const pTrack = pTracks->GetTrackByNumber(tn); |
- |
- if (pTrack == NULL) |
- return E_FILE_FORMAT_INVALID; |
-#endif |
- |
pos += len; // consume track number |
if ((pos + 2) > block_stop) |
@@ -6924,68 +6380,6 @@ long long Cluster::GetPosition() const { |
long long Cluster::GetElementSize() const { return m_element_size; } |
-#if 0 |
-bool Cluster::HasBlockEntries( |
- const Segment* pSegment, |
- long long off) { |
- assert(pSegment); |
- assert(off >= 0); //relative to start of segment payload |
- |
- 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); |
- (void)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; |
-} |
-#endif |
- |
long Cluster::HasBlockEntries( |
const Segment* pSegment, |
long long off, // relative to start of segment payload |
@@ -7269,7 +6663,7 @@ long Cluster::CreateBlock(long long id, |
assert(m_entries_size == 0); |
m_entries_size = 1024; |
- m_entries = new BlockEntry* [m_entries_size]; |
+ m_entries = new BlockEntry*[m_entries_size]; |
m_entries_count = 0; |
} else { |
@@ -7280,7 +6674,7 @@ long Cluster::CreateBlock(long long id, |
if (m_entries_count >= m_entries_size) { |
const long entries_size = 2 * m_entries_size; |
- BlockEntry** const entries = new BlockEntry* [entries_size]; |
+ BlockEntry** const entries = new BlockEntry*[entries_size]; |
assert(entries); |
BlockEntry** src = m_entries; |
@@ -7349,12 +6743,16 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size, |
bsize = size; |
} |
} else if (id == 0x1B) { // Duration ID |
- assert(size <= 8); |
+ if (size > 8) |
+ return E_FILE_FORMAT_INVALID; |
duration = UnserializeUInt(pReader, pos, size); |
- assert(duration >= 0); // TODO |
+ |
+ if (duration < 0) |
+ return E_FILE_FORMAT_INVALID; |
} else if (id == 0x7B) { // ReferenceBlock |
- assert(size <= 8); |
+ if (size > 8 || size <= 0) |
+ return E_FILE_FORMAT_INVALID; |
const long size_ = static_cast<long>(size); |
long long time; |
@@ -7373,9 +6771,10 @@ long Cluster::CreateBlockGroup(long long start_offset, long long size, |
pos += size; // consume payload |
assert(pos <= stop); |
} |
+ if (bpos < 0) |
+ return E_FILE_FORMAT_INVALID; |
assert(pos == stop); |
- assert(bpos >= 0); |
assert(bsize >= 0); |
const long idx = m_entries_count; |
@@ -7539,57 +6938,6 @@ const BlockEntry* Cluster::GetEntry(const Track* pTrack, |
if (m_pSegment == NULL) // this is the special EOS cluster |
return pTrack->GetEOS(); |
-#if 0 |
- |
- LoadBlockEntries(); |
- |
- if ((m_entries == NULL) || (m_entries_count <= 0)) |
- return NULL; //return EOS here? |
- |
- const BlockEntry* pResult = pTrack->GetEOS(); |
- |
- BlockEntry** i = m_entries; |
- assert(i); |
- |
- BlockEntry** const j = i + m_entries_count; |
- |
- while (i != j) |
- { |
- const BlockEntry* const pEntry = *i++; |
- assert(pEntry); |
- assert(!pEntry->EOS()); |
- |
- const Block* const pBlock = pEntry->GetBlock(); |
- assert(pBlock); |
- |
- if (pBlock->GetTrackNumber() != pTrack->GetNumber()) |
- continue; |
- |
- if (pTrack->VetEntry(pEntry)) |
- { |
- if (time_ns < 0) //just want first candidate block |
- 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 pResult; |
- |
-#else |
- |
const BlockEntry* pResult = pTrack->GetEOS(); |
long index = 0; |
@@ -7643,103 +6991,11 @@ const BlockEntry* Cluster::GetEntry(const Track* pTrack, |
++index; |
} |
- |
-#endif |
} |
const BlockEntry* Cluster::GetEntry(const CuePoint& cp, |
const CuePoint::TrackPosition& tp) const { |
assert(m_pSegment); |
- |
-#if 0 |
- |
- LoadBlockEntries(); |
- |
- if (m_entries == NULL) |
- return NULL; |
- |
- const long long count = m_entries_count; |
- |
- if (count <= 0) |
- return NULL; |
- |
- const long long tc = cp.GetTimeCode(); |
- |
- if ((tp.m_block > 0) && (tp.m_block <= count)) |
- { |
- const size_t block = static_cast<size_t>(tp.m_block); |
- const size_t index = block - 1; |
- |
- const BlockEntry* const pEntry = m_entries[index]; |
- assert(pEntry); |
- assert(!pEntry->EOS()); |
- |
- const Block* const pBlock = pEntry->GetBlock(); |
- assert(pBlock); |
- |
- if ((pBlock->GetTrackNumber() == tp.m_track) && |
- (pBlock->GetTimeCode(this) == tc)) |
- { |
- return pEntry; |
- } |
- } |
- |
- const BlockEntry* const* i = m_entries; |
- const BlockEntry* const* const j = i + count; |
- |
- while (i != j) |
- { |
-#ifdef _DEBUG |
- const ptrdiff_t idx = i - m_entries; |
- idx; |
-#endif |
- |
- const BlockEntry* const pEntry = *i++; |
- assert(pEntry); |
- assert(!pEntry->EOS()); |
- |
- const Block* const pBlock = pEntry->GetBlock(); |
- assert(pBlock); |
- |
- if (pBlock->GetTrackNumber() != tp.m_track) |
- continue; |
- |
- const long long tc_ = pBlock->GetTimeCode(this); |
- assert(tc_ >= 0); |
- |
- if (tc_ < tc) |
- continue; |
- |
- if (tc_ > tc) |
- return NULL; |
- |
- const Tracks* const pTracks = m_pSegment->GetTracks(); |
- assert(pTracks); |
- |
- const long tn = static_cast<long>(tp.m_track); |
- const Track* const pTrack = pTracks->GetTrackByNumber(tn); |
- |
- if (pTrack == NULL) |
- return NULL; |
- |
- const long long type = pTrack->GetType(); |
- |
- if (type == 2) //audio |
- return pEntry; |
- |
- if (type != 1) //not video |
- return NULL; |
- |
- if (!pBlock->IsKey()) |
- return NULL; |
- |
- return pEntry; |
- } |
- |
- return NULL; |
- |
-#else |
- |
const long long tc = cp.GetTimeCode(); |
if (tp.m_block > 0) { |
@@ -7835,54 +7091,12 @@ const BlockEntry* Cluster::GetEntry(const CuePoint& cp, |
return pEntry; |
} |
- |
-#endif |
-} |
- |
-#if 0 |
-const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const |
-{ |
- assert(pTrack); |
- |
- if (m_pSegment == NULL) //EOS |
- return pTrack->GetEOS(); |
- |
- LoadBlockEntries(); |
- |
- if ((m_entries == NULL) || (m_entries_count <= 0)) |
- return pTrack->GetEOS(); |
- |
- BlockEntry** i = m_entries + m_entries_count; |
- BlockEntry** const j = m_entries; |
- |
- while (i != j) |
- { |
- const BlockEntry* const pEntry = *--i; |
- assert(pEntry); |
- assert(!pEntry->EOS()); |
- |
- const Block* const pBlock = pEntry->GetBlock(); |
- assert(pBlock); |
- |
- if (pBlock->GetTrackNumber() != pTrack->GetNumber()) |
- continue; |
- |
- if (pBlock->IsKey()) |
- return pEntry; |
- } |
- |
- return pTrack->GetEOS(); //no satisfactory block found |
} |
-#endif |
BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {} |
- |
BlockEntry::~BlockEntry() {} |
- |
bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); } |
- |
const Cluster* BlockEntry::GetCluster() const { return m_pCluster; } |
- |
long BlockEntry::GetIndex() const { return m_index; } |
SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start, |
@@ -7890,9 +7104,7 @@ SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start, |
: BlockEntry(pCluster, idx), m_block(start, size, 0) {} |
long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); } |
- |
BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; } |
- |
const Block* SimpleBlock::GetBlock() const { return &m_block; } |
BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start, |
@@ -7915,30 +7127,10 @@ long BlockGroup::Parse() { |
return 0; |
} |
-#if 0 |
-void BlockGroup::ParseBlock(long long start, long long size) |
-{ |
- IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader; |
- |
- Block* const pBlock = new Block(start, size, pReader); |
- assert(pBlock); //TODO |
- |
- //TODO: the Matroska spec says you have multiple blocks within the |
- //same block group, with blocks ranked by priority (the flag bits). |
- |
- assert(m_pBlock == NULL); |
- m_pBlock = pBlock; |
-} |
-#endif |
- |
BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; } |
- |
const Block* BlockGroup::GetBlock() const { return &m_block; } |
- |
long long BlockGroup::GetPrevTimeCode() const { return m_prev; } |
- |
long long BlockGroup::GetNextTimeCode() const { return m_next; } |
- |
long long BlockGroup::GetDurationTimeCode() const { return m_duration; } |
Block::Block(long long start, long long size_, long long discard_padding) |
@@ -8028,7 +7220,7 @@ long Block::Parse(const Cluster* pCluster) { |
const long long frame_size = stop - pos; |
- if (frame_size > LONG_MAX) |
+ if (frame_size > LONG_MAX || frame_size <= 0) |
return E_FILE_FORMAT_INVALID; |
f.len = static_cast<long>(frame_size); |
@@ -8088,6 +7280,9 @@ long Block::Parse(const Cluster* pCluster) { |
f.pos = 0; // patch later |
+ if (frame_size <= 0) |
+ return E_FILE_FORMAT_INVALID; |
+ |
f.len = frame_size; |
size += frame_size; // contribution of this frame |
@@ -8112,7 +7307,7 @@ long Block::Parse(const Cluster* pCluster) { |
const long long frame_size = total_size - size; |
- if (frame_size > LONG_MAX) |
+ if (frame_size > LONG_MAX || frame_size <= 0) |
return E_FILE_FORMAT_INVALID; |
f.len = static_cast<long>(frame_size); |
@@ -8129,6 +7324,9 @@ long Block::Parse(const Cluster* pCluster) { |
assert(pos == stop); |
} else if (lacing == 2) { // fixed-size lacing |
+ if (pos >= stop) |
+ return E_FILE_FORMAT_INVALID; |
+ |
const long long total_size = stop - pos; |
if ((total_size % m_frame_count) != 0) |
@@ -8136,7 +7334,7 @@ long Block::Parse(const Cluster* pCluster) { |
const long long frame_size = total_size / m_frame_count; |
- if (frame_size > LONG_MAX) |
+ if (frame_size > LONG_MAX || frame_size <= 0) |
return E_FILE_FORMAT_INVALID; |
Frame* pf = m_frames; |
@@ -8165,7 +7363,7 @@ long Block::Parse(const Cluster* pCluster) { |
long long frame_size = ReadUInt(pReader, pos, len); |
- if (frame_size < 0) |
+ if (frame_size <= 0) |
return E_FILE_FORMAT_INVALID; |
if (frame_size > LONG_MAX) |
@@ -8227,7 +7425,7 @@ long Block::Parse(const Cluster* pCluster) { |
frame_size += delta_size; |
- if (frame_size < 0) |
+ if (frame_size <= 0) |
return E_FILE_FORMAT_INVALID; |
if (frame_size > LONG_MAX) |
@@ -8239,7 +7437,8 @@ long Block::Parse(const Cluster* pCluster) { |
--frame_count; |
} |
- { |
+ // parse last frame |
+ if (frame_count > 0) { |
assert(pos <= stop); |
assert(pf < pf_end); |
@@ -8262,7 +7461,7 @@ long Block::Parse(const Cluster* pCluster) { |
frame_size = total_size - size; |
- if (frame_size > LONG_MAX) |
+ if (frame_size > LONG_MAX || frame_size <= 0) |
return E_FILE_FORMAT_INVALID; |
curr.len = static_cast<long>(frame_size); |
@@ -8277,7 +7476,8 @@ long Block::Parse(const Cluster* pCluster) { |
pos += f.len; |
} |
- assert(pos == stop); |
+ if (pos != stop) |
+ return E_FILE_FORMAT_INVALID; |
} |
return 0; // success |