1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
9 #include "mkvparser.hpp"
11 #if defined(_MSC_VER) && _MSC_VER < 1800
12 #include <float.h> // _isnan() / _finite()
22 #include "webmids.hpp"
25 // Disable MSVC warnings that suggest making code non-portable.
26 #pragma warning(disable : 4996)
32 inline bool isnan(double val) { return !!_isnan(val); }
33 inline bool isinf(double val) { return !_finite(val); }
35 inline bool isnan(double val) { return std::isnan(val); }
36 inline bool isinf(double val) { return std::isinf(val); }
39 IMkvReader::~IMkvReader() {}
41 template<typename Type> Type* SafeArrayAlloc(unsigned long long num_elements,
42 unsigned long long element_size) {
43 if (num_elements == 0 || element_size == 0)
46 const size_t kMaxAllocSize = 0x80000000; // 2GiB
47 const unsigned long long num_bytes = num_elements * element_size;
48 if (element_size > (kMaxAllocSize / num_elements))
50 if (num_bytes != static_cast<size_t>(num_bytes))
53 return new (std::nothrow) Type[static_cast<size_t>(num_bytes)];
56 void GetVersion(int& major, int& minor, int& build, int& revision) {
63 long long ReadUInt(IMkvReader* pReader, long long pos, long& len) {
64 if (!pReader || pos < 0)
65 return E_FILE_FORMAT_INVALID;
69 int status = pReader->Read(pos, 1, &b);
71 if (status < 0) // error or underflow
74 if (status > 0) // interpreted as "underflow"
75 return E_BUFFER_NOT_FULL;
77 if (b == 0) // we can't handle u-int values larger than 8 bytes
78 return E_FILE_FORMAT_INVALID;
80 unsigned char m = 0x80;
87 long long result = b & (~m);
90 for (int i = 1; i < len; ++i) {
91 status = pReader->Read(pos, 1, &b);
100 return E_BUFFER_NOT_FULL;
112 // Reads an EBML ID and returns it.
113 // An ID must at least 1 byte long, cannot exceed 4, and its value must be
115 // See known EBML values and EBMLMaxIDLength:
116 // http://www.matroska.org/technical/specs/index.html
117 // Returns the ID, or a value less than 0 to report an error while reading the
119 long long ReadID(IMkvReader* pReader, long long pos, long& len) {
120 if (pReader == NULL || pos < 0)
121 return E_FILE_FORMAT_INVALID;
123 // Read the first byte. The length in bytes of the ID is determined by
124 // finding the first set bit in the first byte of the ID.
125 unsigned char temp_byte = 0;
126 int read_status = pReader->Read(pos, 1, &temp_byte);
129 return E_FILE_FORMAT_INVALID;
130 else if (read_status > 0) // No data to read.
131 return E_BUFFER_NOT_FULL;
133 if (temp_byte == 0) // ID length > 8 bytes; invalid file.
134 return E_FILE_FORMAT_INVALID;
137 const int kMaxIdLengthInBytes = 4;
138 const int kCheckByte = 0x80;
140 // Find the first bit that's set.
141 bool found_bit = false;
142 for (; bit_pos < kMaxIdLengthInBytes; ++bit_pos) {
143 if ((kCheckByte >> bit_pos) & temp_byte) {
150 // The value is too large to be a valid ID.
151 return E_FILE_FORMAT_INVALID;
154 // Read the remaining bytes of the ID (if any).
155 const int id_length = bit_pos + 1;
156 long long ebml_id = temp_byte;
157 for (int i = 1; i < id_length; ++i) {
159 read_status = pReader->Read(pos + i, 1, &temp_byte);
162 return E_FILE_FORMAT_INVALID;
163 else if (read_status > 0)
164 return E_BUFFER_NOT_FULL;
166 ebml_id |= temp_byte;
173 long long GetUIntLength(IMkvReader* pReader, long long pos, long& len) {
174 if (!pReader || pos < 0)
175 return E_FILE_FORMAT_INVALID;
177 long long total, available;
179 int status = pReader->Length(&total, &available);
180 if (status < 0 || (total >= 0 && available > total))
181 return E_FILE_FORMAT_INVALID;
185 if (pos >= available)
186 return pos; // too few bytes available
190 status = pReader->Read(pos, 1, &b);
195 if (b == 0) // we can't handle u-int values larger than 8 bytes
196 return E_FILE_FORMAT_INVALID;
198 unsigned char m = 0x80;
208 // TODO(vigneshv): This function assumes that unsigned values never have their
210 long long UnserializeUInt(IMkvReader* pReader, long long pos, long long size) {
211 if (!pReader || pos < 0 || (size <= 0) || (size > 8))
212 return E_FILE_FORMAT_INVALID;
214 long long result = 0;
216 for (long long i = 0; i < size; ++i) {
219 const long status = pReader->Read(pos, 1, &b);
233 long UnserializeFloat(IMkvReader* pReader, long long pos, long long size_,
235 if (!pReader || pos < 0 || ((size_ != 4) && (size_ != 8)))
236 return E_FILE_FORMAT_INVALID;
238 const long size = static_cast<long>(size_);
240 unsigned char buf[8];
242 const int status = pReader->Read(pos, size, buf);
244 if (status < 0) // error
268 unsigned long long dd;
285 if (mkvparser::isinf(result) || mkvparser::isnan(result))
286 return E_FILE_FORMAT_INVALID;
291 long UnserializeInt(IMkvReader* pReader, long long pos, long long size,
292 long long& result_ref) {
293 if (!pReader || pos < 0 || size < 1 || size > 8)
294 return E_FILE_FORMAT_INVALID;
296 signed char first_byte = 0;
297 const long status = pReader->Read(pos, 1, (unsigned char*)&first_byte);
302 unsigned long long result = first_byte;
305 for (long i = 1; i < size; ++i) {
308 const long status = pReader->Read(pos, 1, &b);
319 result_ref = static_cast<long long>(result);
323 long UnserializeString(IMkvReader* pReader, long long pos, long long size,
328 if (size >= LONG_MAX || size < 0)
329 return E_FILE_FORMAT_INVALID;
331 // +1 for '\0' terminator
332 const long required_size = static_cast<long>(size) + 1;
334 str = SafeArrayAlloc<char>(1, required_size);
336 return E_FILE_FORMAT_INVALID;
338 unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
340 const long status = pReader->Read(pos, static_cast<long>(size), buf);
349 str[required_size - 1] = '\0';
353 long ParseElementHeader(IMkvReader* pReader, long long& pos,
354 long long stop, long long& id,
356 if (stop >= 0 && pos >= stop)
357 return E_FILE_FORMAT_INVALID;
361 id = ReadID(pReader, pos, len);
364 return E_FILE_FORMAT_INVALID;
366 pos += len; // consume id
368 if (stop >= 0 && pos >= stop)
369 return E_FILE_FORMAT_INVALID;
371 size = ReadUInt(pReader, pos, len);
373 if (size < 0 || len < 1 || len > 8) {
374 // Invalid: Negative payload size, negative or 0 length integer, or integer
375 // larger than 64 bits (libwebm cannot handle them).
376 return E_FILE_FORMAT_INVALID;
379 // Avoid rolling over pos when very close to LLONG_MAX.
380 const unsigned long long rollover_check =
381 static_cast<unsigned long long>(pos) + len;
382 if (rollover_check > LLONG_MAX)
383 return E_FILE_FORMAT_INVALID;
385 pos += len; // consume length of size
387 // pos now designates payload
389 if (stop >= 0 && pos >= stop)
390 return E_FILE_FORMAT_INVALID;
395 bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
397 if (!pReader || pos < 0)
401 long long available = 0;
403 const long status = pReader->Length(&total, &available);
404 if (status < 0 || (total >= 0 && available > total))
409 const long long id = ReadID(pReader, pos, len);
410 if (id < 0 || (available - pos) > len)
413 if (static_cast<unsigned long>(id) != expected_id)
416 pos += len; // consume id
418 const long long size = ReadUInt(pReader, pos, len);
419 if (size < 0 || size > 8 || len < 1 || len > 8 || (available - pos) > len)
422 pos += len; // consume length of size of payload
424 val = UnserializeUInt(pReader, pos, size);
428 pos += size; // consume size of payload
433 bool Match(IMkvReader* pReader, long long& pos, unsigned long expected_id,
434 unsigned char*& buf, size_t& buflen) {
435 if (!pReader || pos < 0)
439 long long available = 0;
441 long status = pReader->Length(&total, &available);
442 if (status < 0 || (total >= 0 && available > total))
446 const long long id = ReadID(pReader, pos, len);
447 if (id < 0 || (available - pos) > len)
450 if (static_cast<unsigned long>(id) != expected_id)
453 pos += len; // consume id
455 const long long size = ReadUInt(pReader, pos, len);
456 if (size < 0 || len <= 0 || len > 8 || (available - pos) > len)
459 unsigned long long rollover_check =
460 static_cast<unsigned long long>(pos) + len;
461 if (rollover_check > LLONG_MAX)
464 pos += len; // consume length of size of payload
466 rollover_check = static_cast<unsigned long long>(pos) + size;
467 if (rollover_check > LLONG_MAX)
470 if ((pos + size) > available)
473 if (size >= LONG_MAX)
476 const long buflen_ = static_cast<long>(size);
478 buf = SafeArrayAlloc<unsigned char>(1, buflen_);
482 status = pReader->Read(pos, buflen_, buf);
488 pos += size; // consume size of payload
492 EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
494 EBMLHeader::~EBMLHeader() { delete[] m_docType; }
496 void EBMLHeader::Init() {
507 m_docTypeVersion = 1;
508 m_docTypeReadVersion = 1;
511 long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
513 return E_FILE_FORMAT_INVALID;
515 long long total, available;
517 long status = pReader->Length(&total, &available);
519 if (status < 0) // error
523 long long end = (available >= 1024) ? 1024 : available;
525 // Scan until we find what looks like the first byte of the EBML header.
526 const long long kMaxScanBytes = (available >= 1024) ? 1024 : available;
527 const unsigned char kEbmlByte0 = 0x1A;
528 unsigned char scan_byte = 0;
530 while (pos < kMaxScanBytes) {
531 status = pReader->Read(pos, 1, &scan_byte);
533 if (status < 0) // error
536 return E_BUFFER_NOT_FULL;
538 if (scan_byte == kEbmlByte0)
545 const long long ebml_id = ReadID(pReader, pos, len);
547 // TODO(tomfinegan): Move Matroska ID constants into a common namespace.
548 if (len != 4 || ebml_id != mkvmuxer::kMkvEBML)
549 return E_FILE_FORMAT_INVALID;
551 // Move read pos forward to the EBML header size field.
554 // Read length of size field.
555 long long result = GetUIntLength(pReader, pos, len);
557 if (result < 0) // error
558 return E_FILE_FORMAT_INVALID;
559 else if (result > 0) // need more data
560 return E_BUFFER_NOT_FULL;
562 if (len < 1 || len > 8)
563 return E_FILE_FORMAT_INVALID;
565 if ((total >= 0) && ((total - pos) < len))
566 return E_FILE_FORMAT_INVALID;
568 if ((available - pos) < len)
569 return pos + len; // try again later
571 // Read the EBML header size.
572 result = ReadUInt(pReader, pos, len);
574 if (result < 0) // error
577 pos += len; // consume size field
579 // pos now designates start of payload
581 if ((total >= 0) && ((total - pos) < result))
582 return E_FILE_FORMAT_INVALID;
584 if ((available - pos) < result)
594 status = ParseElementHeader(pReader, pos, end, id, size);
596 if (status < 0) // error
600 return E_FILE_FORMAT_INVALID;
602 if (id == mkvmuxer::kMkvEBMLVersion) {
603 m_version = UnserializeUInt(pReader, pos, size);
606 return E_FILE_FORMAT_INVALID;
607 } else if (id == mkvmuxer::kMkvEBMLReadVersion) {
608 m_readVersion = UnserializeUInt(pReader, pos, size);
610 if (m_readVersion <= 0)
611 return E_FILE_FORMAT_INVALID;
612 } else if (id == mkvmuxer::kMkvEBMLMaxIDLength) {
613 m_maxIdLength = UnserializeUInt(pReader, pos, size);
615 if (m_maxIdLength <= 0)
616 return E_FILE_FORMAT_INVALID;
617 } else if (id == mkvmuxer::kMkvEBMLMaxSizeLength) {
618 m_maxSizeLength = UnserializeUInt(pReader, pos, size);
620 if (m_maxSizeLength <= 0)
621 return E_FILE_FORMAT_INVALID;
622 } else if (id == mkvmuxer::kMkvDocType) {
624 return E_FILE_FORMAT_INVALID;
626 status = UnserializeString(pReader, pos, size, m_docType);
630 } else if (id == mkvmuxer::kMkvDocTypeVersion) {
631 m_docTypeVersion = UnserializeUInt(pReader, pos, size);
633 if (m_docTypeVersion <= 0)
634 return E_FILE_FORMAT_INVALID;
635 } else if (id == mkvmuxer::kMkvDocTypeReadVersion) {
636 m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
638 if (m_docTypeReadVersion <= 0)
639 return E_FILE_FORMAT_INVALID;
646 return E_FILE_FORMAT_INVALID;
648 // Make sure DocType, DocTypeReadVersion, and DocTypeVersion are valid.
649 if (m_docType == NULL || m_docTypeReadVersion <= 0 || m_docTypeVersion <= 0)
650 return E_FILE_FORMAT_INVALID;
652 // Make sure EBMLMaxIDLength and EBMLMaxSizeLength are valid.
653 if (m_maxIdLength <= 0 || m_maxIdLength > 4 ||
654 m_maxSizeLength <= 0 || m_maxSizeLength > 8)
655 return E_FILE_FORMAT_INVALID;
660 Segment::Segment(IMkvReader* pReader, long long elem_start,
661 // long long elem_size,
662 long long start, long long size)
663 : m_pReader(pReader),
664 m_element_start(elem_start),
665 // m_element_size(elem_size),
678 m_clusterPreloadCount(0),
681 Segment::~Segment() {
682 const long count = m_clusterCount + m_clusterPreloadCount;
684 Cluster** i = m_clusters;
685 Cluster** j = m_clusters + count;
688 Cluster* const p = *i++;
702 long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
703 Segment*& pSegment) {
704 if (pReader == NULL || pos < 0)
705 return E_PARSE_FAILED;
709 long long total, available;
711 const long status = pReader->Length(&total, &available);
713 if (status < 0) // error
719 if ((total >= 0) && (available > total))
722 // I would assume that in practice this loop would execute
723 // exactly once, but we allow for other elements (e.g. Void)
724 // to immediately follow the EBML header. This is fine for
725 // the source filter case (since the entire file is available),
726 // but in the splitter case over a network we should probably
727 // just give up early. We could for example decide only to
728 // execute this loop a maximum of, say, 10 times.
730 // There is an implied "give up early" by only parsing up
731 // to the available limit. We do do that, but only if the
732 // total file size is unknown. We could decide to always
733 // use what's available as our limit (irrespective of whether
734 // we happen to know the total file length). This would have
735 // as its sense "parse this much of the file before giving up",
736 // which a slightly different sense from "try to parse up to
737 // 10 EMBL elements before giving up".
740 if ((total >= 0) && (pos >= total))
741 return E_FILE_FORMAT_INVALID;
745 long long result = GetUIntLength(pReader, pos, len);
747 if (result) // error, or too few available bytes
750 if ((total >= 0) && ((pos + len) > total))
751 return E_FILE_FORMAT_INVALID;
753 if ((pos + len) > available)
756 const long long idpos = pos;
757 const long long id = ReadID(pReader, pos, len);
760 return E_FILE_FORMAT_INVALID;
762 pos += len; // consume ID
766 result = GetUIntLength(pReader, pos, len);
768 if (result) // error, or too few available bytes
771 if ((total >= 0) && ((pos + len) > total))
772 return E_FILE_FORMAT_INVALID;
774 if ((pos + len) > available)
777 long long size = ReadUInt(pReader, pos, len);
779 if (size < 0) // error
782 pos += len; // consume length of size of element
784 // Pos now points to start of payload
786 // Handle "unknown size" for live streaming of webm files.
787 const long long unknown_size = (1LL << (7 * len)) - 1;
789 if (id == mkvmuxer::kMkvSegment) {
790 if (size == unknown_size)
796 else if ((pos + size) > total)
799 pSegment = new (std::nothrow) Segment(pReader, idpos, pos, size);
800 if (pSegment == NULL)
801 return E_PARSE_FAILED;
806 if (size == unknown_size)
807 return E_FILE_FORMAT_INVALID;
809 if ((total >= 0) && ((pos + size) > total))
810 return E_FILE_FORMAT_INVALID;
812 if ((pos + size) > available)
815 pos += size; // consume payload
819 long long Segment::ParseHeaders() {
820 // Outermost (level 0) segment object has been constructed,
821 // and pos designates start of payload. We need to find the
822 // inner (level 1) elements.
823 long long total, available;
825 const int status = m_pReader->Length(&total, &available);
827 if (status < 0) // error
830 if (total > 0 && available > total)
831 return E_FILE_FORMAT_INVALID;
833 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
835 if ((segment_stop >= 0 && total >= 0 && segment_stop > total) ||
836 (segment_stop >= 0 && m_pos > segment_stop)) {
837 return E_FILE_FORMAT_INVALID;
841 if ((total >= 0) && (m_pos >= total))
844 if ((segment_stop >= 0) && (m_pos >= segment_stop))
847 long long pos = m_pos;
848 const long long element_start = pos;
850 // Avoid rolling over pos when very close to LLONG_MAX.
851 unsigned long long rollover_check = pos + 1ULL;
852 if (rollover_check > LLONG_MAX)
853 return E_FILE_FORMAT_INVALID;
855 if ((pos + 1) > available)
859 long long result = GetUIntLength(m_pReader, pos, len);
861 if (result < 0) // error
865 // MkvReader doesn't have enough data to satisfy this read attempt.
869 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
870 return E_FILE_FORMAT_INVALID;
872 if ((pos + len) > available)
875 const long long idpos = pos;
876 const long long id = ReadID(m_pReader, idpos, len);
879 return E_FILE_FORMAT_INVALID;
881 if (id == mkvmuxer::kMkvCluster)
884 pos += len; // consume ID
886 if ((pos + 1) > available)
890 result = GetUIntLength(m_pReader, pos, len);
892 if (result < 0) // error
896 // MkvReader doesn't have enough data to satisfy this read attempt.
900 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
901 return E_FILE_FORMAT_INVALID;
903 if ((pos + len) > available)
906 const long long size = ReadUInt(m_pReader, pos, len);
908 if (size < 0 || len < 1 || len > 8) {
909 // TODO(tomfinegan): ReadUInt should return an error when len is < 1 or
910 // len > 8 is true instead of checking this _everywhere_.
914 pos += len; // consume length of size of element
916 // Avoid rolling over pos when very close to LLONG_MAX.
917 rollover_check = static_cast<unsigned long long>(pos) + size;
918 if (rollover_check > LLONG_MAX)
919 return E_FILE_FORMAT_INVALID;
921 const long long element_size = size + pos - element_start;
923 // Pos now points to start of payload
925 if ((segment_stop >= 0) && ((pos + size) > segment_stop))
926 return E_FILE_FORMAT_INVALID;
928 // We read EBML elements either in total or nothing at all.
930 if ((pos + size) > available)
933 if (id == mkvmuxer::kMkvInfo) {
935 return E_FILE_FORMAT_INVALID;
937 m_pInfo = new (std::nothrow)
938 SegmentInfo(this, pos, size, element_start, element_size);
943 const long status = m_pInfo->Parse();
947 } else if (id == mkvmuxer::kMkvTracks) {
949 return E_FILE_FORMAT_INVALID;
951 m_pTracks = new (std::nothrow)
952 Tracks(this, pos, size, element_start, element_size);
954 if (m_pTracks == NULL)
957 const long status = m_pTracks->Parse();
961 } else if (id == mkvmuxer::kMkvCues) {
962 if (m_pCues == NULL) {
963 m_pCues = new (std::nothrow)
964 Cues(this, pos, size, element_start, element_size);
969 } else if (id == mkvmuxer::kMkvSeekHead) {
970 if (m_pSeekHead == NULL) {
971 m_pSeekHead = new (std::nothrow)
972 SeekHead(this, pos, size, element_start, element_size);
974 if (m_pSeekHead == NULL)
977 const long status = m_pSeekHead->Parse();
982 } else if (id == mkvmuxer::kMkvChapters) {
983 if (m_pChapters == NULL) {
984 m_pChapters = new (std::nothrow)
985 Chapters(this, pos, size, element_start, element_size);
987 if (m_pChapters == NULL)
990 const long status = m_pChapters->Parse();
995 } else if (id == mkvmuxer::kMkvTags) {
996 if (m_pTags == NULL) {
997 m_pTags = new (std::nothrow)
998 Tags(this, pos, size, element_start, element_size);
1000 if (m_pTags == NULL)
1003 const long status = m_pTags->Parse();
1010 m_pos = pos + size; // consume payload
1013 if (segment_stop >= 0 && m_pos > segment_stop)
1014 return E_FILE_FORMAT_INVALID;
1016 if (m_pInfo == NULL) // TODO: liberalize this behavior
1017 return E_FILE_FORMAT_INVALID;
1019 if (m_pTracks == NULL)
1020 return E_FILE_FORMAT_INVALID;
1022 return 0; // success
1025 long Segment::LoadCluster(long long& pos, long& len) {
1027 const long result = DoLoadCluster(pos, len);
1034 long Segment::DoLoadCluster(long long& pos, long& len) {
1036 return DoLoadClusterUnknownSize(pos, len);
1038 long long total, avail;
1040 long status = m_pReader->Length(&total, &avail);
1042 if (status < 0) // error
1045 if (total >= 0 && avail > total)
1046 return E_FILE_FORMAT_INVALID;
1048 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1050 long long cluster_off = -1; // offset relative to start of segment
1051 long long cluster_size = -1; // size of cluster payload
1054 if ((total >= 0) && (m_pos >= total))
1055 return 1; // no more clusters
1057 if ((segment_stop >= 0) && (m_pos >= segment_stop))
1058 return 1; // no more clusters
1064 if ((pos + 1) > avail) {
1066 return E_BUFFER_NOT_FULL;
1069 long long result = GetUIntLength(m_pReader, pos, len);
1071 if (result < 0) // error
1072 return static_cast<long>(result);
1075 return E_BUFFER_NOT_FULL;
1077 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1078 return E_FILE_FORMAT_INVALID;
1080 if ((pos + len) > avail)
1081 return E_BUFFER_NOT_FULL;
1083 const long long idpos = pos;
1084 const long long id = ReadID(m_pReader, idpos, len);
1087 return E_FILE_FORMAT_INVALID;
1089 pos += len; // consume ID
1093 if ((pos + 1) > avail) {
1095 return E_BUFFER_NOT_FULL;
1098 result = GetUIntLength(m_pReader, pos, len);
1100 if (result < 0) // error
1101 return static_cast<long>(result);
1104 return E_BUFFER_NOT_FULL;
1106 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1107 return E_FILE_FORMAT_INVALID;
1109 if ((pos + len) > avail)
1110 return E_BUFFER_NOT_FULL;
1112 const long long size = ReadUInt(m_pReader, pos, len);
1114 if (size < 0) // error
1115 return static_cast<long>(size);
1117 pos += len; // consume length of size of element
1119 // pos now points to start of payload
1122 // Missing element payload: move on.
1127 const long long unknown_size = (1LL << (7 * len)) - 1;
1129 if ((segment_stop >= 0) && (size != unknown_size) &&
1130 ((pos + size) > segment_stop)) {
1131 return E_FILE_FORMAT_INVALID;
1134 if (id == mkvmuxer::kMkvCues) {
1135 if (size == unknown_size) {
1136 // Cues element of unknown size: Not supported.
1137 return E_FILE_FORMAT_INVALID;
1140 if (m_pCues == NULL) {
1141 const long long element_size = (pos - idpos) + size;
1143 m_pCues = new (std::nothrow) Cues(this, pos, size, idpos, element_size);
1144 if (m_pCues == NULL)
1148 m_pos = pos + size; // consume payload
1152 if (id != mkvmuxer::kMkvCluster) {
1153 // Besides the Segment, Libwebm allows only cluster elements of unknown
1154 // size. Fail the parse upon encountering a non-cluster element reporting
1156 if (size == unknown_size)
1157 return E_FILE_FORMAT_INVALID;
1159 m_pos = pos + size; // consume payload
1163 // We have a cluster.
1165 cluster_off = idpos - m_start; // relative pos
1167 if (size != unknown_size)
1168 cluster_size = size;
1173 if (cluster_off < 0) {
1175 return E_FILE_FORMAT_INVALID;
1181 status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
1183 if (status < 0) { // error, or underflow
1190 // status == 0 means "no block entries found"
1191 // status > 0 means "found at least one block entry"
1194 // The issue here is that the segment increments its own
1195 // pos ptr past the most recent cluster parsed, and then
1196 // starts from there to parse the next cluster. If we
1197 // don't know the size of the current cluster, then we
1198 // must either parse its payload (as we do below), looking
1199 // for the cluster (or cues) ID to terminate the parse.
1200 // This isn't really what we want: rather, we really need
1201 // a way to create the curr cluster object immediately.
1202 // The pity is that cluster::parse can determine its own
1203 // boundary, and we largely duplicate that same logic here.
1205 // Maybe we need to get rid of our look-ahead preloading
1206 // in source::parse???
1208 // As we're parsing the blocks in the curr cluster
1209 //(in cluster::parse), we should have some way to signal
1210 // to the segment that we have determined the boundary,
1211 // so it can adjust its own segment::m_pos member.
1213 // The problem is that we're asserting in asyncreadinit,
1214 // because we adjust the pos down to the curr seek pos,
1215 // and the resulting adjusted len is > 2GB. I'm suspicious
1216 // that this is even correct, but even if it is, we can't
1217 // be loading that much data in the cache anyway.
1219 const long idx = m_clusterCount;
1221 if (m_clusterPreloadCount > 0) {
1222 if (idx >= m_clusterSize)
1223 return E_FILE_FORMAT_INVALID;
1225 Cluster* const pCluster = m_clusters[idx];
1226 if (pCluster == NULL || pCluster->m_index >= 0)
1227 return E_FILE_FORMAT_INVALID;
1229 const long long off = pCluster->GetPosition();
1231 return E_FILE_FORMAT_INVALID;
1233 if (off == cluster_off) { // preloaded already
1234 if (status == 0) // no entries found
1235 return E_FILE_FORMAT_INVALID;
1237 if (cluster_size >= 0)
1238 pos += cluster_size;
1240 const long long element_size = pCluster->GetElementSize();
1242 if (element_size <= 0)
1243 return E_FILE_FORMAT_INVALID; // TODO: handle this case
1245 pos = pCluster->m_element_start + element_size;
1248 pCluster->m_index = idx; // move from preloaded to loaded
1250 --m_clusterPreloadCount;
1252 m_pos = pos; // consume payload
1253 if (segment_stop >= 0 && m_pos > segment_stop)
1254 return E_FILE_FORMAT_INVALID;
1256 return 0; // success
1260 if (status == 0) { // no entries found
1261 if (cluster_size >= 0)
1262 pos += cluster_size;
1264 if ((total >= 0) && (pos >= total)) {
1266 return 1; // no more clusters
1269 if ((segment_stop >= 0) && (pos >= segment_stop)) {
1270 m_pos = segment_stop;
1271 return 1; // no more clusters
1275 return 2; // try again
1278 // status > 0 means we have an entry
1280 Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
1281 if (pCluster == NULL)
1284 if (!AppendCluster(pCluster)) {
1289 if (cluster_size >= 0) {
1290 pos += cluster_size;
1294 if (segment_stop > 0 && m_pos > segment_stop)
1295 return E_FILE_FORMAT_INVALID;
1300 m_pUnknownSize = pCluster;
1303 return 0; // partial success, since we have a new cluster
1305 // status == 0 means "no block entries found"
1306 // pos designates start of payload
1307 // m_pos has NOT been adjusted yet (in case we need to come back here)
1310 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
1311 if (m_pos >= 0 || m_pUnknownSize == NULL)
1312 return E_PARSE_FAILED;
1314 const long status = m_pUnknownSize->Parse(pos, len);
1316 if (status < 0) // error or underflow
1319 if (status == 0) // parsed a block
1320 return 2; // continue parsing
1322 const long long start = m_pUnknownSize->m_element_start;
1323 const long long size = m_pUnknownSize->GetElementSize();
1326 return E_FILE_FORMAT_INVALID;
1333 return 2; // continue parsing
1336 bool Segment::AppendCluster(Cluster* pCluster) {
1337 if (pCluster == NULL || pCluster->m_index < 0)
1340 const long count = m_clusterCount + m_clusterPreloadCount;
1342 long& size = m_clusterSize;
1343 const long idx = pCluster->m_index;
1345 if (size < count || idx != m_clusterCount)
1348 if (count >= size) {
1349 const long n = (size <= 0) ? 2048 : 2 * size;
1351 Cluster** const qq = new (std::nothrow) Cluster*[n];
1356 Cluster** p = m_clusters;
1357 Cluster** const pp = p + count;
1362 delete[] m_clusters;
1368 if (m_clusterPreloadCount > 0) {
1369 Cluster** const p = m_clusters + m_clusterCount;
1370 if (*p == NULL || (*p)->m_index >= 0)
1373 Cluster** q = p + m_clusterPreloadCount;
1374 if (q >= (m_clusters + size))
1378 Cluster** const qq = q - 1;
1379 if ((*qq)->m_index >= 0)
1390 m_clusters[idx] = pCluster;
1395 bool Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
1396 if (pCluster == NULL || pCluster->m_index >= 0 || idx < m_clusterCount)
1399 const long count = m_clusterCount + m_clusterPreloadCount;
1401 long& size = m_clusterSize;
1405 if (count >= size) {
1406 const long n = (size <= 0) ? 2048 : 2 * size;
1408 Cluster** const qq = new (std::nothrow) Cluster*[n];
1413 Cluster** p = m_clusters;
1414 Cluster** const pp = p + count;
1419 delete[] m_clusters;
1425 if (m_clusters == NULL)
1428 Cluster** const p = m_clusters + idx;
1430 Cluster** q = m_clusters + count;
1431 if (q < p || q >= (m_clusters + size))
1435 Cluster** const qq = q - 1;
1437 if ((*qq)->m_index >= 0)
1444 m_clusters[idx] = pCluster;
1445 ++m_clusterPreloadCount;
1449 long Segment::Load() {
1450 if (m_clusters != NULL || m_clusterSize != 0 || m_clusterCount != 0)
1451 return E_PARSE_FAILED;
1453 // Outermost (level 0) segment object has been constructed,
1454 // and pos designates start of payload. We need to find the
1455 // inner (level 1) elements.
1457 const long long header_status = ParseHeaders();
1459 if (header_status < 0) // error
1460 return static_cast<long>(header_status);
1462 if (header_status > 0) // underflow
1463 return E_BUFFER_NOT_FULL;
1465 if (m_pInfo == NULL || m_pTracks == NULL)
1466 return E_FILE_FORMAT_INVALID;
1469 const int status = LoadCluster();
1471 if (status < 0) // error
1474 if (status >= 1) // no more clusters
1479 SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
1480 long long element_start, long long element_size)
1481 : m_pSegment(pSegment),
1484 m_element_start(element_start),
1485 m_element_size(element_size),
1489 m_void_element_count(0) {}
1491 SeekHead::~SeekHead() {
1493 delete[] m_void_elements;
1496 long SeekHead::Parse() {
1497 IMkvReader* const pReader = m_pSegment->m_pReader;
1499 long long pos = m_start;
1500 const long long stop = m_start + m_size;
1502 // first count the seek head entries
1504 int entry_count = 0;
1505 int void_element_count = 0;
1507 while (pos < stop) {
1510 const long status = ParseElementHeader(pReader, pos, stop, id, size);
1512 if (status < 0) // error
1515 if (id == mkvmuxer::kMkvSeek)
1517 else if (id == mkvmuxer::kMkvVoid)
1518 ++void_element_count;
1520 pos += size; // consume payload
1523 return E_FILE_FORMAT_INVALID;
1527 return E_FILE_FORMAT_INVALID;
1529 m_entries = new (std::nothrow) Entry[entry_count];
1531 if (m_entries == NULL)
1534 m_void_elements = new (std::nothrow) VoidElement[void_element_count];
1536 if (m_void_elements == NULL)
1539 // now parse the entries and void elements
1541 Entry* pEntry = m_entries;
1542 VoidElement* pVoidElement = m_void_elements;
1546 while (pos < stop) {
1547 const long long idpos = pos;
1551 const long status = ParseElementHeader(pReader, pos, stop, id, size);
1553 if (status < 0) // error
1556 if (id == mkvmuxer::kMkvSeek) {
1557 if (ParseEntry(pReader, pos, size, pEntry)) {
1558 Entry& e = *pEntry++;
1560 e.element_start = idpos;
1561 e.element_size = (pos + size) - idpos;
1563 } else if (id == mkvmuxer::kMkvVoid) {
1564 VoidElement& e = *pVoidElement++;
1566 e.element_start = idpos;
1567 e.element_size = (pos + size) - idpos;
1570 pos += size; // consume payload
1572 return E_FILE_FORMAT_INVALID;
1576 return E_FILE_FORMAT_INVALID;
1578 ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
1579 assert(count_ >= 0);
1580 assert(count_ <= entry_count);
1582 m_entry_count = static_cast<int>(count_);
1584 count_ = ptrdiff_t(pVoidElement - m_void_elements);
1585 assert(count_ >= 0);
1586 assert(count_ <= void_element_count);
1588 m_void_element_count = static_cast<int>(count_);
1593 int SeekHead::GetCount() const { return m_entry_count; }
1595 const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
1599 if (idx >= m_entry_count)
1602 return m_entries + idx;
1605 int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1607 const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
1611 if (idx >= m_void_element_count)
1614 return m_void_elements + idx;
1617 long Segment::ParseCues(long long off, long long& pos, long& len) {
1619 return 0; // success
1624 long long total, avail;
1626 const int status = m_pReader->Length(&total, &avail);
1628 if (status < 0) // error
1631 assert((total < 0) || (avail <= total));
1633 pos = m_start + off;
1635 if ((total < 0) || (pos >= total))
1636 return 1; // don't bother parsing cues
1638 const long long element_start = pos;
1639 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1641 if ((pos + 1) > avail) {
1643 return E_BUFFER_NOT_FULL;
1646 long long result = GetUIntLength(m_pReader, pos, len);
1648 if (result < 0) // error
1649 return static_cast<long>(result);
1651 if (result > 0) // underflow (weird)
1654 return E_BUFFER_NOT_FULL;
1657 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1658 return E_FILE_FORMAT_INVALID;
1660 if ((pos + len) > avail)
1661 return E_BUFFER_NOT_FULL;
1663 const long long idpos = pos;
1665 const long long id = ReadID(m_pReader, idpos, len);
1667 if (id != mkvmuxer::kMkvCues)
1668 return E_FILE_FORMAT_INVALID;
1670 pos += len; // consume ID
1671 assert((segment_stop < 0) || (pos <= segment_stop));
1675 if ((pos + 1) > avail) {
1677 return E_BUFFER_NOT_FULL;
1680 result = GetUIntLength(m_pReader, pos, len);
1682 if (result < 0) // error
1683 return static_cast<long>(result);
1685 if (result > 0) // underflow (weird)
1688 return E_BUFFER_NOT_FULL;
1691 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1692 return E_FILE_FORMAT_INVALID;
1694 if ((pos + len) > avail)
1695 return E_BUFFER_NOT_FULL;
1697 const long long size = ReadUInt(m_pReader, pos, len);
1699 if (size < 0) // error
1700 return static_cast<long>(size);
1702 if (size == 0) // weird, although technically not illegal
1705 pos += len; // consume length of size of element
1706 assert((segment_stop < 0) || (pos <= segment_stop));
1708 // Pos now points to start of payload
1710 const long long element_stop = pos + size;
1712 if ((segment_stop >= 0) && (element_stop > segment_stop))
1713 return E_FILE_FORMAT_INVALID;
1715 if ((total >= 0) && (element_stop > total))
1716 return 1; // don't bother parsing anymore
1718 len = static_cast<long>(size);
1720 if (element_stop > avail)
1721 return E_BUFFER_NOT_FULL;
1723 const long long element_size = element_stop - element_start;
1726 new (std::nothrow) Cues(this, pos, size, element_start, element_size);
1727 if (m_pCues == NULL)
1730 return 0; // success
1733 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
1738 long long pos = start;
1739 const long long stop = start + size_;
1743 // parse the container for the level-1 element ID
1745 const long long seekIdId = ReadID(pReader, pos, len);
1749 if (seekIdId != mkvmuxer::kMkvSeekID)
1752 if ((pos + len) > stop)
1755 pos += len; // consume SeekID id
1757 const long long seekIdSize = ReadUInt(pReader, pos, len);
1759 if (seekIdSize <= 0)
1762 if ((pos + len) > stop)
1765 pos += len; // consume size of field
1767 if ((pos + seekIdSize) > stop)
1770 // Note that the SeekId payload really is serialized
1771 // as a "Matroska integer", not as a plain binary value.
1772 // In fact, Matroska requires that ID values in the
1773 // stream exactly match the binary representation as listed
1774 // in the Matroska specification.
1776 // This parser is more liberal, and permits IDs to have
1777 // any width. (This could make the representation in the stream
1778 // different from what's in the spec, but it doesn't matter here,
1779 // since we always normalize "Matroska integer" values.)
1781 pEntry->id = ReadUInt(pReader, pos, len); // payload
1783 if (pEntry->id <= 0)
1786 if (len != seekIdSize)
1789 pos += seekIdSize; // consume SeekID payload
1791 const long long seekPosId = ReadID(pReader, pos, len);
1793 if (seekPosId != mkvmuxer::kMkvSeekPosition)
1796 if ((pos + len) > stop)
1799 pos += len; // consume id
1801 const long long seekPosSize = ReadUInt(pReader, pos, len);
1803 if (seekPosSize <= 0)
1806 if ((pos + len) > stop)
1809 pos += len; // consume size
1811 if ((pos + seekPosSize) > stop)
1814 pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
1816 if (pEntry->pos < 0)
1819 pos += seekPosSize; // consume payload
1827 Cues::Cues(Segment* pSegment, long long start_, long long size_,
1828 long long element_start, long long element_size)
1829 : m_pSegment(pSegment),
1832 m_element_start(element_start),
1833 m_element_size(element_size),
1840 const long n = m_count + m_preload_count;
1842 CuePoint** p = m_cue_points;
1843 CuePoint** const q = p + n;
1846 CuePoint* const pCP = *p++;
1852 delete[] m_cue_points;
1855 long Cues::GetCount() const {
1856 if (m_cue_points == NULL)
1859 return m_count; // TODO: really ignore preload count?
1862 bool Cues::DoneParsing() const {
1863 const long long stop = m_start + m_size;
1864 return (m_pos >= stop);
1867 bool Cues::Init() const {
1871 if (m_count != 0 || m_preload_count != 0)
1874 IMkvReader* const pReader = m_pSegment->m_pReader;
1876 const long long stop = m_start + m_size;
1877 long long pos = m_start;
1879 long cue_points_size = 0;
1881 while (pos < stop) {
1882 const long long idpos = pos;
1886 const long long id = ReadID(pReader, pos, len);
1887 if (id < 0 || (pos + len) > stop) {
1891 pos += len; // consume ID
1893 const long long size = ReadUInt(pReader, pos, len);
1894 if (size < 0 || (pos + len > stop)) {
1898 pos += len; // consume Size field
1899 if (pos + size > stop) {
1903 if (id == mkvmuxer::kMkvCuePoint) {
1904 if (!PreloadCuePoint(cue_points_size, idpos))
1908 pos += size; // skip payload
1913 bool Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
1917 if (m_preload_count >= cue_points_size) {
1918 const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
1920 CuePoint** const qq = new (std::nothrow) CuePoint*[n];
1924 CuePoint** q = qq; // beginning of target
1926 CuePoint** p = m_cue_points; // beginning of source
1927 CuePoint** const pp = p + m_preload_count; // end of source
1932 delete[] m_cue_points;
1935 cue_points_size = n;
1938 CuePoint* const pCP = new (std::nothrow) CuePoint(m_preload_count, pos);
1942 m_cue_points[m_preload_count++] = pCP;
1946 bool Cues::LoadCuePoint() const {
1947 const long long stop = m_start + m_size;
1950 return false; // nothing else to do
1957 IMkvReader* const pReader = m_pSegment->m_pReader;
1959 while (m_pos < stop) {
1960 const long long idpos = m_pos;
1964 const long long id = ReadID(pReader, m_pos, len);
1965 if (id < 0 || (m_pos + len) > stop)
1968 m_pos += len; // consume ID
1970 const long long size = ReadUInt(pReader, m_pos, len);
1971 if (size < 0 || (m_pos + len) > stop)
1974 m_pos += len; // consume Size field
1975 if ((m_pos + size) > stop)
1978 if (id != mkvmuxer::kMkvCuePoint) {
1979 m_pos += size; // consume payload
1986 if (m_preload_count < 1)
1989 CuePoint* const pCP = m_cue_points[m_count];
1990 if (!pCP || (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos)))
1993 if (!pCP->Load(pReader)) {
2000 m_pos += size; // consume payload
2004 return true; // yes, we loaded a cue point
2007 return false; // no, we did not load a cue point
2010 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
2011 const CuePoint::TrackPosition*& pTP) const {
2012 if (time_ns < 0 || pTrack == NULL || m_cue_points == NULL || m_count == 0)
2015 CuePoint** const ii = m_cue_points;
2018 CuePoint** const jj = ii + m_count;
2025 if (time_ns <= pCP->GetTime(m_pSegment)) {
2026 pTP = pCP->Find(pTrack);
2027 return (pTP != NULL);
2032 //[ii, i) <= time_ns
2036 CuePoint** const k = i + (j - i) / 2;
2040 CuePoint* const pCP = *k;
2044 const long long t = pCP->GetTime(m_pSegment);
2055 if (i != j || i > jj || i <= ii)
2060 if (pCP == NULL || pCP->GetTime(m_pSegment) > time_ns)
2063 // TODO: here and elsewhere, it's probably not correct to search
2064 // for the cue point with this time, and then search for a matching
2065 // track. In principle, the matching track could be on some earlier
2066 // cue point, and with our current algorithm, we'd miss it. To make
2067 // this bullet-proof, we'd need to create a secondary structure,
2068 // with a list of cue points that apply to a track, and then search
2069 // that track-based structure for a matching cue point.
2071 pTP = pCP->Find(pTrack);
2072 return (pTP != NULL);
2075 const CuePoint* Cues::GetFirst() const {
2076 if (m_cue_points == NULL || m_count == 0)
2079 CuePoint* const* const pp = m_cue_points;
2083 CuePoint* const pCP = pp[0];
2084 if (pCP == NULL || pCP->GetTimeCode() < 0)
2090 const CuePoint* Cues::GetLast() const {
2091 if (m_cue_points == NULL || m_count <= 0)
2094 const long index = m_count - 1;
2096 CuePoint* const* const pp = m_cue_points;
2100 CuePoint* const pCP = pp[index];
2101 if (pCP == NULL || pCP->GetTimeCode() < 0)
2107 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
2108 if (pCurr == NULL || pCurr->GetTimeCode() < 0 ||
2109 m_cue_points == NULL || m_count < 1) {
2113 long index = pCurr->m_index;
2114 if (index >= m_count)
2117 CuePoint* const* const pp = m_cue_points;
2118 if (pp == NULL || pp[index] != pCurr)
2123 if (index >= m_count)
2126 CuePoint* const pNext = pp[index];
2128 if (pNext == NULL || pNext->GetTimeCode() < 0)
2134 const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
2135 const CuePoint::TrackPosition* pTP) const {
2136 if (pCP == NULL || pTP == NULL)
2139 return m_pSegment->GetBlock(*pCP, *pTP);
2142 const BlockEntry* Segment::GetBlock(const CuePoint& cp,
2143 const CuePoint::TrackPosition& tp) {
2144 Cluster** const ii = m_clusters;
2147 const long count = m_clusterCount + m_clusterPreloadCount;
2149 Cluster** const jj = ii + count;
2154 //[ii, i) < pTP->m_pos
2156 //[j, jj) > pTP->m_pos
2158 Cluster** const k = i + (j - i) / 2;
2161 Cluster* const pCluster = *k;
2164 // const long long pos_ = pCluster->m_pos;
2166 // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2168 const long long pos = pCluster->GetPosition();
2173 else if (pos > tp.m_pos)
2176 return pCluster->GetEntry(cp, tp);
2180 // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2182 Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1);
2183 if (pCluster == NULL)
2186 const ptrdiff_t idx = i - m_clusters;
2188 if (!PreloadCluster(pCluster, idx)) {
2193 assert(m_clusterPreloadCount > 0);
2194 assert(m_clusters[idx] == pCluster);
2196 return pCluster->GetEntry(cp, tp);
2199 const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
2200 if (requested_pos < 0)
2203 Cluster** const ii = m_clusters;
2206 const long count = m_clusterCount + m_clusterPreloadCount;
2208 Cluster** const jj = ii + count;
2213 //[ii, i) < pTP->m_pos
2215 //[j, jj) > pTP->m_pos
2217 Cluster** const k = i + (j - i) / 2;
2220 Cluster* const pCluster = *k;
2223 // const long long pos_ = pCluster->m_pos;
2225 // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2227 const long long pos = pCluster->GetPosition();
2230 if (pos < requested_pos)
2232 else if (pos > requested_pos)
2239 // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2241 Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
2242 if (pCluster == NULL)
2245 const ptrdiff_t idx = i - m_clusters;
2247 if (!PreloadCluster(pCluster, idx)) {
2252 assert(m_clusterPreloadCount > 0);
2253 assert(m_clusters[idx] == pCluster);
2258 CuePoint::CuePoint(long idx, long long pos)
2259 : m_element_start(0),
2262 m_timecode(-1 * pos),
2263 m_track_positions(NULL),
2264 m_track_positions_count(0) {
2268 CuePoint::~CuePoint() { delete[] m_track_positions; }
2270 bool CuePoint::Load(IMkvReader* pReader) {
2272 // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
2274 if (m_timecode >= 0) // already loaded
2277 assert(m_track_positions == NULL);
2278 assert(m_track_positions_count == 0);
2280 long long pos_ = -m_timecode;
2281 const long long element_start = pos_;
2288 const long long id = ReadID(pReader, pos_, len);
2289 if (id != mkvmuxer::kMkvCuePoint)
2292 pos_ += len; // consume ID
2294 const long long size = ReadUInt(pReader, pos_, len);
2297 pos_ += len; // consume Size field
2298 // pos_ now points to start of payload
2303 const long long element_size = stop - element_start;
2305 long long pos = pos_;
2307 // First count number of track positions
2309 while (pos < stop) {
2312 const long long id = ReadID(pReader, pos, len);
2313 if ((id < 0) || (pos + len > stop)) {
2317 pos += len; // consume ID
2319 const long long size = ReadUInt(pReader, pos, len);
2320 if ((size < 0) || (pos + len > stop)) {
2324 pos += len; // consume Size field
2325 if ((pos + size) > stop) {
2329 if (id == mkvmuxer::kMkvCueTime)
2330 m_timecode = UnserializeUInt(pReader, pos, size);
2332 else if (id == mkvmuxer::kMkvCueTrackPositions)
2333 ++m_track_positions_count;
2335 pos += size; // consume payload
2338 if (m_timecode < 0 || m_track_positions_count <= 0) {
2342 // os << "CuePoint::Load(cont'd): idpos=" << idpos
2343 // << " timecode=" << m_timecode
2346 m_track_positions = new (std::nothrow) TrackPosition[m_track_positions_count];
2347 if (m_track_positions == NULL)
2350 // Now parse track positions
2352 TrackPosition* p = m_track_positions;
2355 while (pos < stop) {
2358 const long long id = ReadID(pReader, pos, len);
2359 if (id < 0 || (pos + len) > stop)
2362 pos += len; // consume ID
2364 const long long size = ReadUInt(pReader, pos, len);
2366 assert((pos + len) <= stop);
2368 pos += len; // consume Size field
2369 assert((pos + size) <= stop);
2371 if (id == mkvmuxer::kMkvCueTrackPositions) {
2372 TrackPosition& tp = *p++;
2373 if (!tp.Parse(pReader, pos, size)) {
2378 pos += size; // consume payload
2383 assert(size_t(p - m_track_positions) == m_track_positions_count);
2385 m_element_start = element_start;
2386 m_element_size = element_size;
2391 bool CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
2393 const long long stop = start_ + size_;
2394 long long pos = start_;
2398 m_block = 1; // default
2400 while (pos < stop) {
2403 const long long id = ReadID(pReader, pos, len);
2404 if ((id < 0) || ((pos + len) > stop)) {
2408 pos += len; // consume ID
2410 const long long size = ReadUInt(pReader, pos, len);
2411 if ((size < 0) || ((pos + len) > stop)) {
2415 pos += len; // consume Size field
2416 if ((pos + size) > stop) {
2420 if (id == mkvmuxer::kMkvCueTrack)
2421 m_track = UnserializeUInt(pReader, pos, size);
2422 else if (id == mkvmuxer::kMkvCueClusterPosition)
2423 m_pos = UnserializeUInt(pReader, pos, size);
2424 else if (id == mkvmuxer::kMkvCueBlockNumber)
2425 m_block = UnserializeUInt(pReader, pos, size);
2427 pos += size; // consume payload
2430 if ((m_pos < 0) || (m_track <= 0)) {
2437 const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
2440 const long long n = pTrack->GetNumber();
2442 const TrackPosition* i = m_track_positions;
2443 const TrackPosition* const j = i + m_track_positions_count;
2446 const TrackPosition& p = *i++;
2452 return NULL; // no matching track number found
2455 long long CuePoint::GetTimeCode() const { return m_timecode; }
2457 long long CuePoint::GetTime(const Segment* pSegment) const {
2459 assert(m_timecode >= 0);
2461 const SegmentInfo* const pInfo = pSegment->GetInfo();
2464 const long long scale = pInfo->GetTimeCodeScale();
2467 const long long time = scale * m_timecode;
2472 bool Segment::DoneParsing() const {
2474 long long total, avail;
2476 const int status = m_pReader->Length(&total, &avail);
2478 if (status < 0) // error
2479 return true; // must assume done
2482 return false; // assume live stream
2484 return (m_pos >= total);
2487 const long long stop = m_start + m_size;
2489 return (m_pos >= stop);
2492 const Cluster* Segment::GetFirst() const {
2493 if ((m_clusters == NULL) || (m_clusterCount <= 0))
2496 Cluster* const pCluster = m_clusters[0];
2502 const Cluster* Segment::GetLast() const {
2503 if ((m_clusters == NULL) || (m_clusterCount <= 0))
2506 const long idx = m_clusterCount - 1;
2508 Cluster* const pCluster = m_clusters[idx];
2514 unsigned long Segment::GetCount() const { return m_clusterCount; }
2516 const Cluster* Segment::GetNext(const Cluster* pCurr) {
2518 assert(pCurr != &m_eos);
2521 long idx = pCurr->m_index;
2524 assert(m_clusterCount > 0);
2525 assert(idx < m_clusterCount);
2526 assert(pCurr == m_clusters[idx]);
2530 if (idx >= m_clusterCount)
2531 return &m_eos; // caller will LoadCluster as desired
2533 Cluster* const pNext = m_clusters[idx];
2535 assert(pNext->m_index >= 0);
2536 assert(pNext->m_index == idx);
2541 assert(m_clusterPreloadCount > 0);
2543 long long pos = pCurr->m_element_start;
2545 assert(m_size >= 0); // TODO
2546 const long long stop = m_start + m_size; // end of segment
2551 long long result = GetUIntLength(m_pReader, pos, len);
2552 assert(result == 0);
2553 assert((pos + len) <= stop); // TODO
2557 const long long id = ReadID(m_pReader, pos, len);
2558 if (id != mkvmuxer::kMkvCluster)
2561 pos += len; // consume ID
2564 result = GetUIntLength(m_pReader, pos, len);
2565 assert(result == 0); // TODO
2566 assert((pos + len) <= stop); // TODO
2568 const long long size = ReadUInt(m_pReader, pos, len);
2569 assert(size > 0); // TODO
2570 // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2572 pos += len; // consume length of size of element
2573 assert((pos + size) <= stop); // TODO
2575 // Pos now points to start of payload
2577 pos += size; // consume payload
2580 long long off_next = 0;
2582 while (pos < stop) {
2585 long long result = GetUIntLength(m_pReader, pos, len);
2586 assert(result == 0);
2587 assert((pos + len) <= stop); // TODO
2591 const long long idpos = pos; // pos of next (potential) cluster
2593 const long long id = ReadID(m_pReader, idpos, len);
2597 pos += len; // consume ID
2600 result = GetUIntLength(m_pReader, pos, len);
2601 assert(result == 0); // TODO
2602 assert((pos + len) <= stop); // TODO
2604 const long long size = ReadUInt(m_pReader, pos, len);
2605 assert(size >= 0); // TODO
2607 pos += len; // consume length of size of element
2608 assert((pos + size) <= stop); // TODO
2610 // Pos now points to start of payload
2612 if (size == 0) // weird
2615 if (id == mkvmuxer::kMkvCluster) {
2616 const long long off_next_ = idpos - m_start;
2621 const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
2623 assert(status >= 0);
2626 off_next = off_next_;
2631 pos += size; // consume payload
2637 Cluster** const ii = m_clusters + m_clusterCount;
2640 Cluster** const jj = ii + m_clusterPreloadCount;
2647 //[j, jj) > pos_next
2649 Cluster** const k = i + (j - i) / 2;
2652 Cluster* const pNext = *k;
2654 assert(pNext->m_index < 0);
2656 // const long long pos_ = pNext->m_pos;
2658 // pos = pos_ * ((pos_ < 0) ? -1 : 1);
2660 pos = pNext->GetPosition();
2664 else if (pos > off_next)
2672 Cluster* const pNext = Cluster::Create(this, -1, off_next);
2676 const ptrdiff_t idx_next = i - m_clusters; // insertion position
2678 if (!PreloadCluster(pNext, idx_next)) {
2683 assert(idx_next < m_clusterSize);
2684 assert(m_clusters[idx_next] == pNext);
2689 long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
2690 long long& pos, long& len) {
2692 assert(!pCurr->EOS());
2697 if (pCurr->m_index >= 0) { // loaded (not merely preloaded)
2698 assert(m_clusters[pCurr->m_index] == pCurr);
2700 const long next_idx = pCurr->m_index + 1;
2702 if (next_idx < m_clusterCount) {
2703 pResult = m_clusters[next_idx];
2704 return 0; // success
2707 // curr cluster is last among loaded
2709 const long result = LoadCluster(pos, len);
2711 if (result < 0) // error or underflow
2714 if (result > 0) // no more clusters
2716 // pResult = &m_eos;
2720 pResult = GetLast();
2721 return 0; // success
2726 long long total, avail;
2728 long status = m_pReader->Length(&total, &avail);
2730 if (status < 0) // error
2733 assert((total < 0) || (avail <= total));
2735 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2737 // interrogate curr cluster
2739 pos = pCurr->m_element_start;
2741 if (pCurr->m_element_size >= 0)
2742 pos += pCurr->m_element_size;
2744 if ((pos + 1) > avail) {
2746 return E_BUFFER_NOT_FULL;
2749 long long result = GetUIntLength(m_pReader, pos, len);
2751 if (result < 0) // error
2752 return static_cast<long>(result);
2754 if (result > 0) // weird
2755 return E_BUFFER_NOT_FULL;
2757 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2758 return E_FILE_FORMAT_INVALID;
2760 if ((pos + len) > avail)
2761 return E_BUFFER_NOT_FULL;
2763 const long long id = ReadUInt(m_pReader, pos, len);
2765 if (id != mkvmuxer::kMkvCluster)
2768 pos += len; // consume ID
2772 if ((pos + 1) > avail) {
2774 return E_BUFFER_NOT_FULL;
2777 result = GetUIntLength(m_pReader, pos, len);
2779 if (result < 0) // error
2780 return static_cast<long>(result);
2782 if (result > 0) // weird
2783 return E_BUFFER_NOT_FULL;
2785 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2786 return E_FILE_FORMAT_INVALID;
2788 if ((pos + len) > avail)
2789 return E_BUFFER_NOT_FULL;
2791 const long long size = ReadUInt(m_pReader, pos, len);
2793 if (size < 0) // error
2794 return static_cast<long>(size);
2796 pos += len; // consume size field
2798 const long long unknown_size = (1LL << (7 * len)) - 1;
2800 if (size == unknown_size) // TODO: should never happen
2801 return E_FILE_FORMAT_INVALID; // TODO: resolve this
2803 // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
2805 if ((segment_stop >= 0) && ((pos + size) > segment_stop))
2806 return E_FILE_FORMAT_INVALID;
2808 // Pos now points to start of payload
2810 pos += size; // consume payload (that is, the current cluster)
2811 if (segment_stop >= 0 && pos > segment_stop)
2812 return E_FILE_FORMAT_INVALID;
2814 // By consuming the payload, we are assuming that the curr
2815 // cluster isn't interesting. That is, we don't bother checking
2816 // whether the payload of the curr cluster is less than what
2817 // happens to be available (obtained via IMkvReader::Length).
2818 // Presumably the caller has already dispensed with the current
2819 // cluster, and really does want the next cluster.
2822 // pos now points to just beyond the last fully-loaded cluster
2825 const long status = DoParseNext(pResult, pos, len);
2832 long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
2833 long long total, avail;
2835 long status = m_pReader->Length(&total, &avail);
2837 if (status < 0) // error
2840 assert((total < 0) || (avail <= total));
2842 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
2844 // Parse next cluster. This is strictly a parsing activity.
2845 // Creation of a new cluster object happens later, after the
2848 long long off_next = 0;
2849 long long cluster_size = -1;
2852 if ((total >= 0) && (pos >= total))
2855 if ((segment_stop >= 0) && (pos >= segment_stop))
2858 if ((pos + 1) > avail) {
2860 return E_BUFFER_NOT_FULL;
2863 long long result = GetUIntLength(m_pReader, pos, len);
2865 if (result < 0) // error
2866 return static_cast<long>(result);
2868 if (result > 0) // weird
2869 return E_BUFFER_NOT_FULL;
2871 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2872 return E_FILE_FORMAT_INVALID;
2874 if ((pos + len) > avail)
2875 return E_BUFFER_NOT_FULL;
2877 const long long idpos = pos; // absolute
2878 const long long idoff = pos - m_start; // relative
2880 const long long id = ReadID(m_pReader, idpos, len); // absolute
2882 if (id < 0) // error
2883 return static_cast<long>(id);
2885 if (id == 0) // weird
2886 return -1; // generic error
2888 pos += len; // consume ID
2892 if ((pos + 1) > avail) {
2894 return E_BUFFER_NOT_FULL;
2897 result = GetUIntLength(m_pReader, pos, len);
2899 if (result < 0) // error
2900 return static_cast<long>(result);
2902 if (result > 0) // weird
2903 return E_BUFFER_NOT_FULL;
2905 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
2906 return E_FILE_FORMAT_INVALID;
2908 if ((pos + len) > avail)
2909 return E_BUFFER_NOT_FULL;
2911 const long long size = ReadUInt(m_pReader, pos, len);
2913 if (size < 0) // error
2914 return static_cast<long>(size);
2916 pos += len; // consume length of size of element
2918 // Pos now points to start of payload
2920 if (size == 0) // weird
2923 const long long unknown_size = (1LL << (7 * len)) - 1;
2925 if ((segment_stop >= 0) && (size != unknown_size) &&
2926 ((pos + size) > segment_stop)) {
2927 return E_FILE_FORMAT_INVALID;
2930 if (id == mkvmuxer::kMkvCues) {
2931 if (size == unknown_size)
2932 return E_FILE_FORMAT_INVALID;
2934 const long long element_stop = pos + size;
2936 if ((segment_stop >= 0) && (element_stop > segment_stop))
2937 return E_FILE_FORMAT_INVALID;
2939 const long long element_start = idpos;
2940 const long long element_size = element_stop - element_start;
2942 if (m_pCues == NULL) {
2943 m_pCues = new (std::nothrow)
2944 Cues(this, pos, size, element_start, element_size);
2945 if (m_pCues == NULL)
2949 pos += size; // consume payload
2950 if (segment_stop >= 0 && pos > segment_stop)
2951 return E_FILE_FORMAT_INVALID;
2956 if (id != mkvmuxer::kMkvCluster) { // not a Cluster ID
2957 if (size == unknown_size)
2958 return E_FILE_FORMAT_INVALID;
2960 pos += size; // consume payload
2961 if (segment_stop >= 0 && pos > segment_stop)
2962 return E_FILE_FORMAT_INVALID;
2967 // We have a cluster.
2970 if (size != unknown_size)
2971 cluster_size = size;
2976 assert(off_next > 0); // have cluster
2978 // We have parsed the next cluster.
2979 // We have not created a cluster object yet. What we need
2980 // to do now is determine whether it has already be preloaded
2981 //(in which case, an object for this cluster has already been
2982 // created), and if not, create a new cluster object.
2984 Cluster** const ii = m_clusters + m_clusterCount;
2987 Cluster** const jj = ii + m_clusterPreloadCount;
2994 //[j, jj) > pos_next
2996 Cluster** const k = i + (j - i) / 2;
2999 const Cluster* const pNext = *k;
3001 assert(pNext->m_index < 0);
3003 pos = pNext->GetPosition();
3008 else if (pos > off_next)
3012 return 0; // success
3021 status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
3023 if (status < 0) { // error or underflow
3030 if (status > 0) { // means "found at least one block entry"
3031 Cluster* const pNext = Cluster::Create(this,
3037 const ptrdiff_t idx_next = i - m_clusters; // insertion position
3039 if (!PreloadCluster(pNext, idx_next)) {
3044 assert(idx_next < m_clusterSize);
3045 assert(m_clusters[idx_next] == pNext);
3048 return 0; // success
3051 // status == 0 means "no block entries found"
3053 if (cluster_size < 0) { // unknown size
3054 const long long payload_pos = pos; // absolute pos of cluster payload
3056 for (;;) { // determine cluster size
3057 if ((total >= 0) && (pos >= total))
3060 if ((segment_stop >= 0) && (pos >= segment_stop))
3061 break; // no more clusters
3065 if ((pos + 1) > avail) {
3067 return E_BUFFER_NOT_FULL;
3070 long long result = GetUIntLength(m_pReader, pos, len);
3072 if (result < 0) // error
3073 return static_cast<long>(result);
3075 if (result > 0) // weird
3076 return E_BUFFER_NOT_FULL;
3078 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3079 return E_FILE_FORMAT_INVALID;
3081 if ((pos + len) > avail)
3082 return E_BUFFER_NOT_FULL;
3084 const long long idpos = pos;
3085 const long long id = ReadID(m_pReader, idpos, len);
3087 if (id < 0) // error (or underflow)
3088 return static_cast<long>(id);
3090 // This is the distinguished set of ID's we use to determine
3091 // that we have exhausted the sub-element's inside the cluster
3092 // whose ID we parsed earlier.
3094 if (id == mkvmuxer::kMkvCluster || id == mkvmuxer::kMkvCues)
3097 pos += len; // consume ID (of sub-element)
3101 if ((pos + 1) > avail) {
3103 return E_BUFFER_NOT_FULL;
3106 result = GetUIntLength(m_pReader, pos, len);
3108 if (result < 0) // error
3109 return static_cast<long>(result);
3111 if (result > 0) // weird
3112 return E_BUFFER_NOT_FULL;
3114 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3115 return E_FILE_FORMAT_INVALID;
3117 if ((pos + len) > avail)
3118 return E_BUFFER_NOT_FULL;
3120 const long long size = ReadUInt(m_pReader, pos, len);
3122 if (size < 0) // error
3123 return static_cast<long>(size);
3125 pos += len; // consume size field of element
3127 // pos now points to start of sub-element's payload
3129 if (size == 0) // weird
3132 const long long unknown_size = (1LL << (7 * len)) - 1;
3134 if (size == unknown_size)
3135 return E_FILE_FORMAT_INVALID; // not allowed for sub-elements
3137 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) // weird
3138 return E_FILE_FORMAT_INVALID;
3140 pos += size; // consume payload of sub-element
3141 if (segment_stop >= 0 && pos > segment_stop)
3142 return E_FILE_FORMAT_INVALID;
3143 } // determine cluster size
3145 cluster_size = pos - payload_pos;
3146 assert(cluster_size >= 0); // TODO: handle cluster_size = 0
3148 pos = payload_pos; // reset and re-parse original cluster
3151 pos += cluster_size; // consume payload
3152 if (segment_stop >= 0 && pos > segment_stop)
3153 return E_FILE_FORMAT_INVALID;
3155 return 2; // try to find a cluster that follows next
3158 const Cluster* Segment::FindCluster(long long time_ns) const {
3159 if ((m_clusters == NULL) || (m_clusterCount <= 0))
3163 Cluster* const pCluster = m_clusters[0];
3165 assert(pCluster->m_index == 0);
3167 if (time_ns <= pCluster->GetTime())
3171 // Binary search of cluster array
3174 long j = m_clusterCount;
3180 //[j, m_clusterCount) > time_ns
3182 const long k = i + (j - i) / 2;
3183 assert(k < m_clusterCount);
3185 Cluster* const pCluster = m_clusters[k];
3187 assert(pCluster->m_index == k);
3189 const long long t = pCluster->GetTime();
3201 assert(i <= m_clusterCount);
3203 const long k = i - 1;
3205 Cluster* const pCluster = m_clusters[k];
3207 assert(pCluster->m_index == k);
3208 assert(pCluster->GetTime() <= time_ns);
3213 const Tracks* Segment::GetTracks() const { return m_pTracks; }
3214 const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
3215 const Cues* Segment::GetCues() const { return m_pCues; }
3216 const Chapters* Segment::GetChapters() const { return m_pChapters; }
3217 const Tags* Segment::GetTags() const { return m_pTags; }
3218 const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3220 long long Segment::GetDuration() const {
3222 return m_pInfo->GetDuration();
3225 Chapters::Chapters(Segment* pSegment, long long payload_start,
3226 long long payload_size, long long element_start,
3227 long long element_size)
3228 : m_pSegment(pSegment),
3229 m_start(payload_start),
3230 m_size(payload_size),
3231 m_element_start(element_start),
3232 m_element_size(element_size),
3235 m_editions_count(0) {}
3237 Chapters::~Chapters() {
3238 while (m_editions_count > 0) {
3239 Edition& e = m_editions[--m_editions_count];
3242 delete[] m_editions;
3245 long Chapters::Parse() {
3246 IMkvReader* const pReader = m_pSegment->m_pReader;
3248 long long pos = m_start; // payload start
3249 const long long stop = pos + m_size; // payload stop
3251 while (pos < stop) {
3254 long status = ParseElementHeader(pReader, pos, stop, id, size);
3256 if (status < 0) // error
3259 if (size == 0) // weird
3262 if (id == mkvmuxer::kMkvEditionEntry) {
3263 status = ParseEdition(pos, size);
3265 if (status < 0) // error
3271 return E_FILE_FORMAT_INVALID;
3275 return E_FILE_FORMAT_INVALID;
3279 int Chapters::GetEditionCount() const { return m_editions_count; }
3281 const Chapters::Edition* Chapters::GetEdition(int idx) const {
3285 if (idx >= m_editions_count)
3288 return m_editions + idx;
3291 bool Chapters::ExpandEditionsArray() {
3292 if (m_editions_size > m_editions_count)
3293 return true; // nothing else to do
3295 const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
3297 Edition* const editions = new (std::nothrow) Edition[size];
3299 if (editions == NULL)
3302 for (int idx = 0; idx < m_editions_count; ++idx) {
3303 m_editions[idx].ShallowCopy(editions[idx]);
3306 delete[] m_editions;
3307 m_editions = editions;
3309 m_editions_size = size;
3313 long Chapters::ParseEdition(long long pos, long long size) {
3314 if (!ExpandEditionsArray())
3317 Edition& e = m_editions[m_editions_count++];
3320 return e.Parse(m_pSegment->m_pReader, pos, size);
3323 Chapters::Edition::Edition() {}
3325 Chapters::Edition::~Edition() {}
3327 int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3329 const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
3333 if (index >= m_atoms_count)
3336 return m_atoms + index;
3339 void Chapters::Edition::Init() {
3345 void Chapters::Edition::ShallowCopy(Edition& rhs) const {
3346 rhs.m_atoms = m_atoms;
3347 rhs.m_atoms_size = m_atoms_size;
3348 rhs.m_atoms_count = m_atoms_count;
3351 void Chapters::Edition::Clear() {
3352 while (m_atoms_count > 0) {
3353 Atom& a = m_atoms[--m_atoms_count];
3363 long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
3365 const long long stop = pos + size;
3367 while (pos < stop) {
3370 long status = ParseElementHeader(pReader, pos, stop, id, size);
3372 if (status < 0) // error
3378 if (id == mkvmuxer::kMkvChapterAtom) {
3379 status = ParseAtom(pReader, pos, size);
3381 if (status < 0) // error
3387 return E_FILE_FORMAT_INVALID;
3391 return E_FILE_FORMAT_INVALID;
3395 long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
3397 if (!ExpandAtomsArray())
3400 Atom& a = m_atoms[m_atoms_count++];
3403 return a.Parse(pReader, pos, size);
3406 bool Chapters::Edition::ExpandAtomsArray() {
3407 if (m_atoms_size > m_atoms_count)
3408 return true; // nothing else to do
3410 const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
3412 Atom* const atoms = new (std::nothrow) Atom[size];
3417 for (int idx = 0; idx < m_atoms_count; ++idx) {
3418 m_atoms[idx].ShallowCopy(atoms[idx]);
3424 m_atoms_size = size;
3428 Chapters::Atom::Atom() {}
3430 Chapters::Atom::~Atom() {}
3432 unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
3434 const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
3436 long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
3438 long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
3440 long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
3441 return GetTime(pChapters, m_start_timecode);
3444 long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
3445 return GetTime(pChapters, m_stop_timecode);
3448 int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
3450 const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
3454 if (index >= m_displays_count)
3457 return m_displays + index;
3460 void Chapters::Atom::Init() {
3461 m_string_uid = NULL;
3463 m_start_timecode = -1;
3464 m_stop_timecode = -1;
3467 m_displays_size = 0;
3468 m_displays_count = 0;
3471 void Chapters::Atom::ShallowCopy(Atom& rhs) const {
3472 rhs.m_string_uid = m_string_uid;
3474 rhs.m_start_timecode = m_start_timecode;
3475 rhs.m_stop_timecode = m_stop_timecode;
3477 rhs.m_displays = m_displays;
3478 rhs.m_displays_size = m_displays_size;
3479 rhs.m_displays_count = m_displays_count;
3482 void Chapters::Atom::Clear() {
3483 delete[] m_string_uid;
3484 m_string_uid = NULL;
3486 while (m_displays_count > 0) {
3487 Display& d = m_displays[--m_displays_count];
3491 delete[] m_displays;
3494 m_displays_size = 0;
3497 long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
3498 const long long stop = pos + size;
3500 while (pos < stop) {
3503 long status = ParseElementHeader(pReader, pos, stop, id, size);
3505 if (status < 0) // error
3508 if (size == 0) // 0 length payload, skip.
3511 if (id == mkvmuxer::kMkvChapterDisplay) {
3512 status = ParseDisplay(pReader, pos, size);
3514 if (status < 0) // error
3516 } else if (id == mkvmuxer::kMkvChapterStringUID) {
3517 status = UnserializeString(pReader, pos, size, m_string_uid);
3519 if (status < 0) // error
3521 } else if (id == mkvmuxer::kMkvChapterUID) {
3523 status = UnserializeInt(pReader, pos, size, val);
3525 if (status < 0) // error
3528 m_uid = static_cast<unsigned long long>(val);
3529 } else if (id == mkvmuxer::kMkvChapterTimeStart) {
3530 const long long val = UnserializeUInt(pReader, pos, size);
3532 if (val < 0) // error
3533 return static_cast<long>(val);
3535 m_start_timecode = val;
3536 } else if (id == mkvmuxer::kMkvChapterTimeEnd) {
3537 const long long val = UnserializeUInt(pReader, pos, size);
3539 if (val < 0) // error
3540 return static_cast<long>(val);
3542 m_stop_timecode = val;
3547 return E_FILE_FORMAT_INVALID;
3551 return E_FILE_FORMAT_INVALID;
3555 long long Chapters::Atom::GetTime(const Chapters* pChapters,
3556 long long timecode) {
3557 if (pChapters == NULL)
3560 Segment* const pSegment = pChapters->m_pSegment;
3562 if (pSegment == NULL) // weird
3565 const SegmentInfo* const pInfo = pSegment->GetInfo();
3570 const long long timecode_scale = pInfo->GetTimeCodeScale();
3572 if (timecode_scale < 1) // weird
3578 const long long result = timecode_scale * timecode;
3583 long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
3585 if (!ExpandDisplaysArray())
3588 Display& d = m_displays[m_displays_count++];
3591 return d.Parse(pReader, pos, size);
3594 bool Chapters::Atom::ExpandDisplaysArray() {
3595 if (m_displays_size > m_displays_count)
3596 return true; // nothing else to do
3598 const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
3600 Display* const displays = new (std::nothrow) Display[size];
3602 if (displays == NULL)
3605 for (int idx = 0; idx < m_displays_count; ++idx) {
3606 m_displays[idx].ShallowCopy(displays[idx]);
3609 delete[] m_displays;
3610 m_displays = displays;
3612 m_displays_size = size;
3616 Chapters::Display::Display() {}
3618 Chapters::Display::~Display() {}
3620 const char* Chapters::Display::GetString() const { return m_string; }
3622 const char* Chapters::Display::GetLanguage() const { return m_language; }
3624 const char* Chapters::Display::GetCountry() const { return m_country; }
3626 void Chapters::Display::Init() {
3632 void Chapters::Display::ShallowCopy(Display& rhs) const {
3633 rhs.m_string = m_string;
3634 rhs.m_language = m_language;
3635 rhs.m_country = m_country;
3638 void Chapters::Display::Clear() {
3642 delete[] m_language;
3649 long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
3651 const long long stop = pos + size;
3653 while (pos < stop) {
3656 long status = ParseElementHeader(pReader, pos, stop, id, size);
3658 if (status < 0) // error
3661 if (size == 0) // No payload.
3664 if (id == mkvmuxer::kMkvChapString) {
3665 status = UnserializeString(pReader, pos, size, m_string);
3669 } else if (id == mkvmuxer::kMkvChapLanguage) {
3670 status = UnserializeString(pReader, pos, size, m_language);
3674 } else if (id == mkvmuxer::kMkvChapCountry) {
3675 status = UnserializeString(pReader, pos, size, m_country);
3683 return E_FILE_FORMAT_INVALID;
3687 return E_FILE_FORMAT_INVALID;
3691 Tags::Tags(Segment* pSegment, long long payload_start, long long payload_size,
3692 long long element_start, long long element_size)
3693 : m_pSegment(pSegment),
3694 m_start(payload_start),
3695 m_size(payload_size),
3696 m_element_start(element_start),
3697 m_element_size(element_size),
3703 while (m_tags_count > 0) {
3704 Tag& t = m_tags[--m_tags_count];
3710 long Tags::Parse() {
3711 IMkvReader* const pReader = m_pSegment->m_pReader;
3713 long long pos = m_start; // payload start
3714 const long long stop = pos + m_size; // payload stop
3716 while (pos < stop) {
3719 long status = ParseElementHeader(pReader, pos, stop, id, size);
3724 if (size == 0) // 0 length tag, read another
3727 if (id == mkvmuxer::kMkvTag) {
3728 status = ParseTag(pos, size);
3736 return E_FILE_FORMAT_INVALID;
3740 return E_FILE_FORMAT_INVALID;
3745 int Tags::GetTagCount() const { return m_tags_count; }
3747 const Tags::Tag* Tags::GetTag(int idx) const {
3751 if (idx >= m_tags_count)
3754 return m_tags + idx;
3757 bool Tags::ExpandTagsArray() {
3758 if (m_tags_size > m_tags_count)
3759 return true; // nothing else to do
3761 const int size = (m_tags_size == 0) ? 1 : 2 * m_tags_size;
3763 Tag* const tags = new (std::nothrow) Tag[size];
3768 for (int idx = 0; idx < m_tags_count; ++idx) {
3769 m_tags[idx].ShallowCopy(tags[idx]);
3779 long Tags::ParseTag(long long pos, long long size) {
3780 if (!ExpandTagsArray())
3783 Tag& t = m_tags[m_tags_count++];
3786 return t.Parse(m_pSegment->m_pReader, pos, size);
3791 Tags::Tag::~Tag() {}
3793 int Tags::Tag::GetSimpleTagCount() const { return m_simple_tags_count; }
3795 const Tags::SimpleTag* Tags::Tag::GetSimpleTag(int index) const {
3799 if (index >= m_simple_tags_count)
3802 return m_simple_tags + index;
3805 void Tags::Tag::Init() {
3806 m_simple_tags = NULL;
3807 m_simple_tags_size = 0;
3808 m_simple_tags_count = 0;
3811 void Tags::Tag::ShallowCopy(Tag& rhs) const {
3812 rhs.m_simple_tags = m_simple_tags;
3813 rhs.m_simple_tags_size = m_simple_tags_size;
3814 rhs.m_simple_tags_count = m_simple_tags_count;
3817 void Tags::Tag::Clear() {
3818 while (m_simple_tags_count > 0) {
3819 SimpleTag& d = m_simple_tags[--m_simple_tags_count];
3823 delete[] m_simple_tags;
3824 m_simple_tags = NULL;
3826 m_simple_tags_size = 0;
3829 long Tags::Tag::Parse(IMkvReader* pReader, long long pos, long long size) {
3830 const long long stop = pos + size;
3832 while (pos < stop) {
3835 long status = ParseElementHeader(pReader, pos, stop, id, size);
3840 if (size == 0) // 0 length tag, read another
3843 if (id == mkvmuxer::kMkvSimpleTag) {
3844 status = ParseSimpleTag(pReader, pos, size);
3852 return E_FILE_FORMAT_INVALID;
3856 return E_FILE_FORMAT_INVALID;
3860 long Tags::Tag::ParseSimpleTag(IMkvReader* pReader, long long pos,
3862 if (!ExpandSimpleTagsArray())
3865 SimpleTag& st = m_simple_tags[m_simple_tags_count++];
3868 return st.Parse(pReader, pos, size);
3871 bool Tags::Tag::ExpandSimpleTagsArray() {
3872 if (m_simple_tags_size > m_simple_tags_count)
3873 return true; // nothing else to do
3875 const int size = (m_simple_tags_size == 0) ? 1 : 2 * m_simple_tags_size;
3877 SimpleTag* const displays = new (std::nothrow) SimpleTag[size];
3879 if (displays == NULL)
3882 for (int idx = 0; idx < m_simple_tags_count; ++idx) {
3883 m_simple_tags[idx].ShallowCopy(displays[idx]);
3886 delete[] m_simple_tags;
3887 m_simple_tags = displays;
3889 m_simple_tags_size = size;
3893 Tags::SimpleTag::SimpleTag() {}
3895 Tags::SimpleTag::~SimpleTag() {}
3897 const char* Tags::SimpleTag::GetTagName() const { return m_tag_name; }
3899 const char* Tags::SimpleTag::GetTagString() const { return m_tag_string; }
3901 void Tags::SimpleTag::Init() {
3903 m_tag_string = NULL;
3906 void Tags::SimpleTag::ShallowCopy(SimpleTag& rhs) const {
3907 rhs.m_tag_name = m_tag_name;
3908 rhs.m_tag_string = m_tag_string;
3911 void Tags::SimpleTag::Clear() {
3912 delete[] m_tag_name;
3915 delete[] m_tag_string;
3916 m_tag_string = NULL;
3919 long Tags::SimpleTag::Parse(IMkvReader* pReader, long long pos,
3921 const long long stop = pos + size;
3923 while (pos < stop) {
3926 long status = ParseElementHeader(pReader, pos, stop, id, size);
3928 if (status < 0) // error
3931 if (size == 0) // weird
3934 if (id == mkvmuxer::kMkvTagName) {
3935 status = UnserializeString(pReader, pos, size, m_tag_name);
3939 } else if (id == mkvmuxer::kMkvTagString) {
3940 status = UnserializeString(pReader, pos, size, m_tag_string);
3948 return E_FILE_FORMAT_INVALID;
3952 return E_FILE_FORMAT_INVALID;
3956 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
3957 long long element_start, long long element_size)
3958 : m_pSegment(pSegment),
3961 m_element_start(element_start),
3962 m_element_size(element_size),
3963 m_pMuxingAppAsUTF8(NULL),
3964 m_pWritingAppAsUTF8(NULL),
3965 m_pTitleAsUTF8(NULL) {}
3967 SegmentInfo::~SegmentInfo() {
3968 delete[] m_pMuxingAppAsUTF8;
3969 m_pMuxingAppAsUTF8 = NULL;
3971 delete[] m_pWritingAppAsUTF8;
3972 m_pWritingAppAsUTF8 = NULL;
3974 delete[] m_pTitleAsUTF8;
3975 m_pTitleAsUTF8 = NULL;
3978 long SegmentInfo::Parse() {
3979 assert(m_pMuxingAppAsUTF8 == NULL);
3980 assert(m_pWritingAppAsUTF8 == NULL);
3981 assert(m_pTitleAsUTF8 == NULL);
3983 IMkvReader* const pReader = m_pSegment->m_pReader;
3985 long long pos = m_start;
3986 const long long stop = m_start + m_size;
3988 m_timecodeScale = 1000000;
3991 while (pos < stop) {
3994 const long status = ParseElementHeader(pReader, pos, stop, id, size);
3996 if (status < 0) // error
3999 if (id == mkvmuxer::kMkvTimecodeScale) {
4000 m_timecodeScale = UnserializeUInt(pReader, pos, size);
4002 if (m_timecodeScale <= 0)
4003 return E_FILE_FORMAT_INVALID;
4004 } else if (id == mkvmuxer::kMkvDuration) {
4005 const long status = UnserializeFloat(pReader, pos, size, m_duration);
4011 return E_FILE_FORMAT_INVALID;
4012 } else if (id == mkvmuxer::kMkvMuxingApp) {
4014 UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
4018 } else if (id == mkvmuxer::kMkvWritingApp) {
4020 UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
4024 } else if (id == mkvmuxer::kMkvTitle) {
4025 const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
4034 return E_FILE_FORMAT_INVALID;
4037 const double rollover_check = m_duration * m_timecodeScale;
4038 if (rollover_check > LLONG_MAX)
4039 return E_FILE_FORMAT_INVALID;
4042 return E_FILE_FORMAT_INVALID;
4047 long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
4049 long long SegmentInfo::GetDuration() const {
4053 assert(m_timecodeScale >= 1);
4055 const double dd = double(m_duration) * double(m_timecodeScale);
4056 const long long d = static_cast<long long>(dd);
4061 const char* SegmentInfo::GetMuxingAppAsUTF8() const {
4062 return m_pMuxingAppAsUTF8;
4065 const char* SegmentInfo::GetWritingAppAsUTF8() const {
4066 return m_pWritingAppAsUTF8;
4069 const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
4071 ///////////////////////////////////////////////////////////////
4072 // ContentEncoding element
4073 ContentEncoding::ContentCompression::ContentCompression()
4074 : algo(0), settings(NULL), settings_len(0) {}
4076 ContentEncoding::ContentCompression::~ContentCompression() {
4080 ContentEncoding::ContentEncryption::ContentEncryption()
4091 ContentEncoding::ContentEncryption::~ContentEncryption() {
4094 delete[] sig_key_id;
4097 ContentEncoding::ContentEncoding()
4098 : compression_entries_(NULL),
4099 compression_entries_end_(NULL),
4100 encryption_entries_(NULL),
4101 encryption_entries_end_(NULL),
4104 encoding_type_(0) {}
4106 ContentEncoding::~ContentEncoding() {
4107 ContentCompression** comp_i = compression_entries_;
4108 ContentCompression** const comp_j = compression_entries_end_;
4110 while (comp_i != comp_j) {
4111 ContentCompression* const comp = *comp_i++;
4115 delete[] compression_entries_;
4117 ContentEncryption** enc_i = encryption_entries_;
4118 ContentEncryption** const enc_j = encryption_entries_end_;
4120 while (enc_i != enc_j) {
4121 ContentEncryption* const enc = *enc_i++;
4125 delete[] encryption_entries_;
4128 const ContentEncoding::ContentCompression*
4129 ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
4130 const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4133 if (idx >= static_cast<unsigned long>(count))
4136 return compression_entries_[idx];
4139 unsigned long ContentEncoding::GetCompressionCount() const {
4140 const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4143 return static_cast<unsigned long>(count);
4146 const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
4147 unsigned long idx) const {
4148 const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4151 if (idx >= static_cast<unsigned long>(count))
4154 return encryption_entries_[idx];
4157 unsigned long ContentEncoding::GetEncryptionCount() const {
4158 const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4161 return static_cast<unsigned long>(count);
4164 long ContentEncoding::ParseContentEncAESSettingsEntry(
4165 long long start, long long size, IMkvReader* pReader,
4166 ContentEncAESSettings* aes) {
4170 long long pos = start;
4171 const long long stop = start + size;
4173 while (pos < stop) {
4175 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4176 if (status < 0) // error
4179 if (id == mkvmuxer::kMkvAESSettingsCipherMode) {
4180 aes->cipher_mode = UnserializeUInt(pReader, pos, size);
4181 if (aes->cipher_mode != 1)
4182 return E_FILE_FORMAT_INVALID;
4185 pos += size; // consume payload
4187 return E_FILE_FORMAT_INVALID;
4193 long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
4194 IMkvReader* pReader) {
4197 long long pos = start;
4198 const long long stop = start + size;
4200 // Count ContentCompression and ContentEncryption elements.
4201 int compression_count = 0;
4202 int encryption_count = 0;
4204 while (pos < stop) {
4206 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4207 if (status < 0) // error
4210 if (id == mkvmuxer::kMkvContentCompression)
4211 ++compression_count;
4213 if (id == mkvmuxer::kMkvContentEncryption)
4216 pos += size; // consume payload
4218 return E_FILE_FORMAT_INVALID;
4221 if (compression_count <= 0 && encryption_count <= 0)
4224 if (compression_count > 0) {
4225 compression_entries_ =
4226 new (std::nothrow) ContentCompression*[compression_count];
4227 if (!compression_entries_)
4229 compression_entries_end_ = compression_entries_;
4232 if (encryption_count > 0) {
4233 encryption_entries_ =
4234 new (std::nothrow) ContentEncryption*[encryption_count];
4235 if (!encryption_entries_) {
4236 delete[] compression_entries_;
4239 encryption_entries_end_ = encryption_entries_;
4243 while (pos < stop) {
4245 long status = ParseElementHeader(pReader, pos, stop, id, size);
4246 if (status < 0) // error
4249 if (id == mkvmuxer::kMkvContentEncodingOrder) {
4250 encoding_order_ = UnserializeUInt(pReader, pos, size);
4251 } else if (id == mkvmuxer::kMkvContentEncodingScope) {
4252 encoding_scope_ = UnserializeUInt(pReader, pos, size);
4253 if (encoding_scope_ < 1)
4255 } else if (id == mkvmuxer::kMkvContentEncodingType) {
4256 encoding_type_ = UnserializeUInt(pReader, pos, size);
4257 } else if (id == mkvmuxer::kMkvContentCompression) {
4258 ContentCompression* const compression =
4259 new (std::nothrow) ContentCompression();
4263 status = ParseCompressionEntry(pos, size, pReader, compression);
4268 *compression_entries_end_++ = compression;
4269 } else if (id == mkvmuxer::kMkvContentEncryption) {
4270 ContentEncryption* const encryption =
4271 new (std::nothrow) ContentEncryption();
4275 status = ParseEncryptionEntry(pos, size, pReader, encryption);
4280 *encryption_entries_end_++ = encryption;
4283 pos += size; // consume payload
4285 return E_FILE_FORMAT_INVALID;
4289 return E_FILE_FORMAT_INVALID;
4293 long ContentEncoding::ParseCompressionEntry(long long start, long long size,
4294 IMkvReader* pReader,
4295 ContentCompression* compression) {
4297 assert(compression);
4299 long long pos = start;
4300 const long long stop = start + size;
4304 while (pos < stop) {
4306 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4307 if (status < 0) // error
4310 if (id == mkvmuxer::kMkvContentCompAlgo) {
4311 long long algo = UnserializeUInt(pReader, pos, size);
4313 return E_FILE_FORMAT_INVALID;
4314 compression->algo = algo;
4316 } else if (id == mkvmuxer::kMkvContentCompSettings) {
4318 return E_FILE_FORMAT_INVALID;
4320 const size_t buflen = static_cast<size_t>(size);
4321 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4325 const int read_status =
4326 pReader->Read(pos, static_cast<long>(buflen), buf);
4332 compression->settings = buf;
4333 compression->settings_len = buflen;
4336 pos += size; // consume payload
4338 return E_FILE_FORMAT_INVALID;
4341 // ContentCompAlgo is mandatory
4343 return E_FILE_FORMAT_INVALID;
4348 long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
4349 IMkvReader* pReader,
4350 ContentEncryption* encryption) {
4354 long long pos = start;
4355 const long long stop = start + size;
4357 while (pos < stop) {
4359 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4360 if (status < 0) // error
4363 if (id == mkvmuxer::kMkvContentEncAlgo) {
4364 encryption->algo = UnserializeUInt(pReader, pos, size);
4365 if (encryption->algo != 5)
4366 return E_FILE_FORMAT_INVALID;
4367 } else if (id == mkvmuxer::kMkvContentEncKeyID) {
4368 delete[] encryption->key_id;
4369 encryption->key_id = NULL;
4370 encryption->key_id_len = 0;
4373 return E_FILE_FORMAT_INVALID;
4375 const size_t buflen = static_cast<size_t>(size);
4376 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4380 const int read_status =
4381 pReader->Read(pos, static_cast<long>(buflen), buf);
4387 encryption->key_id = buf;
4388 encryption->key_id_len = buflen;
4389 } else if (id == mkvmuxer::kMkvContentSignature) {
4390 delete[] encryption->signature;
4391 encryption->signature = NULL;
4392 encryption->signature_len = 0;
4395 return E_FILE_FORMAT_INVALID;
4397 const size_t buflen = static_cast<size_t>(size);
4398 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4402 const int read_status =
4403 pReader->Read(pos, static_cast<long>(buflen), buf);
4409 encryption->signature = buf;
4410 encryption->signature_len = buflen;
4411 } else if (id == mkvmuxer::kMkvContentSigKeyID) {
4412 delete[] encryption->sig_key_id;
4413 encryption->sig_key_id = NULL;
4414 encryption->sig_key_id_len = 0;
4417 return E_FILE_FORMAT_INVALID;
4419 const size_t buflen = static_cast<size_t>(size);
4420 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
4424 const int read_status =
4425 pReader->Read(pos, static_cast<long>(buflen), buf);
4431 encryption->sig_key_id = buf;
4432 encryption->sig_key_id_len = buflen;
4433 } else if (id == mkvmuxer::kMkvContentSigAlgo) {
4434 encryption->sig_algo = UnserializeUInt(pReader, pos, size);
4435 } else if (id == mkvmuxer::kMkvContentSigHashAlgo) {
4436 encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
4437 } else if (id == mkvmuxer::kMkvContentEncAESSettings) {
4438 const long status = ParseContentEncAESSettingsEntry(
4439 pos, size, pReader, &encryption->aes_settings);
4444 pos += size; // consume payload
4446 return E_FILE_FORMAT_INVALID;
4452 Track::Track(Segment* pSegment, long long element_start, long long element_size)
4453 : m_pSegment(pSegment),
4454 m_element_start(element_start),
4455 m_element_size(element_size),
4456 content_encoding_entries_(NULL),
4457 content_encoding_entries_end_(NULL) {}
4460 Info& info = const_cast<Info&>(m_info);
4463 ContentEncoding** i = content_encoding_entries_;
4464 ContentEncoding** const j = content_encoding_entries_end_;
4467 ContentEncoding* const encoding = *i++;
4471 delete[] content_encoding_entries_;
4474 long Track::Create(Segment* pSegment, const Info& info, long long element_start,
4475 long long element_size, Track*& pResult) {
4479 Track* const pTrack =
4480 new (std::nothrow) Track(pSegment, element_start, element_size);
4483 return -1; // generic error
4485 const int status = info.Copy(pTrack->m_info);
4487 if (status) { // error
4493 return 0; // success
4504 codecNameAsUTF8(NULL),
4506 codecPrivateSize(0),
4509 Track::Info::~Info() { Clear(); }
4511 void Track::Info::Clear() {
4512 delete[] nameAsUTF8;
4521 delete[] codecPrivate;
4522 codecPrivate = NULL;
4523 codecPrivateSize = 0;
4525 delete[] codecNameAsUTF8;
4526 codecNameAsUTF8 = NULL;
4529 int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
4530 if (str == static_cast<char * Info::*>(NULL))
4533 char*& dst = dst_.*str;
4535 if (dst) // should be NULL already
4538 const char* const src = this->*str;
4543 const size_t len = strlen(src);
4545 dst = SafeArrayAlloc<char>(1, len + 1);
4555 int Track::Info::Copy(Info& dst) const {
4560 dst.number = number;
4561 dst.defaultDuration = defaultDuration;
4562 dst.codecDelay = codecDelay;
4563 dst.seekPreRoll = seekPreRoll;
4565 dst.lacing = lacing;
4566 dst.settings = settings;
4568 // We now copy the string member variables from src to dst.
4569 // This involves memory allocation so in principle the operation
4570 // can fail (indeed, that's why we have Info::Copy), so we must
4571 // report this to the caller. An error return from this function
4572 // therefore implies that the copy was only partially successful.
4574 if (int status = CopyStr(&Info::nameAsUTF8, dst))
4577 if (int status = CopyStr(&Info::language, dst))
4580 if (int status = CopyStr(&Info::codecId, dst))
4583 if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
4586 if (codecPrivateSize > 0) {
4587 if (codecPrivate == NULL)
4590 if (dst.codecPrivate)
4593 if (dst.codecPrivateSize != 0)
4596 dst.codecPrivate = SafeArrayAlloc<unsigned char>(1, codecPrivateSize);
4598 if (dst.codecPrivate == NULL)
4601 memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
4602 dst.codecPrivateSize = codecPrivateSize;
4608 const BlockEntry* Track::GetEOS() const { return &m_eos; }
4610 long Track::GetType() const { return m_info.type; }
4612 long Track::GetNumber() const { return m_info.number; }
4614 unsigned long long Track::GetUid() const { return m_info.uid; }
4616 const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4618 const char* Track::GetLanguage() const { return m_info.language; }
4620 const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4622 const char* Track::GetCodecId() const { return m_info.codecId; }
4624 const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4625 size = m_info.codecPrivateSize;
4626 return m_info.codecPrivate;
4629 bool Track::GetLacing() const { return m_info.lacing; }
4631 unsigned long long Track::GetDefaultDuration() const {
4632 return m_info.defaultDuration;
4635 unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4637 unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4639 long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
4640 const Cluster* pCluster = m_pSegment->GetFirst();
4643 if (pCluster == NULL) {
4644 pBlockEntry = GetEOS();
4648 if (pCluster->EOS()) {
4649 if (m_pSegment->DoneParsing()) {
4650 pBlockEntry = GetEOS();
4655 return E_BUFFER_NOT_FULL;
4658 long status = pCluster->GetFirst(pBlockEntry);
4660 if (status < 0) // error
4663 if (pBlockEntry == 0) { // empty cluster
4664 pCluster = m_pSegment->GetNext(pCluster);
4669 const Block* const pBlock = pBlockEntry->GetBlock();
4672 const long long tn = pBlock->GetTrackNumber();
4674 if ((tn == m_info.number) && VetEntry(pBlockEntry))
4677 const BlockEntry* pNextEntry;
4679 status = pCluster->GetNext(pBlockEntry, pNextEntry);
4681 if (status < 0) // error
4684 if (pNextEntry == 0)
4687 pBlockEntry = pNextEntry;
4695 pCluster = m_pSegment->GetNext(pCluster);
4698 // NOTE: if we get here, it means that we didn't find a block with
4699 // a matching track number. We interpret that as an error (which
4700 // might be too conservative).
4702 pBlockEntry = GetEOS(); // so we can return a non-NULL value
4706 long Track::GetNext(const BlockEntry* pCurrEntry,
4707 const BlockEntry*& pNextEntry) const {
4709 assert(!pCurrEntry->EOS()); //?
4711 const Block* const pCurrBlock = pCurrEntry->GetBlock();
4712 assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
4713 if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
4716 const Cluster* pCluster = pCurrEntry->GetCluster();
4718 assert(!pCluster->EOS());
4720 long status = pCluster->GetNext(pCurrEntry, pNextEntry);
4722 if (status < 0) // error
4726 while (pNextEntry) {
4727 const Block* const pNextBlock = pNextEntry->GetBlock();
4730 if (pNextBlock->GetTrackNumber() == m_info.number)
4733 pCurrEntry = pNextEntry;
4735 status = pCluster->GetNext(pCurrEntry, pNextEntry);
4737 if (status < 0) // error
4741 pCluster = m_pSegment->GetNext(pCluster);
4743 if (pCluster == NULL) {
4744 pNextEntry = GetEOS();
4748 if (pCluster->EOS()) {
4749 if (m_pSegment->DoneParsing()) {
4750 pNextEntry = GetEOS();
4754 // TODO: there is a potential O(n^2) problem here: we tell the
4755 // caller to (pre)load another cluster, which he does, but then he
4756 // calls GetNext again, which repeats the same search. This is
4757 // a pathological case, since the only way it can happen is if
4758 // there exists a long sequence of clusters none of which contain a
4759 // block from this track. One way around this problem is for the
4760 // caller to be smarter when he loads another cluster: don't call
4761 // us back until you have a cluster that contains a block from this
4762 // track. (Of course, that's not cheap either, since our caller
4763 // would have to scan the each cluster as it's loaded, so that
4764 // would just push back the problem.)
4767 return E_BUFFER_NOT_FULL;
4770 status = pCluster->GetFirst(pNextEntry);
4772 if (status < 0) // error
4775 if (pNextEntry == NULL) // empty cluster
4784 // NOTE: if we get here, it means that we didn't find a block with
4785 // a matching track number after lots of searching, so we give
4788 pNextEntry = GetEOS(); // so we can return a non-NULL value
4792 bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
4793 assert(pBlockEntry);
4794 const Block* const pBlock = pBlockEntry->GetBlock();
4796 assert(pBlock->GetTrackNumber() == m_info.number);
4797 if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
4800 // This function is used during a seek to determine whether the
4801 // frame is a valid seek target. This default function simply
4802 // returns true, which means all frames are valid seek targets.
4803 // It gets overridden by the VideoTrack class, because only video
4804 // keyframes can be used as seek target.
4809 long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
4810 const long status = GetFirst(pResult);
4812 if (status < 0) // buffer underflow, etc
4820 const Cluster* pCluster = pResult->GetCluster();
4822 assert(pCluster->GetIndex() >= 0);
4824 if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
4827 Cluster** const clusters = m_pSegment->m_clusters;
4830 const long count = m_pSegment->GetCount(); // loaded only, not preloaded
4833 Cluster** const i = clusters + pCluster->GetIndex();
4835 assert(*i == pCluster);
4836 assert(pCluster->GetTime() <= time_ns);
4838 Cluster** const j = clusters + count;
4845 //[i, lo) <= time_ns
4849 Cluster** const mid = lo + (hi - lo) / 2;
4854 assert(pCluster->GetIndex() >= 0);
4855 assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
4857 const long long t = pCluster->GetTime();
4874 assert(pCluster->GetTime() <= time_ns);
4876 pResult = pCluster->GetEntry(this);
4878 if ((pResult != 0) && !pResult->EOS())
4881 // landed on empty cluster (no entries)
4884 pResult = GetEOS(); // weird
4888 const ContentEncoding* Track::GetContentEncodingByIndex(
4889 unsigned long idx) const {
4890 const ptrdiff_t count =
4891 content_encoding_entries_end_ - content_encoding_entries_;
4894 if (idx >= static_cast<unsigned long>(count))
4897 return content_encoding_entries_[idx];
4900 unsigned long Track::GetContentEncodingCount() const {
4901 const ptrdiff_t count =
4902 content_encoding_entries_end_ - content_encoding_entries_;
4905 return static_cast<unsigned long>(count);
4908 long Track::ParseContentEncodingsEntry(long long start, long long size) {
4909 IMkvReader* const pReader = m_pSegment->m_pReader;
4912 long long pos = start;
4913 const long long stop = start + size;
4915 // Count ContentEncoding elements.
4917 while (pos < stop) {
4919 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4920 if (status < 0) // error
4923 // pos now designates start of element
4924 if (id == mkvmuxer::kMkvContentEncoding)
4927 pos += size; // consume payload
4929 return E_FILE_FORMAT_INVALID;
4935 content_encoding_entries_ = new (std::nothrow) ContentEncoding*[count];
4936 if (!content_encoding_entries_)
4939 content_encoding_entries_end_ = content_encoding_entries_;
4942 while (pos < stop) {
4944 long status = ParseElementHeader(pReader, pos, stop, id, size);
4945 if (status < 0) // error
4948 // pos now designates start of element
4949 if (id == mkvmuxer::kMkvContentEncoding) {
4950 ContentEncoding* const content_encoding =
4951 new (std::nothrow) ContentEncoding();
4952 if (!content_encoding)
4955 status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
4957 delete content_encoding;
4961 *content_encoding_entries_end_++ = content_encoding;
4964 pos += size; // consume payload
4966 return E_FILE_FORMAT_INVALID;
4970 return E_FILE_FORMAT_INVALID;
4975 Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
4977 BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
4979 const Block* Track::EOSBlock::GetBlock() const { return NULL; }
4981 VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
4982 long long element_size)
4983 : Track(pSegment, element_start, element_size) {}
4985 long VideoTrack::Parse(Segment* pSegment, const Info& info,
4986 long long element_start, long long element_size,
4987 VideoTrack*& pResult) {
4991 if (info.type != Track::kVideo)
4994 long long width = 0;
4995 long long height = 0;
4996 long long display_width = 0;
4997 long long display_height = 0;
4998 long long display_unit = 0;
4999 long long stereo_mode = 0;
5003 IMkvReader* const pReader = pSegment->m_pReader;
5005 const Settings& s = info.settings;
5006 assert(s.start >= 0);
5007 assert(s.size >= 0);
5009 long long pos = s.start;
5012 const long long stop = pos + s.size;
5014 while (pos < stop) {
5017 const long status = ParseElementHeader(pReader, pos, stop, id, size);
5019 if (status < 0) // error
5022 if (id == mkvmuxer::kMkvPixelWidth) {
5023 width = UnserializeUInt(pReader, pos, size);
5026 return E_FILE_FORMAT_INVALID;
5027 } else if (id == mkvmuxer::kMkvPixelHeight) {
5028 height = UnserializeUInt(pReader, pos, size);
5031 return E_FILE_FORMAT_INVALID;
5032 } else if (id == mkvmuxer::kMkvDisplayWidth) {
5033 display_width = UnserializeUInt(pReader, pos, size);
5035 if (display_width <= 0)
5036 return E_FILE_FORMAT_INVALID;
5037 } else if (id == mkvmuxer::kMkvDisplayHeight) {
5038 display_height = UnserializeUInt(pReader, pos, size);
5040 if (display_height <= 0)
5041 return E_FILE_FORMAT_INVALID;
5042 } else if (id == mkvmuxer::kMkvDisplayUnit) {
5043 display_unit = UnserializeUInt(pReader, pos, size);
5045 if (display_unit < 0)
5046 return E_FILE_FORMAT_INVALID;
5047 } else if (id == mkvmuxer::kMkvStereoMode) {
5048 stereo_mode = UnserializeUInt(pReader, pos, size);
5050 if (stereo_mode < 0)
5051 return E_FILE_FORMAT_INVALID;
5052 } else if (id == mkvmuxer::kMkvFrameRate) {
5053 const long status = UnserializeFloat(pReader, pos, size, rate);
5059 return E_FILE_FORMAT_INVALID;
5062 pos += size; // consume payload
5064 return E_FILE_FORMAT_INVALID;
5068 return E_FILE_FORMAT_INVALID;
5070 VideoTrack* const pTrack =
5071 new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
5074 return -1; // generic error
5076 const int status = info.Copy(pTrack->m_info);
5078 if (status) { // error
5083 pTrack->m_width = width;
5084 pTrack->m_height = height;
5085 pTrack->m_display_width = display_width;
5086 pTrack->m_display_height = display_height;
5087 pTrack->m_display_unit = display_unit;
5088 pTrack->m_stereo_mode = stereo_mode;
5089 pTrack->m_rate = rate;
5092 return 0; // success
5095 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
5096 return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
5099 long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
5100 const long status = GetFirst(pResult);
5102 if (status < 0) // buffer underflow, etc
5110 const Cluster* pCluster = pResult->GetCluster();
5112 assert(pCluster->GetIndex() >= 0);
5114 if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5117 Cluster** const clusters = m_pSegment->m_clusters;
5120 const long count = m_pSegment->GetCount(); // loaded only, not pre-loaded
5123 Cluster** const i = clusters + pCluster->GetIndex();
5125 assert(*i == pCluster);
5126 assert(pCluster->GetTime() <= time_ns);
5128 Cluster** const j = clusters + count;
5135 //[i, lo) <= time_ns
5139 Cluster** const mid = lo + (hi - lo) / 2;
5144 assert(pCluster->GetIndex() >= 0);
5145 assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5147 const long long t = pCluster->GetTime();
5163 assert(pCluster->GetTime() <= time_ns);
5165 pResult = pCluster->GetEntry(this, time_ns);
5167 if ((pResult != 0) && !pResult->EOS()) // found a keyframe
5173 assert(pCluster->GetTime() <= time_ns);
5175 pResult = pCluster->GetEntry(this, time_ns);
5177 if ((pResult != 0) && !pResult->EOS())
5181 // weird: we're on the first cluster, but no keyframe found
5182 // should never happen but we must return something anyway
5188 long long VideoTrack::GetWidth() const { return m_width; }
5190 long long VideoTrack::GetHeight() const { return m_height; }
5192 long long VideoTrack::GetDisplayWidth() const {
5193 return m_display_width > 0 ? m_display_width : GetWidth();
5196 long long VideoTrack::GetDisplayHeight() const {
5197 return m_display_height > 0 ? m_display_height : GetHeight();
5200 long long VideoTrack::GetDisplayUnit() const { return m_display_unit; }
5202 long long VideoTrack::GetStereoMode() const { return m_stereo_mode; }
5204 double VideoTrack::GetFrameRate() const { return m_rate; }
5206 AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5207 long long element_size)
5208 : Track(pSegment, element_start, element_size) {}
5210 long AudioTrack::Parse(Segment* pSegment, const Info& info,
5211 long long element_start, long long element_size,
5212 AudioTrack*& pResult) {
5216 if (info.type != Track::kAudio)
5219 IMkvReader* const pReader = pSegment->m_pReader;
5221 const Settings& s = info.settings;
5222 assert(s.start >= 0);
5223 assert(s.size >= 0);
5225 long long pos = s.start;
5228 const long long stop = pos + s.size;
5230 double rate = 8000.0; // MKV default
5231 long long channels = 1;
5232 long long bit_depth = 0;
5234 while (pos < stop) {
5237 long status = ParseElementHeader(pReader, pos, stop, id, size);
5239 if (status < 0) // error
5242 if (id == mkvmuxer::kMkvSamplingFrequency) {
5243 status = UnserializeFloat(pReader, pos, size, rate);
5249 return E_FILE_FORMAT_INVALID;
5250 } else if (id == mkvmuxer::kMkvChannels) {
5251 channels = UnserializeUInt(pReader, pos, size);
5254 return E_FILE_FORMAT_INVALID;
5255 } else if (id == mkvmuxer::kMkvBitDepth) {
5256 bit_depth = UnserializeUInt(pReader, pos, size);
5259 return E_FILE_FORMAT_INVALID;
5262 pos += size; // consume payload
5264 return E_FILE_FORMAT_INVALID;
5268 return E_FILE_FORMAT_INVALID;
5270 AudioTrack* const pTrack =
5271 new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
5274 return -1; // generic error
5276 const int status = info.Copy(pTrack->m_info);
5283 pTrack->m_rate = rate;
5284 pTrack->m_channels = channels;
5285 pTrack->m_bitDepth = bit_depth;
5288 return 0; // success
5291 double AudioTrack::GetSamplingRate() const { return m_rate; }
5293 long long AudioTrack::GetChannels() const { return m_channels; }
5295 long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5297 Tracks::Tracks(Segment* pSegment, long long start, long long size_,
5298 long long element_start, long long element_size)
5299 : m_pSegment(pSegment),
5302 m_element_start(element_start),
5303 m_element_size(element_size),
5304 m_trackEntries(NULL),
5305 m_trackEntriesEnd(NULL) {}
5307 long Tracks::Parse() {
5308 assert(m_trackEntries == NULL);
5309 assert(m_trackEntriesEnd == NULL);
5311 const long long stop = m_start + m_size;
5312 IMkvReader* const pReader = m_pSegment->m_pReader;
5315 long long pos = m_start;
5317 while (pos < stop) {
5320 const long status = ParseElementHeader(pReader, pos, stop, id, size);
5322 if (status < 0) // error
5325 if (size == 0) // weird
5328 if (id == mkvmuxer::kMkvTrackEntry)
5331 pos += size; // consume payload
5333 return E_FILE_FORMAT_INVALID;
5337 return E_FILE_FORMAT_INVALID;
5340 return 0; // success
5342 m_trackEntries = new (std::nothrow) Track*[count];
5344 if (m_trackEntries == NULL)
5347 m_trackEntriesEnd = m_trackEntries;
5351 while (pos < stop) {
5352 const long long element_start = pos;
5354 long long id, payload_size;
5357 ParseElementHeader(pReader, pos, stop, id, payload_size);
5359 if (status < 0) // error
5362 if (payload_size == 0) // weird
5365 const long long payload_stop = pos + payload_size;
5366 assert(payload_stop <= stop); // checked in ParseElement
5368 const long long element_size = payload_stop - element_start;
5370 if (id == mkvmuxer::kMkvTrackEntry) {
5371 Track*& pTrack = *m_trackEntriesEnd;
5374 const long status = ParseTrackEntry(pos, payload_size, element_start,
5375 element_size, pTrack);
5380 ++m_trackEntriesEnd;
5385 return E_FILE_FORMAT_INVALID;
5389 return E_FILE_FORMAT_INVALID;
5391 return 0; // success
5394 unsigned long Tracks::GetTracksCount() const {
5395 const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
5396 assert(result >= 0);
5398 return static_cast<unsigned long>(result);
5401 long Tracks::ParseTrackEntry(long long track_start, long long track_size,
5402 long long element_start, long long element_size,
5403 Track*& pResult) const {
5407 IMkvReader* const pReader = m_pSegment->m_pReader;
5409 long long pos = track_start;
5410 const long long track_stop = track_start + track_size;
5417 info.defaultDuration = 0;
5427 Track::Settings e; // content_encodings_settings;
5431 long long lacing = 1; // default is true
5433 while (pos < track_stop) {
5436 const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
5438 if (status < 0) // error
5442 return E_FILE_FORMAT_INVALID;
5444 const long long start = pos;
5446 if (id == mkvmuxer::kMkvVideo) {
5449 } else if (id == mkvmuxer::kMkvAudio) {
5452 } else if (id == mkvmuxer::kMkvContentEncodings) {
5455 } else if (id == mkvmuxer::kMkvTrackUID) {
5457 return E_FILE_FORMAT_INVALID;
5461 long long pos_ = start;
5462 const long long pos_end = start + size;
5464 while (pos_ != pos_end) {
5467 const int status = pReader->Read(pos_, 1, &b);
5477 } else if (id == mkvmuxer::kMkvTrackNumber) {
5478 const long long num = UnserializeUInt(pReader, pos, size);
5480 if ((num <= 0) || (num > 127))
5481 return E_FILE_FORMAT_INVALID;
5483 info.number = static_cast<long>(num);
5484 } else if (id == mkvmuxer::kMkvTrackType) {
5485 const long long type = UnserializeUInt(pReader, pos, size);
5487 if ((type <= 0) || (type > 254))
5488 return E_FILE_FORMAT_INVALID;
5490 info.type = static_cast<long>(type);
5491 } else if (id == mkvmuxer::kMkvName) {
5493 UnserializeString(pReader, pos, size, info.nameAsUTF8);
5497 } else if (id == mkvmuxer::kMkvLanguage) {
5498 const long status = UnserializeString(pReader, pos, size, info.language);
5502 } else if (id == mkvmuxer::kMkvDefaultDuration) {
5503 const long long duration = UnserializeUInt(pReader, pos, size);
5506 return E_FILE_FORMAT_INVALID;
5508 info.defaultDuration = static_cast<unsigned long long>(duration);
5509 } else if (id == mkvmuxer::kMkvCodecID) {
5510 const long status = UnserializeString(pReader, pos, size, info.codecId);
5514 } else if (id == mkvmuxer::kMkvFlagLacing) {
5515 lacing = UnserializeUInt(pReader, pos, size);
5517 if ((lacing < 0) || (lacing > 1))
5518 return E_FILE_FORMAT_INVALID;
5519 } else if (id == mkvmuxer::kMkvCodecPrivate) {
5520 delete[] info.codecPrivate;
5521 info.codecPrivate = NULL;
5522 info.codecPrivateSize = 0;
5524 const size_t buflen = static_cast<size_t>(size);
5527 unsigned char* buf = SafeArrayAlloc<unsigned char>(1, buflen);
5532 const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
5539 info.codecPrivate = buf;
5540 info.codecPrivateSize = buflen;
5542 } else if (id == mkvmuxer::kMkvCodecName) {
5544 UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
5548 } else if (id == mkvmuxer::kMkvCodecDelay) {
5549 info.codecDelay = UnserializeUInt(pReader, pos, size);
5550 } else if (id == mkvmuxer::kMkvSeekPreRoll) {
5551 info.seekPreRoll = UnserializeUInt(pReader, pos, size);
5554 pos += size; // consume payload
5555 if (pos > track_stop)
5556 return E_FILE_FORMAT_INVALID;
5559 if (pos != track_stop)
5560 return E_FILE_FORMAT_INVALID;
5562 if (info.number <= 0) // not specified
5563 return E_FILE_FORMAT_INVALID;
5565 if (GetTrackByNumber(info.number))
5566 return E_FILE_FORMAT_INVALID;
5568 if (info.type <= 0) // not specified
5569 return E_FILE_FORMAT_INVALID;
5571 info.lacing = (lacing > 0) ? true : false;
5573 if (info.type == Track::kVideo) {
5575 return E_FILE_FORMAT_INVALID;
5578 return E_FILE_FORMAT_INVALID;
5582 VideoTrack* pTrack = NULL;
5584 const long status = VideoTrack::Parse(m_pSegment, info, element_start,
5585 element_size, pTrack);
5594 pResult->ParseContentEncodingsEntry(e.start, e.size);
5595 } else if (info.type == Track::kAudio) {
5597 return E_FILE_FORMAT_INVALID;
5600 return E_FILE_FORMAT_INVALID;
5604 AudioTrack* pTrack = NULL;
5606 const long status = AudioTrack::Parse(m_pSegment, info, element_start,
5607 element_size, pTrack);
5616 pResult->ParseContentEncodingsEntry(e.start, e.size);
5618 // neither video nor audio - probably metadata or subtitles
5621 return E_FILE_FORMAT_INVALID;
5624 return E_FILE_FORMAT_INVALID;
5626 if (info.type == Track::kMetadata && e.start >= 0)
5627 return E_FILE_FORMAT_INVALID;
5629 info.settings.start = -1;
5630 info.settings.size = 0;
5632 Track* pTrack = NULL;
5635 Track::Create(m_pSegment, info, element_start, element_size, pTrack);
5644 return 0; // success
5648 Track** i = m_trackEntries;
5649 Track** const j = m_trackEntriesEnd;
5652 Track* const pTrack = *i++;
5656 delete[] m_trackEntries;
5659 const Track* Tracks::GetTrackByNumber(long tn) const {
5663 Track** i = m_trackEntries;
5664 Track** const j = m_trackEntriesEnd;
5667 Track* const pTrack = *i++;
5672 if (tn == pTrack->GetNumber())
5676 return NULL; // not found
5679 const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
5680 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
5682 if (idx >= static_cast<unsigned long>(count))
5685 return m_trackEntries[idx];
5688 long Cluster::Load(long long& pos, long& len) const {
5689 if (m_pSegment == NULL)
5690 return E_PARSE_FAILED;
5692 if (m_timecode >= 0) // at least partially loaded
5695 if (m_pos != m_element_start || m_element_size >= 0)
5696 return E_PARSE_FAILED;
5698 IMkvReader* const pReader = m_pSegment->m_pReader;
5699 long long total, avail;
5700 const int status = pReader->Length(&total, &avail);
5702 if (status < 0) // error
5705 if (total >= 0 && (avail > total || m_pos > total))
5706 return E_FILE_FORMAT_INVALID;
5710 long long cluster_size = -1;
5712 if ((pos + 1) > avail) {
5714 return E_BUFFER_NOT_FULL;
5717 long long result = GetUIntLength(pReader, pos, len);
5719 if (result < 0) // error or underflow
5720 return static_cast<long>(result);
5723 return E_BUFFER_NOT_FULL;
5725 if ((pos + len) > avail)
5726 return E_BUFFER_NOT_FULL;
5728 const long long id_ = ReadID(pReader, pos, len);
5730 if (id_ < 0) // error
5731 return static_cast<long>(id_);
5733 if (id_ != mkvmuxer::kMkvCluster)
5734 return E_FILE_FORMAT_INVALID;
5736 pos += len; // consume id
5738 // read cluster size
5740 if ((pos + 1) > avail) {
5742 return E_BUFFER_NOT_FULL;
5745 result = GetUIntLength(pReader, pos, len);
5747 if (result < 0) // error
5748 return static_cast<long>(result);
5751 return E_BUFFER_NOT_FULL;
5753 if ((pos + len) > avail)
5754 return E_BUFFER_NOT_FULL;
5756 const long long size = ReadUInt(pReader, pos, len);
5758 if (size < 0) // error
5759 return static_cast<long>(cluster_size);
5762 return E_FILE_FORMAT_INVALID;
5764 pos += len; // consume length of size of element
5766 const long long unknown_size = (1LL << (7 * len)) - 1;
5768 if (size != unknown_size)
5769 cluster_size = size;
5771 // pos points to start of payload
5772 long long timecode = -1;
5773 long long new_pos = -1;
5774 bool bBlock = false;
5776 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
5779 if ((cluster_stop >= 0) && (pos >= cluster_stop))
5784 if ((pos + 1) > avail) {
5786 return E_BUFFER_NOT_FULL;
5789 long long result = GetUIntLength(pReader, pos, len);
5791 if (result < 0) // error
5792 return static_cast<long>(result);
5795 return E_BUFFER_NOT_FULL;
5797 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
5798 return E_FILE_FORMAT_INVALID;
5800 if ((pos + len) > avail)
5801 return E_BUFFER_NOT_FULL;
5803 const long long id = ReadID(pReader, pos, len);
5805 if (id < 0) // error
5806 return static_cast<long>(id);
5809 return E_FILE_FORMAT_INVALID;
5811 // This is the distinguished set of ID's we use to determine
5812 // that we have exhausted the sub-element's inside the cluster
5813 // whose ID we parsed earlier.
5815 if (id == mkvmuxer::kMkvCluster)
5818 if (id == mkvmuxer::kMkvCues)
5821 pos += len; // consume ID field
5825 if ((pos + 1) > avail) {
5827 return E_BUFFER_NOT_FULL;
5830 result = GetUIntLength(pReader, pos, len);
5832 if (result < 0) // error
5833 return static_cast<long>(result);
5836 return E_BUFFER_NOT_FULL;
5838 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
5839 return E_FILE_FORMAT_INVALID;
5841 if ((pos + len) > avail)
5842 return E_BUFFER_NOT_FULL;
5844 const long long size = ReadUInt(pReader, pos, len);
5846 if (size < 0) // error
5847 return static_cast<long>(size);
5849 const long long unknown_size = (1LL << (7 * len)) - 1;
5851 if (size == unknown_size)
5852 return E_FILE_FORMAT_INVALID;
5854 pos += len; // consume size field
5856 if ((cluster_stop >= 0) && (pos > cluster_stop))
5857 return E_FILE_FORMAT_INVALID;
5859 // pos now points to start of payload
5864 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
5865 return E_FILE_FORMAT_INVALID;
5867 if (id == mkvmuxer::kMkvTimecode) {
5868 len = static_cast<long>(size);
5870 if ((pos + size) > avail)
5871 return E_BUFFER_NOT_FULL;
5873 timecode = UnserializeUInt(pReader, pos, size);
5875 if (timecode < 0) // error (or underflow)
5876 return static_cast<long>(timecode);
5878 new_pos = pos + size;
5882 } else if (id == mkvmuxer::kMkvBlockGroup) {
5885 } else if (id == mkvmuxer::kMkvSimpleBlock) {
5890 pos += size; // consume payload
5891 if (cluster_stop >= 0 && pos > cluster_stop)
5892 return E_FILE_FORMAT_INVALID;
5895 if (cluster_stop >= 0 && pos > cluster_stop)
5896 return E_FILE_FORMAT_INVALID;
5898 if (timecode < 0) // no timecode found
5899 return E_FILE_FORMAT_INVALID;
5902 return E_FILE_FORMAT_INVALID;
5904 m_pos = new_pos; // designates position just beyond timecode payload
5905 m_timecode = timecode; // m_timecode >= 0 means we're partially loaded
5907 if (cluster_size >= 0)
5908 m_element_size = cluster_stop - m_element_start;
5913 long Cluster::Parse(long long& pos, long& len) const {
5914 long status = Load(pos, len);
5919 if (m_pos < m_element_start || m_timecode < 0)
5920 return E_PARSE_FAILED;
5922 const long long cluster_stop =
5923 (m_element_size < 0) ? -1 : m_element_start + m_element_size;
5925 if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
5926 return 1; // nothing else to do
5928 IMkvReader* const pReader = m_pSegment->m_pReader;
5930 long long total, avail;
5932 status = pReader->Length(&total, &avail);
5934 if (status < 0) // error
5937 if (total >= 0 && avail > total)
5938 return E_FILE_FORMAT_INVALID;
5943 if ((cluster_stop >= 0) && (pos >= cluster_stop))
5946 if ((total >= 0) && (pos >= total)) {
5947 if (m_element_size < 0)
5948 m_element_size = pos - m_element_start;
5955 if ((pos + 1) > avail) {
5957 return E_BUFFER_NOT_FULL;
5960 long long result = GetUIntLength(pReader, pos, len);
5962 if (result < 0) // error
5963 return static_cast<long>(result);
5966 return E_BUFFER_NOT_FULL;
5968 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
5969 return E_FILE_FORMAT_INVALID;
5971 if ((pos + len) > avail)
5972 return E_BUFFER_NOT_FULL;
5974 const long long id = ReadID(pReader, pos, len);
5977 return E_FILE_FORMAT_INVALID;
5979 // This is the distinguished set of ID's we use to determine
5980 // that we have exhausted the sub-element's inside the cluster
5981 // whose ID we parsed earlier.
5983 if ((id == mkvmuxer::kMkvCluster) || (id == mkvmuxer::kMkvCues)) {
5984 if (m_element_size < 0)
5985 m_element_size = pos - m_element_start;
5990 pos += len; // consume ID field
5994 if ((pos + 1) > avail) {
5996 return E_BUFFER_NOT_FULL;
5999 result = GetUIntLength(pReader, pos, len);
6001 if (result < 0) // error
6002 return static_cast<long>(result);
6005 return E_BUFFER_NOT_FULL;
6007 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6008 return E_FILE_FORMAT_INVALID;
6010 if ((pos + len) > avail)
6011 return E_BUFFER_NOT_FULL;
6013 const long long size = ReadUInt(pReader, pos, len);
6015 if (size < 0) // error
6016 return static_cast<long>(size);
6018 const long long unknown_size = (1LL << (7 * len)) - 1;
6020 if (size == unknown_size)
6021 return E_FILE_FORMAT_INVALID;
6023 pos += len; // consume size field
6025 if ((cluster_stop >= 0) && (pos > cluster_stop))
6026 return E_FILE_FORMAT_INVALID;
6028 // pos now points to start of payload
6033 // const long long block_start = pos;
6034 const long long block_stop = pos + size;
6036 if (cluster_stop >= 0) {
6037 if (block_stop > cluster_stop) {
6038 if (id == mkvmuxer::kMkvBlockGroup ||
6039 id == mkvmuxer::kMkvSimpleBlock) {
6040 return E_FILE_FORMAT_INVALID;
6046 } else if ((total >= 0) && (block_stop > total)) {
6047 m_element_size = total - m_element_start;
6050 } else if (block_stop > avail) {
6051 len = static_cast<long>(size);
6052 return E_BUFFER_NOT_FULL;
6055 Cluster* const this_ = const_cast<Cluster*>(this);
6057 if (id == mkvmuxer::kMkvBlockGroup)
6058 return this_->ParseBlockGroup(size, pos, len);
6060 if (id == mkvmuxer::kMkvSimpleBlock)
6061 return this_->ParseSimpleBlock(size, pos, len);
6063 pos += size; // consume payload
6064 if (cluster_stop >= 0 && pos > cluster_stop)
6065 return E_FILE_FORMAT_INVALID;
6068 if (m_element_size < 1)
6069 return E_FILE_FORMAT_INVALID;
6072 if (cluster_stop >= 0 && m_pos > cluster_stop)
6073 return E_FILE_FORMAT_INVALID;
6075 if (m_entries_count > 0) {
6076 const long idx = m_entries_count - 1;
6078 const BlockEntry* const pLast = m_entries[idx];
6080 return E_PARSE_FAILED;
6082 const Block* const pBlock = pLast->GetBlock();
6084 return E_PARSE_FAILED;
6086 const long long start = pBlock->m_start;
6088 if ((total >= 0) && (start > total))
6089 return E_PARSE_FAILED; // defend against trucated stream
6091 const long long size = pBlock->m_size;
6093 const long long stop = start + size;
6094 if (cluster_stop >= 0 && stop > cluster_stop)
6095 return E_FILE_FORMAT_INVALID;
6097 if ((total >= 0) && (stop > total))
6098 return E_PARSE_FAILED; // defend against trucated stream
6101 return 1; // no more entries
6104 long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
6106 const long long block_start = pos;
6107 const long long block_stop = pos + block_size;
6109 IMkvReader* const pReader = m_pSegment->m_pReader;
6111 long long total, avail;
6113 long status = pReader->Length(&total, &avail);
6115 if (status < 0) // error
6118 assert((total < 0) || (avail <= total));
6120 // parse track number
6122 if ((pos + 1) > avail) {
6124 return E_BUFFER_NOT_FULL;
6127 long long result = GetUIntLength(pReader, pos, len);
6129 if (result < 0) // error
6130 return static_cast<long>(result);
6132 if (result > 0) // weird
6133 return E_BUFFER_NOT_FULL;
6135 if ((pos + len) > block_stop)
6136 return E_FILE_FORMAT_INVALID;
6138 if ((pos + len) > avail)
6139 return E_BUFFER_NOT_FULL;
6141 const long long track = ReadUInt(pReader, pos, len);
6143 if (track < 0) // error
6144 return static_cast<long>(track);
6147 return E_FILE_FORMAT_INVALID;
6149 pos += len; // consume track number
6151 if ((pos + 2) > block_stop)
6152 return E_FILE_FORMAT_INVALID;
6154 if ((pos + 2) > avail) {
6156 return E_BUFFER_NOT_FULL;
6159 pos += 2; // consume timecode
6161 if ((pos + 1) > block_stop)
6162 return E_FILE_FORMAT_INVALID;
6164 if ((pos + 1) > avail) {
6166 return E_BUFFER_NOT_FULL;
6169 unsigned char flags;
6171 status = pReader->Read(pos, 1, &flags);
6173 if (status < 0) { // error or underflow
6178 ++pos; // consume flags byte
6179 assert(pos <= avail);
6181 if (pos >= block_stop)
6182 return E_FILE_FORMAT_INVALID;
6184 const int lacing = int(flags & 0x06) >> 1;
6186 if ((lacing != 0) && (block_stop > avail)) {
6187 len = static_cast<long>(block_stop - pos);
6188 return E_BUFFER_NOT_FULL;
6191 status = CreateBlock(mkvmuxer::kMkvSimpleBlock,
6192 block_start, block_size,
6193 0); // DiscardPadding
6200 return 0; // success
6203 long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
6205 const long long payload_start = pos;
6206 const long long payload_stop = pos + payload_size;
6208 IMkvReader* const pReader = m_pSegment->m_pReader;
6210 long long total, avail;
6212 long status = pReader->Length(&total, &avail);
6214 if (status < 0) // error
6217 assert((total < 0) || (avail <= total));
6219 if ((total >= 0) && (payload_stop > total))
6220 return E_FILE_FORMAT_INVALID;
6222 if (payload_stop > avail) {
6223 len = static_cast<long>(payload_size);
6224 return E_BUFFER_NOT_FULL;
6227 long long discard_padding = 0;
6229 while (pos < payload_stop) {
6230 // parse sub-block element ID
6232 if ((pos + 1) > avail) {
6234 return E_BUFFER_NOT_FULL;
6237 long long result = GetUIntLength(pReader, pos, len);
6239 if (result < 0) // error
6240 return static_cast<long>(result);
6242 if (result > 0) // weird
6243 return E_BUFFER_NOT_FULL;
6245 if ((pos + len) > payload_stop)
6246 return E_FILE_FORMAT_INVALID;
6248 if ((pos + len) > avail)
6249 return E_BUFFER_NOT_FULL;
6251 const long long id = ReadID(pReader, pos, len);
6253 if (id < 0) // error
6254 return static_cast<long>(id);
6256 if (id == 0) // not a valid ID
6257 return E_FILE_FORMAT_INVALID;
6259 pos += len; // consume ID field
6263 if ((pos + 1) > avail) {
6265 return E_BUFFER_NOT_FULL;
6268 result = GetUIntLength(pReader, pos, len);
6270 if (result < 0) // error
6271 return static_cast<long>(result);
6273 if (result > 0) // weird
6274 return E_BUFFER_NOT_FULL;
6276 if ((pos + len) > payload_stop)
6277 return E_FILE_FORMAT_INVALID;
6279 if ((pos + len) > avail)
6280 return E_BUFFER_NOT_FULL;
6282 const long long size = ReadUInt(pReader, pos, len);
6284 if (size < 0) // error
6285 return static_cast<long>(size);
6287 pos += len; // consume size field
6289 // pos now points to start of sub-block group payload
6291 if (pos > payload_stop)
6292 return E_FILE_FORMAT_INVALID;
6294 if (size == 0) // weird
6297 const long long unknown_size = (1LL << (7 * len)) - 1;
6299 if (size == unknown_size)
6300 return E_FILE_FORMAT_INVALID;
6302 if (id == mkvmuxer::kMkvDiscardPadding) {
6303 status = UnserializeInt(pReader, pos, size, discard_padding);
6305 if (status < 0) // error
6309 if (id != mkvmuxer::kMkvBlock) {
6310 pos += size; // consume sub-part of block group
6312 if (pos > payload_stop)
6313 return E_FILE_FORMAT_INVALID;
6318 const long long block_stop = pos + size;
6320 if (block_stop > payload_stop)
6321 return E_FILE_FORMAT_INVALID;
6323 // parse track number
6325 if ((pos + 1) > avail) {
6327 return E_BUFFER_NOT_FULL;
6330 result = GetUIntLength(pReader, pos, len);
6332 if (result < 0) // error
6333 return static_cast<long>(result);
6335 if (result > 0) // weird
6336 return E_BUFFER_NOT_FULL;
6338 if ((pos + len) > block_stop)
6339 return E_FILE_FORMAT_INVALID;
6341 if ((pos + len) > avail)
6342 return E_BUFFER_NOT_FULL;
6344 const long long track = ReadUInt(pReader, pos, len);
6346 if (track < 0) // error
6347 return static_cast<long>(track);
6350 return E_FILE_FORMAT_INVALID;
6352 pos += len; // consume track number
6354 if ((pos + 2) > block_stop)
6355 return E_FILE_FORMAT_INVALID;
6357 if ((pos + 2) > avail) {
6359 return E_BUFFER_NOT_FULL;
6362 pos += 2; // consume timecode
6364 if ((pos + 1) > block_stop)
6365 return E_FILE_FORMAT_INVALID;
6367 if ((pos + 1) > avail) {
6369 return E_BUFFER_NOT_FULL;
6372 unsigned char flags;
6374 status = pReader->Read(pos, 1, &flags);
6376 if (status < 0) { // error or underflow
6381 ++pos; // consume flags byte
6382 assert(pos <= avail);
6384 if (pos >= block_stop)
6385 return E_FILE_FORMAT_INVALID;
6387 const int lacing = int(flags & 0x06) >> 1;
6389 if ((lacing != 0) && (block_stop > avail)) {
6390 len = static_cast<long>(block_stop - pos);
6391 return E_BUFFER_NOT_FULL;
6394 pos = block_stop; // consume block-part of block group
6395 if (pos > payload_stop)
6396 return E_FILE_FORMAT_INVALID;
6399 if (pos != payload_stop)
6400 return E_FILE_FORMAT_INVALID;
6402 status = CreateBlock(mkvmuxer::kMkvBlockGroup,
6403 payload_start, payload_size, discard_padding);
6407 m_pos = payload_stop;
6409 return 0; // success
6412 long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
6413 assert(m_pos >= m_element_start);
6418 return -1; // generic error
6420 if (m_entries_count < 0)
6421 return E_BUFFER_NOT_FULL;
6424 assert(m_entries_size > 0);
6425 assert(m_entries_count <= m_entries_size);
6427 if (index < m_entries_count) {
6428 pEntry = m_entries[index];
6431 return 1; // found entry
6434 if (m_element_size < 0) // we don't know cluster end yet
6435 return E_BUFFER_NOT_FULL; // underflow
6437 const long long element_stop = m_element_start + m_element_size;
6439 if (m_pos >= element_stop)
6440 return 0; // nothing left to parse
6442 return E_BUFFER_NOT_FULL; // underflow, since more remains to be parsed
6445 Cluster* Cluster::Create(Segment* pSegment, long idx, long long off) {
6446 if (!pSegment || off < 0)
6449 const long long element_start = pSegment->m_start + off;
6451 Cluster* const pCluster =
6452 new (std::nothrow) Cluster(pSegment, idx, element_start);
6466 m_entries_count(0) // means "no entries"
6469 Cluster::Cluster(Segment* pSegment, long idx, long long element_start
6470 /* long long element_size */)
6471 : m_pSegment(pSegment),
6472 m_element_start(element_start),
6474 m_pos(element_start),
6475 m_element_size(-1 /* element_size */),
6479 m_entries_count(-1) // means "has not been parsed yet"
6482 Cluster::~Cluster() {
6483 if (m_entries_count <= 0)
6486 BlockEntry** i = m_entries;
6487 BlockEntry** const j = m_entries + m_entries_count;
6490 BlockEntry* p = *i++;
6499 bool Cluster::EOS() const { return (m_pSegment == NULL); }
6501 long Cluster::GetIndex() const { return m_index; }
6503 long long Cluster::GetPosition() const {
6504 const long long pos = m_element_start - m_pSegment->m_start;
6510 long long Cluster::GetElementSize() const { return m_element_size; }
6512 long Cluster::HasBlockEntries(
6513 const Segment* pSegment,
6514 long long off, // relative to start of segment payload
6515 long long& pos, long& len) {
6517 assert(off >= 0); // relative to segment
6519 IMkvReader* const pReader = pSegment->m_pReader;
6521 long long total, avail;
6523 long status = pReader->Length(&total, &avail);
6525 if (status < 0) // error
6528 assert((total < 0) || (avail <= total));
6530 pos = pSegment->m_start + off; // absolute
6532 if ((total >= 0) && (pos >= total))
6533 return 0; // we don't even have a complete cluster
6535 const long long segment_stop =
6536 (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
6538 long long cluster_stop = -1; // interpreted later to mean "unknown size"
6541 if ((pos + 1) > avail) {
6543 return E_BUFFER_NOT_FULL;
6546 long long result = GetUIntLength(pReader, pos, len);
6548 if (result < 0) // error
6549 return static_cast<long>(result);
6551 if (result > 0) // need more data
6552 return E_BUFFER_NOT_FULL;
6554 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6555 return E_FILE_FORMAT_INVALID;
6557 if ((total >= 0) && ((pos + len) > total))
6560 if ((pos + len) > avail)
6561 return E_BUFFER_NOT_FULL;
6563 const long long id = ReadID(pReader, pos, len);
6565 if (id < 0) // error
6566 return static_cast<long>(id);
6568 if (id != mkvmuxer::kMkvCluster)
6569 return E_PARSE_FAILED;
6571 pos += len; // consume Cluster ID field
6575 if ((pos + 1) > avail) {
6577 return E_BUFFER_NOT_FULL;
6580 result = GetUIntLength(pReader, pos, len);
6582 if (result < 0) // error
6583 return static_cast<long>(result);
6585 if (result > 0) // weird
6586 return E_BUFFER_NOT_FULL;
6588 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
6589 return E_FILE_FORMAT_INVALID;
6591 if ((total >= 0) && ((pos + len) > total))
6594 if ((pos + len) > avail)
6595 return E_BUFFER_NOT_FULL;
6597 const long long size = ReadUInt(pReader, pos, len);
6599 if (size < 0) // error
6600 return static_cast<long>(size);
6603 return 0; // cluster does not have entries
6605 pos += len; // consume size field
6607 // pos now points to start of payload
6609 const long long unknown_size = (1LL << (7 * len)) - 1;
6611 if (size != unknown_size) {
6612 cluster_stop = pos + size;
6613 assert(cluster_stop >= 0);
6615 if ((segment_stop >= 0) && (cluster_stop > segment_stop))
6616 return E_FILE_FORMAT_INVALID;
6618 if ((total >= 0) && (cluster_stop > total))
6619 // return E_FILE_FORMAT_INVALID; //too conservative
6620 return 0; // cluster does not have any entries
6625 if ((cluster_stop >= 0) && (pos >= cluster_stop))
6626 return 0; // no entries detected
6628 if ((pos + 1) > avail) {
6630 return E_BUFFER_NOT_FULL;
6633 long long result = GetUIntLength(pReader, pos, len);
6635 if (result < 0) // error
6636 return static_cast<long>(result);
6638 if (result > 0) // need more data
6639 return E_BUFFER_NOT_FULL;
6641 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6642 return E_FILE_FORMAT_INVALID;
6644 if ((pos + len) > avail)
6645 return E_BUFFER_NOT_FULL;
6647 const long long id = ReadID(pReader, pos, len);
6649 if (id < 0) // error
6650 return static_cast<long>(id);
6652 // This is the distinguished set of ID's we use to determine
6653 // that we have exhausted the sub-element's inside the cluster
6654 // whose ID we parsed earlier.
6656 if (id == mkvmuxer::kMkvCluster)
6657 return 0; // no entries found
6659 if (id == mkvmuxer::kMkvCues)
6660 return 0; // no entries found
6662 pos += len; // consume id field
6664 if ((cluster_stop >= 0) && (pos >= cluster_stop))
6665 return E_FILE_FORMAT_INVALID;
6669 if ((pos + 1) > avail) {
6671 return E_BUFFER_NOT_FULL;
6674 result = GetUIntLength(pReader, pos, len);
6676 if (result < 0) // error
6677 return static_cast<long>(result);
6679 if (result > 0) // underflow
6680 return E_BUFFER_NOT_FULL;
6682 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6683 return E_FILE_FORMAT_INVALID;
6685 if ((pos + len) > avail)
6686 return E_BUFFER_NOT_FULL;
6688 const long long size = ReadUInt(pReader, pos, len);
6690 if (size < 0) // error
6691 return static_cast<long>(size);
6693 pos += len; // consume size field
6695 // pos now points to start of payload
6697 if ((cluster_stop >= 0) && (pos > cluster_stop))
6698 return E_FILE_FORMAT_INVALID;
6700 if (size == 0) // weird
6703 const long long unknown_size = (1LL << (7 * len)) - 1;
6705 if (size == unknown_size)
6706 return E_FILE_FORMAT_INVALID; // not supported inside cluster
6708 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
6709 return E_FILE_FORMAT_INVALID;
6711 if (id == mkvmuxer::kMkvBlockGroup)
6712 return 1; // have at least one entry
6714 if (id == mkvmuxer::kMkvSimpleBlock)
6715 return 1; // have at least one entry
6717 pos += size; // consume payload
6718 if (cluster_stop >= 0 && pos > cluster_stop)
6719 return E_FILE_FORMAT_INVALID;
6723 long long Cluster::GetTimeCode() const {
6727 const long status = Load(pos, len);
6729 if (status < 0) // error
6735 long long Cluster::GetTime() const {
6736 const long long tc = GetTimeCode();
6741 const SegmentInfo* const pInfo = m_pSegment->GetInfo();
6744 const long long scale = pInfo->GetTimeCodeScale();
6747 const long long t = m_timecode * scale;
6752 long long Cluster::GetFirstTime() const {
6753 const BlockEntry* pEntry;
6755 const long status = GetFirst(pEntry);
6757 if (status < 0) // error
6760 if (pEntry == NULL) // empty cluster
6763 const Block* const pBlock = pEntry->GetBlock();
6766 return pBlock->GetTime(this);
6769 long long Cluster::GetLastTime() const {
6770 const BlockEntry* pEntry;
6772 const long status = GetLast(pEntry);
6774 if (status < 0) // error
6777 if (pEntry == NULL) // empty cluster
6780 const Block* const pBlock = pEntry->GetBlock();
6783 return pBlock->GetTime(this);
6786 long Cluster::CreateBlock(long long id,
6787 long long pos, // absolute pos of payload
6788 long long size, long long discard_padding) {
6789 if (id != mkvmuxer::kMkvBlockGroup && id != mkvmuxer::kMkvSimpleBlock)
6790 return E_PARSE_FAILED;
6792 if (m_entries_count < 0) { // haven't parsed anything yet
6793 assert(m_entries == NULL);
6794 assert(m_entries_size == 0);
6796 m_entries_size = 1024;
6797 m_entries = new (std::nothrow) BlockEntry*[m_entries_size];
6798 if (m_entries == NULL)
6801 m_entries_count = 0;
6804 assert(m_entries_size > 0);
6805 assert(m_entries_count <= m_entries_size);
6807 if (m_entries_count >= m_entries_size) {
6808 const long entries_size = 2 * m_entries_size;
6810 BlockEntry** const entries = new (std::nothrow) BlockEntry*[entries_size];
6811 if (entries == NULL)
6814 BlockEntry** src = m_entries;
6815 BlockEntry** const src_end = src + m_entries_count;
6817 BlockEntry** dst = entries;
6819 while (src != src_end)
6824 m_entries = entries;
6825 m_entries_size = entries_size;
6829 if (id == mkvmuxer::kMkvBlockGroup)
6830 return CreateBlockGroup(pos, size, discard_padding);
6832 return CreateSimpleBlock(pos, size);
6835 long Cluster::CreateBlockGroup(long long start_offset, long long size,
6836 long long discard_padding) {
6838 assert(m_entries_size > 0);
6839 assert(m_entries_count >= 0);
6840 assert(m_entries_count < m_entries_size);
6842 IMkvReader* const pReader = m_pSegment->m_pReader;
6844 long long pos = start_offset;
6845 const long long stop = start_offset + size;
6847 // For WebM files, there is a bias towards previous reference times
6848 //(in order to support alt-ref frames, which refer back to the previous
6849 // keyframe). Normally a 0 value is not possible, but here we tenatively
6850 // allow 0 as the value of a reference frame, with the interpretation
6851 // that this is a "previous" reference time.
6853 long long prev = 1; // nonce
6854 long long next = 0; // nonce
6855 long long duration = -1; // really, this is unsigned
6857 long long bpos = -1;
6858 long long bsize = -1;
6860 while (pos < stop) {
6862 const long long id = ReadID(pReader, pos, len);
6863 if (id < 0 || (pos + len) > stop)
6864 return E_FILE_FORMAT_INVALID;
6866 pos += len; // consume ID
6868 const long long size = ReadUInt(pReader, pos, len);
6869 assert(size >= 0); // TODO
6870 assert((pos + len) <= stop);
6872 pos += len; // consume size
6874 if (id == mkvmuxer::kMkvBlock) {
6875 if (bpos < 0) { // Block ID
6879 } else if (id == mkvmuxer::kMkvBlockDuration) {
6881 return E_FILE_FORMAT_INVALID;
6883 duration = UnserializeUInt(pReader, pos, size);
6886 return E_FILE_FORMAT_INVALID;
6887 } else if (id == mkvmuxer::kMkvReferenceBlock) {
6888 if (size > 8 || size <= 0)
6889 return E_FILE_FORMAT_INVALID;
6890 const long size_ = static_cast<long>(size);
6894 long status = UnserializeInt(pReader, pos, size_, time);
6895 assert(status == 0);
6899 if (time <= 0) // see note above
6905 pos += size; // consume payload
6907 return E_FILE_FORMAT_INVALID;
6910 return E_FILE_FORMAT_INVALID;
6913 return E_FILE_FORMAT_INVALID;
6916 const long idx = m_entries_count;
6918 BlockEntry** const ppEntry = m_entries + idx;
6919 BlockEntry*& pEntry = *ppEntry;
6921 pEntry = new (std::nothrow)
6922 BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
6925 return -1; // generic error
6927 BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
6929 const long status = p->Parse();
6931 if (status == 0) { // success
6942 long Cluster::CreateSimpleBlock(long long st, long long sz) {
6944 assert(m_entries_size > 0);
6945 assert(m_entries_count >= 0);
6946 assert(m_entries_count < m_entries_size);
6948 const long idx = m_entries_count;
6950 BlockEntry** const ppEntry = m_entries + idx;
6951 BlockEntry*& pEntry = *ppEntry;
6953 pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
6956 return -1; // generic error
6958 SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
6960 const long status = p->Parse();
6973 long Cluster::GetFirst(const BlockEntry*& pFirst) const {
6974 if (m_entries_count <= 0) {
6978 const long status = Parse(pos, len);
6980 if (status < 0) { // error
6985 if (m_entries_count <= 0) { // empty cluster
6993 pFirst = m_entries[0];
6996 return 0; // success
6999 long Cluster::GetLast(const BlockEntry*& pLast) const {
7004 const long status = Parse(pos, len);
7006 if (status < 0) { // error
7011 if (status > 0) // no new block
7015 if (m_entries_count <= 0) {
7022 const long idx = m_entries_count - 1;
7024 pLast = m_entries[idx];
7030 long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
7033 assert(m_entries_count > 0);
7035 size_t idx = pCurr->GetIndex();
7036 assert(idx < size_t(m_entries_count));
7037 assert(m_entries[idx] == pCurr);
7041 if (idx >= size_t(m_entries_count)) {
7045 const long status = Parse(pos, len);
7047 if (status < 0) { // error
7058 assert(m_entries_count > 0);
7059 assert(idx < size_t(m_entries_count));
7062 pNext = m_entries[idx];
7068 long Cluster::GetEntryCount() const { return m_entries_count; }
7070 const BlockEntry* Cluster::GetEntry(const Track* pTrack,
7071 long long time_ns) const {
7074 if (m_pSegment == NULL) // this is the special EOS cluster
7075 return pTrack->GetEOS();
7077 const BlockEntry* pResult = pTrack->GetEOS();
7082 if (index >= m_entries_count) {
7086 const long status = Parse(pos, len);
7087 assert(status >= 0);
7089 if (status > 0) // completely parsed, and no more entries
7092 if (status < 0) // should never happen
7096 assert(index < m_entries_count);
7099 const BlockEntry* const pEntry = m_entries[index];
7101 assert(!pEntry->EOS());
7103 const Block* const pBlock = pEntry->GetBlock();
7106 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
7111 if (pTrack->VetEntry(pEntry)) {
7112 if (time_ns < 0) // just want first candidate block
7115 const long long ns = pBlock->GetTime(this);
7120 pResult = pEntry; // have a candidate
7121 } else if (time_ns >= 0) {
7122 const long long ns = pBlock->GetTime(this);
7132 const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
7133 const CuePoint::TrackPosition& tp) const {
7135 const long long tc = cp.GetTimeCode();
7137 if (tp.m_block > 0) {
7138 const long block = static_cast<long>(tp.m_block);
7139 const long index = block - 1;
7141 while (index >= m_entries_count) {
7145 const long status = Parse(pos, len);
7147 if (status < 0) // TODO: can this happen?
7150 if (status > 0) // nothing remains to be parsed
7154 const BlockEntry* const pEntry = m_entries[index];
7156 assert(!pEntry->EOS());
7158 const Block* const pBlock = pEntry->GetBlock();
7161 if ((pBlock->GetTrackNumber() == tp.m_track) &&
7162 (pBlock->GetTimeCode(this) == tc)) {
7170 if (index >= m_entries_count) {
7174 const long status = Parse(pos, len);
7176 if (status < 0) // TODO: can this happen?
7179 if (status > 0) // nothing remains to be parsed
7183 assert(index < m_entries_count);
7186 const BlockEntry* const pEntry = m_entries[index];
7188 assert(!pEntry->EOS());
7190 const Block* const pBlock = pEntry->GetBlock();
7193 if (pBlock->GetTrackNumber() != tp.m_track) {
7198 const long long tc_ = pBlock->GetTimeCode(this);
7208 const Tracks* const pTracks = m_pSegment->GetTracks();
7211 const long tn = static_cast<long>(tp.m_track);
7212 const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7217 const long long type = pTrack->GetType();
7219 if (type == 2) // audio
7222 if (type != 1) // not video
7225 if (!pBlock->IsKey())
7232 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
7233 BlockEntry::~BlockEntry() {}
7234 bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); }
7235 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
7236 long BlockEntry::GetIndex() const { return m_index; }
7238 SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7240 : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7242 long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
7243 BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
7244 const Block* SimpleBlock::GetBlock() const { return &m_block; }
7246 BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
7247 long long block_size, long long prev, long long next,
7248 long long duration, long long discard_padding)
7249 : BlockEntry(pCluster, idx),
7250 m_block(block_start, block_size, discard_padding),
7253 m_duration(duration) {}
7255 long BlockGroup::Parse() {
7256 const long status = m_block.Parse(m_pCluster);
7261 m_block.SetKey((m_prev > 0) && (m_next <= 0));
7266 BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
7267 const Block* BlockGroup::GetBlock() const { return &m_block; }
7268 long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
7269 long long BlockGroup::GetNextTimeCode() const { return m_next; }
7270 long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7272 Block::Block(long long start, long long size_, long long discard_padding)
7280 m_discard_padding(discard_padding) {}
7282 Block::~Block() { delete[] m_frames; }
7284 long Block::Parse(const Cluster* pCluster) {
7285 if (pCluster == NULL)
7288 if (pCluster->m_pSegment == NULL)
7291 assert(m_start >= 0);
7292 assert(m_size >= 0);
7293 assert(m_track <= 0);
7294 assert(m_frames == NULL);
7295 assert(m_frame_count <= 0);
7297 long long pos = m_start;
7298 const long long stop = m_start + m_size;
7302 IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
7304 m_track = ReadUInt(pReader, pos, len);
7307 return E_FILE_FORMAT_INVALID;
7309 if ((pos + len) > stop)
7310 return E_FILE_FORMAT_INVALID;
7312 pos += len; // consume track number
7314 if ((stop - pos) < 2)
7315 return E_FILE_FORMAT_INVALID;
7320 status = UnserializeInt(pReader, pos, 2, value);
7323 return E_FILE_FORMAT_INVALID;
7325 if (value < SHRT_MIN)
7326 return E_FILE_FORMAT_INVALID;
7328 if (value > SHRT_MAX)
7329 return E_FILE_FORMAT_INVALID;
7331 m_timecode = static_cast<short>(value);
7335 if ((stop - pos) <= 0)
7336 return E_FILE_FORMAT_INVALID;
7338 status = pReader->Read(pos, 1, &m_flags);
7341 return E_FILE_FORMAT_INVALID;
7343 const int lacing = int(m_flags & 0x06) >> 1;
7345 ++pos; // consume flags byte
7347 if (lacing == 0) { // no lacing
7349 return E_FILE_FORMAT_INVALID;
7352 m_frames = new (std::nothrow) Frame[m_frame_count];
7353 if (m_frames == NULL)
7356 Frame& f = m_frames[0];
7359 const long long frame_size = stop - pos;
7361 if (frame_size > LONG_MAX || frame_size <= 0)
7362 return E_FILE_FORMAT_INVALID;
7364 f.len = static_cast<long>(frame_size);
7366 return 0; // success
7370 return E_FILE_FORMAT_INVALID;
7372 unsigned char biased_count;
7374 status = pReader->Read(pos, 1, &biased_count);
7377 return E_FILE_FORMAT_INVALID;
7379 ++pos; // consume frame count
7381 return E_FILE_FORMAT_INVALID;
7383 m_frame_count = int(biased_count) + 1;
7385 m_frames = new (std::nothrow) Frame[m_frame_count];
7386 if (m_frames == NULL)
7390 return E_FILE_FORMAT_INVALID;
7392 if (lacing == 1) { // Xiph
7393 Frame* pf = m_frames;
7394 Frame* const pf_end = pf + m_frame_count;
7397 int frame_count = m_frame_count;
7399 while (frame_count > 1) {
7400 long frame_size = 0;
7406 return E_FILE_FORMAT_INVALID;
7408 status = pReader->Read(pos, 1, &val);
7411 return E_FILE_FORMAT_INVALID;
7413 ++pos; // consume xiph size byte
7422 assert(pf < pf_end);
7424 return E_FILE_FORMAT_INVALID;
7426 f.pos = 0; // patch later
7428 if (frame_size <= 0)
7429 return E_FILE_FORMAT_INVALID;
7432 size += frame_size; // contribution of this frame
7437 if (pf >= pf_end || pos > stop)
7438 return E_FILE_FORMAT_INVALID;
7444 return E_FILE_FORMAT_INVALID;
7446 f.pos = 0; // patch later
7448 const long long total_size = stop - pos;
7450 if (total_size < size)
7451 return E_FILE_FORMAT_INVALID;
7453 const long long frame_size = total_size - size;
7455 if (frame_size > LONG_MAX || frame_size <= 0)
7456 return E_FILE_FORMAT_INVALID;
7458 f.len = static_cast<long>(frame_size);
7462 while (pf != pf_end) {
7464 assert((pos + f.len) <= stop);
7466 if ((pos + f.len) > stop)
7467 return E_FILE_FORMAT_INVALID;
7473 assert(pos == stop);
7475 return E_FILE_FORMAT_INVALID;
7477 } else if (lacing == 2) { // fixed-size lacing
7479 return E_FILE_FORMAT_INVALID;
7481 const long long total_size = stop - pos;
7483 if ((total_size % m_frame_count) != 0)
7484 return E_FILE_FORMAT_INVALID;
7486 const long long frame_size = total_size / m_frame_count;
7488 if (frame_size > LONG_MAX || frame_size <= 0)
7489 return E_FILE_FORMAT_INVALID;
7491 Frame* pf = m_frames;
7492 Frame* const pf_end = pf + m_frame_count;
7494 while (pf != pf_end) {
7495 assert((pos + frame_size) <= stop);
7496 if ((pos + frame_size) > stop)
7497 return E_FILE_FORMAT_INVALID;
7502 f.len = static_cast<long>(frame_size);
7507 assert(pos == stop);
7509 return E_FILE_FORMAT_INVALID;
7512 assert(lacing == 3); // EBML lacing
7515 return E_FILE_FORMAT_INVALID;
7518 int frame_count = m_frame_count;
7520 long long frame_size = ReadUInt(pReader, pos, len);
7522 if (frame_size <= 0)
7523 return E_FILE_FORMAT_INVALID;
7525 if (frame_size > LONG_MAX)
7526 return E_FILE_FORMAT_INVALID;
7528 if ((pos + len) > stop)
7529 return E_FILE_FORMAT_INVALID;
7531 pos += len; // consume length of size of first frame
7533 if ((pos + frame_size) > stop)
7534 return E_FILE_FORMAT_INVALID;
7536 Frame* pf = m_frames;
7537 Frame* const pf_end = pf + m_frame_count;
7542 curr.pos = 0; // patch later
7544 curr.len = static_cast<long>(frame_size);
7545 size += curr.len; // contribution of this frame
7550 while (frame_count > 1) {
7552 return E_FILE_FORMAT_INVALID;
7554 assert(pf < pf_end);
7556 return E_FILE_FORMAT_INVALID;
7559 const Frame& prev = *pf++;
7560 assert(prev.len == frame_size);
7561 if (prev.len != frame_size)
7562 return E_FILE_FORMAT_INVALID;
7564 assert(pf < pf_end);
7566 return E_FILE_FORMAT_INVALID;
7570 curr.pos = 0; // patch later
7572 const long long delta_size_ = ReadUInt(pReader, pos, len);
7574 if (delta_size_ < 0)
7575 return E_FILE_FORMAT_INVALID;
7577 if ((pos + len) > stop)
7578 return E_FILE_FORMAT_INVALID;
7580 pos += len; // consume length of (delta) size
7582 return E_FILE_FORMAT_INVALID;
7584 const int exp = 7 * len - 1;
7585 const long long bias = (1LL << exp) - 1LL;
7586 const long long delta_size = delta_size_ - bias;
7588 frame_size += delta_size;
7590 if (frame_size <= 0)
7591 return E_FILE_FORMAT_INVALID;
7593 if (frame_size > LONG_MAX)
7594 return E_FILE_FORMAT_INVALID;
7596 curr.len = static_cast<long>(frame_size);
7597 size += curr.len; // contribution of this frame
7603 if (frame_count > 0) {
7604 if (pos > stop || pf >= pf_end)
7605 return E_FILE_FORMAT_INVALID;
7607 const Frame& prev = *pf++;
7608 assert(prev.len == frame_size);
7609 if (prev.len != frame_size)
7610 return E_FILE_FORMAT_INVALID;
7613 return E_FILE_FORMAT_INVALID;
7615 Frame& curr = *pf++;
7617 return E_FILE_FORMAT_INVALID;
7619 curr.pos = 0; // patch later
7621 const long long total_size = stop - pos;
7623 if (total_size < size)
7624 return E_FILE_FORMAT_INVALID;
7626 frame_size = total_size - size;
7628 if (frame_size > LONG_MAX || frame_size <= 0)
7629 return E_FILE_FORMAT_INVALID;
7631 curr.len = static_cast<long>(frame_size);
7635 while (pf != pf_end) {
7637 assert((pos + f.len) <= stop);
7638 if ((pos + f.len) > stop)
7639 return E_FILE_FORMAT_INVALID;
7646 return E_FILE_FORMAT_INVALID;
7649 return 0; // success
7652 long long Block::GetTimeCode(const Cluster* pCluster) const {
7656 const long long tc0 = pCluster->GetTimeCode();
7659 const long long tc = tc0 + m_timecode;
7661 return tc; // unscaled timecode units
7664 long long Block::GetTime(const Cluster* pCluster) const {
7667 const long long tc = GetTimeCode(pCluster);
7669 const Segment* const pSegment = pCluster->m_pSegment;
7670 const SegmentInfo* const pInfo = pSegment->GetInfo();
7673 const long long scale = pInfo->GetTimeCodeScale();
7676 const long long ns = tc * scale;
7681 long long Block::GetTrackNumber() const { return m_track; }
7683 bool Block::IsKey() const {
7684 return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
7687 void Block::SetKey(bool bKey) {
7689 m_flags |= static_cast<unsigned char>(1 << 7);
7694 bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
7696 Block::Lacing Block::GetLacing() const {
7697 const int value = int(m_flags & 0x06) >> 1;
7698 return static_cast<Lacing>(value);
7701 int Block::GetFrameCount() const { return m_frame_count; }
7703 const Block::Frame& Block::GetFrame(int idx) const {
7705 assert(idx < m_frame_count);
7707 const Frame& f = m_frames[idx];
7714 long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
7718 const long status = pReader->Read(pos, len, buf);
7722 long long Block::GetDiscardPadding() const { return m_discard_padding; }
7724 } // end namespace mkvparser