1 // Copyright (c) 2012 The WebM project authors. All Rights Reserved.
2 //
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.
8
9 #include "mkvparser.hpp"
10 #include <cassert>
11 #include <cstring>
12 #include <new>
13 #include <climits>
14
15 #ifdef _MSC_VER
16 // Disable MSVC warnings that suggest making code non-portable.
17 #pragma warning(disable : 4996)
18 #endif
19
~IMkvReader()20 mkvparser::IMkvReader::~IMkvReader() {}
21
GetVersion(int & major,int & minor,int & build,int & revision)22 void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision) {
23 major = 1;
24 minor = 0;
25 build = 0;
26 revision = 28;
27 }
28
ReadUInt(IMkvReader * pReader,long long pos,long & len)29 long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) {
30 assert(pReader);
31 assert(pos >= 0);
32
33 int status;
34
35 //#ifdef _DEBUG
36 // long long total, available;
37 // status = pReader->Length(&total, &available);
38 // assert(status >= 0);
39 // assert((total < 0) || (available <= total));
40 // assert(pos < available);
41 // assert((available - pos) >= 1); //assume here max u-int len is 8
42 //#endif
43
44 len = 1;
45
46 unsigned char b;
47
48 status = pReader->Read(pos, 1, &b);
49
50 if (status < 0) // error or underflow
51 return status;
52
53 if (status > 0) // interpreted as "underflow"
54 return E_BUFFER_NOT_FULL;
55
56 if (b == 0) // we can't handle u-int values larger than 8 bytes
57 return E_FILE_FORMAT_INVALID;
58
59 unsigned char m = 0x80;
60
61 while (!(b & m)) {
62 m >>= 1;
63 ++len;
64 }
65
66 //#ifdef _DEBUG
67 // assert((available - pos) >= len);
68 //#endif
69
70 long long result = b & (~m);
71 ++pos;
72
73 for (int i = 1; i < len; ++i) {
74 status = pReader->Read(pos, 1, &b);
75
76 if (status < 0) {
77 len = 1;
78 return status;
79 }
80
81 if (status > 0) {
82 len = 1;
83 return E_BUFFER_NOT_FULL;
84 }
85
86 result <<= 8;
87 result |= b;
88
89 ++pos;
90 }
91
92 return result;
93 }
94
GetUIntLength(IMkvReader * pReader,long long pos,long & len)95 long long mkvparser::GetUIntLength(IMkvReader* pReader, long long pos,
96 long& len) {
97 assert(pReader);
98 assert(pos >= 0);
99
100 long long total, available;
101
102 int status = pReader->Length(&total, &available);
103 assert(status >= 0);
104 assert((total < 0) || (available <= total));
105
106 len = 1;
107
108 if (pos >= available)
109 return pos; // too few bytes available
110
111 unsigned char b;
112
113 status = pReader->Read(pos, 1, &b);
114
115 if (status < 0)
116 return status;
117
118 assert(status == 0);
119
120 if (b == 0) // we can't handle u-int values larger than 8 bytes
121 return E_FILE_FORMAT_INVALID;
122
123 unsigned char m = 0x80;
124
125 while (!(b & m)) {
126 m >>= 1;
127 ++len;
128 }
129
130 return 0; // success
131 }
132
133 // TODO(vigneshv): This function assumes that unsigned values never have their
134 // high bit set.
UnserializeUInt(IMkvReader * pReader,long long pos,long long size)135 long long mkvparser::UnserializeUInt(IMkvReader* pReader, long long pos,
136 long long size) {
137 assert(pReader);
138 assert(pos >= 0);
139
140 if ((size <= 0) || (size > 8))
141 return E_FILE_FORMAT_INVALID;
142
143 long long result = 0;
144
145 for (long long i = 0; i < size; ++i) {
146 unsigned char b;
147
148 const long status = pReader->Read(pos, 1, &b);
149
150 if (status < 0)
151 return status;
152
153 result <<= 8;
154 result |= b;
155
156 ++pos;
157 }
158
159 return result;
160 }
161
UnserializeFloat(IMkvReader * pReader,long long pos,long long size_,double & result)162 long mkvparser::UnserializeFloat(IMkvReader* pReader, long long pos,
163 long long size_, double& result) {
164 assert(pReader);
165 assert(pos >= 0);
166
167 if ((size_ != 4) && (size_ != 8))
168 return E_FILE_FORMAT_INVALID;
169
170 const long size = static_cast<long>(size_);
171
172 unsigned char buf[8];
173
174 const int status = pReader->Read(pos, size, buf);
175
176 if (status < 0) // error
177 return status;
178
179 if (size == 4) {
180 union {
181 float f;
182 unsigned long ff;
183 };
184
185 ff = 0;
186
187 for (int i = 0;;) {
188 ff |= buf[i];
189
190 if (++i >= 4)
191 break;
192
193 ff <<= 8;
194 }
195
196 result = f;
197 } else {
198 assert(size == 8);
199
200 union {
201 double d;
202 unsigned long long dd;
203 };
204
205 dd = 0;
206
207 for (int i = 0;;) {
208 dd |= buf[i];
209
210 if (++i >= 8)
211 break;
212
213 dd <<= 8;
214 }
215
216 result = d;
217 }
218
219 return 0;
220 }
221
UnserializeInt(IMkvReader * pReader,long long pos,long size,long long & result)222 long mkvparser::UnserializeInt(IMkvReader* pReader, long long pos, long size,
223 long long& result) {
224 assert(pReader);
225 assert(pos >= 0);
226 assert(size > 0);
227 assert(size <= 8);
228
229 {
230 signed char b;
231
232 const long status = pReader->Read(pos, 1, (unsigned char*)&b);
233
234 if (status < 0)
235 return status;
236
237 result = b;
238
239 ++pos;
240 }
241
242 for (long i = 1; i < size; ++i) {
243 unsigned char b;
244
245 const long status = pReader->Read(pos, 1, &b);
246
247 if (status < 0)
248 return status;
249
250 result <<= 8;
251 result |= b;
252
253 ++pos;
254 }
255
256 return 0; // success
257 }
258
UnserializeString(IMkvReader * pReader,long long pos,long long size_,char * & str)259 long mkvparser::UnserializeString(IMkvReader* pReader, long long pos,
260 long long size_, char*& str) {
261 delete[] str;
262 str = NULL;
263
264 if (size_ >= LONG_MAX) // we need (size+1) chars
265 return E_FILE_FORMAT_INVALID;
266
267 const long size = static_cast<long>(size_);
268
269 str = new (std::nothrow) char[size + 1];
270
271 if (str == NULL)
272 return -1;
273
274 unsigned char* const buf = reinterpret_cast<unsigned char*>(str);
275
276 const long status = pReader->Read(pos, size, buf);
277
278 if (status) {
279 delete[] str;
280 str = NULL;
281
282 return status;
283 }
284
285 str[size] = '\0';
286
287 return 0; // success
288 }
289
ParseElementHeader(IMkvReader * pReader,long long & pos,long long stop,long long & id,long long & size)290 long mkvparser::ParseElementHeader(IMkvReader* pReader, long long& pos,
291 long long stop, long long& id,
292 long long& size) {
293 if ((stop >= 0) && (pos >= stop))
294 return E_FILE_FORMAT_INVALID;
295
296 long len;
297
298 id = ReadUInt(pReader, pos, len);
299
300 if (id < 0)
301 return E_FILE_FORMAT_INVALID;
302
303 pos += len; // consume id
304
305 if ((stop >= 0) && (pos >= stop))
306 return E_FILE_FORMAT_INVALID;
307
308 size = ReadUInt(pReader, pos, len);
309
310 if (size < 0)
311 return E_FILE_FORMAT_INVALID;
312
313 pos += len; // consume length of size
314
315 // pos now designates payload
316
317 if ((stop >= 0) && ((pos + size) > stop))
318 return E_FILE_FORMAT_INVALID;
319
320 return 0; // success
321 }
322
Match(IMkvReader * pReader,long long & pos,unsigned long id_,long long & val)323 bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_,
324 long long& val) {
325 assert(pReader);
326 assert(pos >= 0);
327
328 long long total, available;
329
330 const long status = pReader->Length(&total, &available);
331 assert(status >= 0);
332 assert((total < 0) || (available <= total));
333 if (status < 0)
334 return false;
335
336 long len;
337
338 const long long id = ReadUInt(pReader, pos, len);
339 assert(id >= 0);
340 assert(len > 0);
341 assert(len <= 8);
342 assert((pos + len) <= available);
343
344 if ((unsigned long)id != id_)
345 return false;
346
347 pos += len; // consume id
348
349 const long long size = ReadUInt(pReader, pos, len);
350 assert(size >= 0);
351 assert(size <= 8);
352 assert(len > 0);
353 assert(len <= 8);
354 assert((pos + len) <= available);
355
356 pos += len; // consume length of size of payload
357
358 val = UnserializeUInt(pReader, pos, size);
359 assert(val >= 0);
360
361 pos += size; // consume size of payload
362
363 return true;
364 }
365
Match(IMkvReader * pReader,long long & pos,unsigned long id_,unsigned char * & buf,size_t & buflen)366 bool mkvparser::Match(IMkvReader* pReader, long long& pos, unsigned long id_,
367 unsigned char*& buf, size_t& buflen) {
368 assert(pReader);
369 assert(pos >= 0);
370
371 long long total, available;
372
373 long status = pReader->Length(&total, &available);
374 assert(status >= 0);
375 assert((total < 0) || (available <= total));
376 if (status < 0)
377 return false;
378
379 long len;
380 const long long id = ReadUInt(pReader, pos, len);
381 assert(id >= 0);
382 assert(len > 0);
383 assert(len <= 8);
384 assert((pos + len) <= available);
385
386 if ((unsigned long)id != id_)
387 return false;
388
389 pos += len; // consume id
390
391 const long long size_ = ReadUInt(pReader, pos, len);
392 assert(size_ >= 0);
393 assert(len > 0);
394 assert(len <= 8);
395 assert((pos + len) <= available);
396
397 pos += len; // consume length of size of payload
398 assert((pos + size_) <= available);
399
400 const long buflen_ = static_cast<long>(size_);
401
402 buf = new (std::nothrow) unsigned char[buflen_];
403 assert(buf); // TODO
404
405 status = pReader->Read(pos, buflen_, buf);
406 assert(status == 0); // TODO
407
408 buflen = buflen_;
409
410 pos += size_; // consume size of payload
411 return true;
412 }
413
414 namespace mkvparser {
415
EBMLHeader()416 EBMLHeader::EBMLHeader() : m_docType(NULL) { Init(); }
417
~EBMLHeader()418 EBMLHeader::~EBMLHeader() { delete[] m_docType; }
419
Init()420 void EBMLHeader::Init() {
421 m_version = 1;
422 m_readVersion = 1;
423 m_maxIdLength = 4;
424 m_maxSizeLength = 8;
425
426 if (m_docType) {
427 delete[] m_docType;
428 m_docType = NULL;
429 }
430
431 m_docTypeVersion = 1;
432 m_docTypeReadVersion = 1;
433 }
434
Parse(IMkvReader * pReader,long long & pos)435 long long EBMLHeader::Parse(IMkvReader* pReader, long long& pos) {
436 assert(pReader);
437
438 long long total, available;
439
440 long status = pReader->Length(&total, &available);
441
442 if (status < 0) // error
443 return status;
444
445 pos = 0;
446 long long end = (available >= 1024) ? 1024 : available;
447
448 for (;;) {
449 unsigned char b = 0;
450
451 while (pos < end) {
452 status = pReader->Read(pos, 1, &b);
453
454 if (status < 0) // error
455 return status;
456
457 if (b == 0x1A)
458 break;
459
460 ++pos;
461 }
462
463 if (b != 0x1A) {
464 if (pos >= 1024)
465 return E_FILE_FORMAT_INVALID; // don't bother looking anymore
466
467 if ((total >= 0) && ((total - available) < 5))
468 return E_FILE_FORMAT_INVALID;
469
470 return available + 5; // 5 = 4-byte ID + 1st byte of size
471 }
472
473 if ((total >= 0) && ((total - pos) < 5))
474 return E_FILE_FORMAT_INVALID;
475
476 if ((available - pos) < 5)
477 return pos + 5; // try again later
478
479 long len;
480
481 const long long result = ReadUInt(pReader, pos, len);
482
483 if (result < 0) // error
484 return result;
485
486 if (result == 0x0A45DFA3) { // EBML Header ID
487 pos += len; // consume ID
488 break;
489 }
490
491 ++pos; // throw away just the 0x1A byte, and try again
492 }
493
494 // pos designates start of size field
495
496 // get length of size field
497
498 long len;
499 long long result = GetUIntLength(pReader, pos, len);
500
501 if (result < 0) // error
502 return result;
503
504 if (result > 0) // need more data
505 return result;
506
507 assert(len > 0);
508 assert(len <= 8);
509
510 if ((total >= 0) && ((total - pos) < len))
511 return E_FILE_FORMAT_INVALID;
512
513 if ((available - pos) < len)
514 return pos + len; // try again later
515
516 // get the EBML header size
517
518 result = ReadUInt(pReader, pos, len);
519
520 if (result < 0) // error
521 return result;
522
523 pos += len; // consume size field
524
525 // pos now designates start of payload
526
527 if ((total >= 0) && ((total - pos) < result))
528 return E_FILE_FORMAT_INVALID;
529
530 if ((available - pos) < result)
531 return pos + result;
532
533 end = pos + result;
534
535 Init();
536
537 while (pos < end) {
538 long long id, size;
539
540 status = ParseElementHeader(pReader, pos, end, id, size);
541
542 if (status < 0) // error
543 return status;
544
545 if (size == 0) // weird
546 return E_FILE_FORMAT_INVALID;
547
548 if (id == 0x0286) { // version
549 m_version = UnserializeUInt(pReader, pos, size);
550
551 if (m_version <= 0)
552 return E_FILE_FORMAT_INVALID;
553 } else if (id == 0x02F7) { // read version
554 m_readVersion = UnserializeUInt(pReader, pos, size);
555
556 if (m_readVersion <= 0)
557 return E_FILE_FORMAT_INVALID;
558 } else if (id == 0x02F2) { // max id length
559 m_maxIdLength = UnserializeUInt(pReader, pos, size);
560
561 if (m_maxIdLength <= 0)
562 return E_FILE_FORMAT_INVALID;
563 } else if (id == 0x02F3) { // max size length
564 m_maxSizeLength = UnserializeUInt(pReader, pos, size);
565
566 if (m_maxSizeLength <= 0)
567 return E_FILE_FORMAT_INVALID;
568 } else if (id == 0x0282) { // doctype
569 if (m_docType)
570 return E_FILE_FORMAT_INVALID;
571
572 status = UnserializeString(pReader, pos, size, m_docType);
573
574 if (status) // error
575 return status;
576 } else if (id == 0x0287) { // doctype version
577 m_docTypeVersion = UnserializeUInt(pReader, pos, size);
578
579 if (m_docTypeVersion <= 0)
580 return E_FILE_FORMAT_INVALID;
581 } else if (id == 0x0285) { // doctype read version
582 m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
583
584 if (m_docTypeReadVersion <= 0)
585 return E_FILE_FORMAT_INVALID;
586 }
587
588 pos += size;
589 }
590
591 assert(pos == end);
592 return 0;
593 }
594
Segment(IMkvReader * pReader,long long elem_start,long long start,long long size)595 Segment::Segment(IMkvReader* pReader, long long elem_start,
596 // long long elem_size,
597 long long start, long long size)
598 : m_pReader(pReader),
599 m_element_start(elem_start),
600 // m_element_size(elem_size),
601 m_start(start),
602 m_size(size),
603 m_pos(start),
604 m_pUnknownSize(0),
605 m_pSeekHead(NULL),
606 m_pInfo(NULL),
607 m_pTracks(NULL),
608 m_pCues(NULL),
609 m_pChapters(NULL),
610 m_clusters(NULL),
611 m_clusterCount(0),
612 m_clusterPreloadCount(0),
613 m_clusterSize(0) {}
614
~Segment()615 Segment::~Segment() {
616 const long count = m_clusterCount + m_clusterPreloadCount;
617
618 Cluster** i = m_clusters;
619 Cluster** j = m_clusters + count;
620
621 while (i != j) {
622 Cluster* const p = *i++;
623 assert(p);
624
625 delete p;
626 }
627
628 delete[] m_clusters;
629
630 delete m_pTracks;
631 delete m_pInfo;
632 delete m_pCues;
633 delete m_pChapters;
634 delete m_pSeekHead;
635 }
636
CreateInstance(IMkvReader * pReader,long long pos,Segment * & pSegment)637 long long Segment::CreateInstance(IMkvReader* pReader, long long pos,
638 Segment*& pSegment) {
639 assert(pReader);
640 assert(pos >= 0);
641
642 pSegment = NULL;
643
644 long long total, available;
645
646 const long status = pReader->Length(&total, &available);
647
648 if (status < 0) // error
649 return status;
650
651 if (available < 0)
652 return -1;
653
654 if ((total >= 0) && (available > total))
655 return -1;
656
657 // I would assume that in practice this loop would execute
658 // exactly once, but we allow for other elements (e.g. Void)
659 // to immediately follow the EBML header. This is fine for
660 // the source filter case (since the entire file is available),
661 // but in the splitter case over a network we should probably
662 // just give up early. We could for example decide only to
663 // execute this loop a maximum of, say, 10 times.
664 // TODO:
665 // There is an implied "give up early" by only parsing up
666 // to the available limit. We do do that, but only if the
667 // total file size is unknown. We could decide to always
668 // use what's available as our limit (irrespective of whether
669 // we happen to know the total file length). This would have
670 // as its sense "parse this much of the file before giving up",
671 // which a slightly different sense from "try to parse up to
672 // 10 EMBL elements before giving up".
673
674 for (;;) {
675 if ((total >= 0) && (pos >= total))
676 return E_FILE_FORMAT_INVALID;
677
678 // Read ID
679 long len;
680 long long result = GetUIntLength(pReader, pos, len);
681
682 if (result) // error, or too few available bytes
683 return result;
684
685 if ((total >= 0) && ((pos + len) > total))
686 return E_FILE_FORMAT_INVALID;
687
688 if ((pos + len) > available)
689 return pos + len;
690
691 const long long idpos = pos;
692 const long long id = ReadUInt(pReader, pos, len);
693
694 if (id < 0) // error
695 return id;
696
697 pos += len; // consume ID
698
699 // Read Size
700
701 result = GetUIntLength(pReader, pos, len);
702
703 if (result) // error, or too few available bytes
704 return result;
705
706 if ((total >= 0) && ((pos + len) > total))
707 return E_FILE_FORMAT_INVALID;
708
709 if ((pos + len) > available)
710 return pos + len;
711
712 long long size = ReadUInt(pReader, pos, len);
713
714 if (size < 0) // error
715 return size;
716
717 pos += len; // consume length of size of element
718
719 // Pos now points to start of payload
720
721 // Handle "unknown size" for live streaming of webm files.
722 const long long unknown_size = (1LL << (7 * len)) - 1;
723
724 if (id == 0x08538067) { // Segment ID
725 if (size == unknown_size)
726 size = -1;
727
728 else if (total < 0)
729 size = -1;
730
731 else if ((pos + size) > total)
732 size = -1;
733
734 pSegment = new (std::nothrow) Segment(pReader, idpos,
735 // elem_size
736 pos, size);
737
738 if (pSegment == 0)
739 return -1; // generic error
740
741 return 0; // success
742 }
743
744 if (size == unknown_size)
745 return E_FILE_FORMAT_INVALID;
746
747 if ((total >= 0) && ((pos + size) > total))
748 return E_FILE_FORMAT_INVALID;
749
750 if ((pos + size) > available)
751 return pos + size;
752
753 pos += size; // consume payload
754 }
755 }
756
ParseHeaders()757 long long Segment::ParseHeaders() {
758 // Outermost (level 0) segment object has been constructed,
759 // and pos designates start of payload. We need to find the
760 // inner (level 1) elements.
761 long long total, available;
762
763 const int status = m_pReader->Length(&total, &available);
764
765 if (status < 0) // error
766 return status;
767
768 assert((total < 0) || (available <= total));
769
770 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
771 assert((segment_stop < 0) || (total < 0) || (segment_stop <= total));
772 assert((segment_stop < 0) || (m_pos <= segment_stop));
773
774 for (;;) {
775 if ((total >= 0) && (m_pos >= total))
776 break;
777
778 if ((segment_stop >= 0) && (m_pos >= segment_stop))
779 break;
780
781 long long pos = m_pos;
782 const long long element_start = pos;
783
784 if ((pos + 1) > available)
785 return (pos + 1);
786
787 long len;
788 long long result = GetUIntLength(m_pReader, pos, len);
789
790 if (result < 0) // error
791 return result;
792
793 if (result > 0) // underflow (weird)
794 return (pos + 1);
795
796 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
797 return E_FILE_FORMAT_INVALID;
798
799 if ((pos + len) > available)
800 return pos + len;
801
802 const long long idpos = pos;
803 const long long id = ReadUInt(m_pReader, idpos, len);
804
805 if (id < 0) // error
806 return id;
807
808 if (id == 0x0F43B675) // Cluster ID
809 break;
810
811 pos += len; // consume ID
812
813 if ((pos + 1) > available)
814 return (pos + 1);
815
816 // Read Size
817 result = GetUIntLength(m_pReader, pos, len);
818
819 if (result < 0) // error
820 return result;
821
822 if (result > 0) // underflow (weird)
823 return (pos + 1);
824
825 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
826 return E_FILE_FORMAT_INVALID;
827
828 if ((pos + len) > available)
829 return pos + len;
830
831 const long long size = ReadUInt(m_pReader, pos, len);
832
833 if (size < 0) // error
834 return size;
835
836 pos += len; // consume length of size of element
837
838 const long long element_size = size + pos - element_start;
839
840 // Pos now points to start of payload
841
842 if ((segment_stop >= 0) && ((pos + size) > segment_stop))
843 return E_FILE_FORMAT_INVALID;
844
845 // We read EBML elements either in total or nothing at all.
846
847 if ((pos + size) > available)
848 return pos + size;
849
850 if (id == 0x0549A966) { // Segment Info ID
851 if (m_pInfo)
852 return E_FILE_FORMAT_INVALID;
853
854 m_pInfo = new (std::nothrow)
855 SegmentInfo(this, pos, size, element_start, element_size);
856
857 if (m_pInfo == NULL)
858 return -1;
859
860 const long status = m_pInfo->Parse();
861
862 if (status)
863 return status;
864 } else if (id == 0x0654AE6B) { // Tracks ID
865 if (m_pTracks)
866 return E_FILE_FORMAT_INVALID;
867
868 m_pTracks = new (std::nothrow)
869 Tracks(this, pos, size, element_start, element_size);
870
871 if (m_pTracks == NULL)
872 return -1;
873
874 const long status = m_pTracks->Parse();
875
876 if (status)
877 return status;
878 } else if (id == 0x0C53BB6B) { // Cues ID
879 if (m_pCues == NULL) {
880 m_pCues = new (std::nothrow)
881 Cues(this, pos, size, element_start, element_size);
882
883 if (m_pCues == NULL)
884 return -1;
885 }
886 } else if (id == 0x014D9B74) { // SeekHead ID
887 if (m_pSeekHead == NULL) {
888 m_pSeekHead = new (std::nothrow)
889 SeekHead(this, pos, size, element_start, element_size);
890
891 if (m_pSeekHead == NULL)
892 return -1;
893
894 const long status = m_pSeekHead->Parse();
895
896 if (status)
897 return status;
898 }
899 } else if (id == 0x0043A770) { // Chapters ID
900 if (m_pChapters == NULL) {
901 m_pChapters = new (std::nothrow)
902 Chapters(this, pos, size, element_start, element_size);
903
904 if (m_pChapters == NULL)
905 return -1;
906
907 const long status = m_pChapters->Parse();
908
909 if (status)
910 return status;
911 }
912 }
913
914 m_pos = pos + size; // consume payload
915 }
916
917 assert((segment_stop < 0) || (m_pos <= segment_stop));
918
919 if (m_pInfo == NULL) // TODO: liberalize this behavior
920 return E_FILE_FORMAT_INVALID;
921
922 if (m_pTracks == NULL)
923 return E_FILE_FORMAT_INVALID;
924
925 return 0; // success
926 }
927
LoadCluster(long long & pos,long & len)928 long Segment::LoadCluster(long long& pos, long& len) {
929 for (;;) {
930 const long result = DoLoadCluster(pos, len);
931
932 if (result <= 1)
933 return result;
934 }
935 }
936
DoLoadCluster(long long & pos,long & len)937 long Segment::DoLoadCluster(long long& pos, long& len) {
938 if (m_pos < 0)
939 return DoLoadClusterUnknownSize(pos, len);
940
941 long long total, avail;
942
943 long status = m_pReader->Length(&total, &avail);
944
945 if (status < 0) // error
946 return status;
947
948 assert((total < 0) || (avail <= total));
949
950 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
951
952 long long cluster_off = -1; // offset relative to start of segment
953 long long cluster_size = -1; // size of cluster payload
954
955 for (;;) {
956 if ((total >= 0) && (m_pos >= total))
957 return 1; // no more clusters
958
959 if ((segment_stop >= 0) && (m_pos >= segment_stop))
960 return 1; // no more clusters
961
962 pos = m_pos;
963
964 // Read ID
965
966 if ((pos + 1) > avail) {
967 len = 1;
968 return E_BUFFER_NOT_FULL;
969 }
970
971 long long result = GetUIntLength(m_pReader, pos, len);
972
973 if (result < 0) // error
974 return static_cast<long>(result);
975
976 if (result > 0) // weird
977 return E_BUFFER_NOT_FULL;
978
979 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
980 return E_FILE_FORMAT_INVALID;
981
982 if ((pos + len) > avail)
983 return E_BUFFER_NOT_FULL;
984
985 const long long idpos = pos;
986 const long long id = ReadUInt(m_pReader, idpos, len);
987
988 if (id < 0) // error (or underflow)
989 return static_cast<long>(id);
990
991 pos += len; // consume ID
992
993 // Read Size
994
995 if ((pos + 1) > avail) {
996 len = 1;
997 return E_BUFFER_NOT_FULL;
998 }
999
1000 result = GetUIntLength(m_pReader, pos, len);
1001
1002 if (result < 0) // error
1003 return static_cast<long>(result);
1004
1005 if (result > 0) // weird
1006 return E_BUFFER_NOT_FULL;
1007
1008 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1009 return E_FILE_FORMAT_INVALID;
1010
1011 if ((pos + len) > avail)
1012 return E_BUFFER_NOT_FULL;
1013
1014 const long long size = ReadUInt(m_pReader, pos, len);
1015
1016 if (size < 0) // error
1017 return static_cast<long>(size);
1018
1019 pos += len; // consume length of size of element
1020
1021 // pos now points to start of payload
1022
1023 if (size == 0) { // weird
1024 m_pos = pos;
1025 continue;
1026 }
1027
1028 const long long unknown_size = (1LL << (7 * len)) - 1;
1029
1030 #if 0 // we must handle this to support live webm
1031 if (size == unknown_size)
1032 return E_FILE_FORMAT_INVALID; //TODO: allow this
1033 #endif
1034
1035 if ((segment_stop >= 0) && (size != unknown_size) &&
1036 ((pos + size) > segment_stop)) {
1037 return E_FILE_FORMAT_INVALID;
1038 }
1039
1040 #if 0 // commented-out, to support incremental cluster parsing
1041 len = static_cast<long>(size);
1042
1043 if ((pos + size) > avail)
1044 return E_BUFFER_NOT_FULL;
1045 #endif
1046
1047 if (id == 0x0C53BB6B) { // Cues ID
1048 if (size == unknown_size)
1049 return E_FILE_FORMAT_INVALID; // TODO: liberalize
1050
1051 if (m_pCues == NULL) {
1052 const long long element_size = (pos - idpos) + size;
1053
1054 m_pCues = new Cues(this, pos, size, idpos, element_size);
1055 assert(m_pCues); // TODO
1056 }
1057
1058 m_pos = pos + size; // consume payload
1059 continue;
1060 }
1061
1062 if (id != 0x0F43B675) { // Cluster ID
1063 if (size == unknown_size)
1064 return E_FILE_FORMAT_INVALID; // TODO: liberalize
1065
1066 m_pos = pos + size; // consume payload
1067 continue;
1068 }
1069
1070 // We have a cluster.
1071
1072 cluster_off = idpos - m_start; // relative pos
1073
1074 if (size != unknown_size)
1075 cluster_size = size;
1076
1077 break;
1078 }
1079
1080 assert(cluster_off >= 0); // have cluster
1081
1082 long long pos_;
1083 long len_;
1084
1085 status = Cluster::HasBlockEntries(this, cluster_off, pos_, len_);
1086
1087 if (status < 0) { // error, or underflow
1088 pos = pos_;
1089 len = len_;
1090
1091 return status;
1092 }
1093
1094 // status == 0 means "no block entries found"
1095 // status > 0 means "found at least one block entry"
1096
1097 // TODO:
1098 // The issue here is that the segment increments its own
1099 // pos ptr past the most recent cluster parsed, and then
1100 // starts from there to parse the next cluster. If we
1101 // don't know the size of the current cluster, then we
1102 // must either parse its payload (as we do below), looking
1103 // for the cluster (or cues) ID to terminate the parse.
1104 // This isn't really what we want: rather, we really need
1105 // a way to create the curr cluster object immediately.
1106 // The pity is that cluster::parse can determine its own
1107 // boundary, and we largely duplicate that same logic here.
1108 //
1109 // Maybe we need to get rid of our look-ahead preloading
1110 // in source::parse???
1111 //
1112 // As we're parsing the blocks in the curr cluster
1113 //(in cluster::parse), we should have some way to signal
1114 // to the segment that we have determined the boundary,
1115 // so it can adjust its own segment::m_pos member.
1116 //
1117 // The problem is that we're asserting in asyncreadinit,
1118 // because we adjust the pos down to the curr seek pos,
1119 // and the resulting adjusted len is > 2GB. I'm suspicious
1120 // that this is even correct, but even if it is, we can't
1121 // be loading that much data in the cache anyway.
1122
1123 const long idx = m_clusterCount;
1124
1125 if (m_clusterPreloadCount > 0) {
1126 assert(idx < m_clusterSize);
1127
1128 Cluster* const pCluster = m_clusters[idx];
1129 assert(pCluster);
1130 assert(pCluster->m_index < 0);
1131
1132 const long long off = pCluster->GetPosition();
1133 assert(off >= 0);
1134
1135 if (off == cluster_off) { // preloaded already
1136 if (status == 0) // no entries found
1137 return E_FILE_FORMAT_INVALID;
1138
1139 if (cluster_size >= 0)
1140 pos += cluster_size;
1141 else {
1142 const long long element_size = pCluster->GetElementSize();
1143
1144 if (element_size <= 0)
1145 return E_FILE_FORMAT_INVALID; // TODO: handle this case
1146
1147 pos = pCluster->m_element_start + element_size;
1148 }
1149
1150 pCluster->m_index = idx; // move from preloaded to loaded
1151 ++m_clusterCount;
1152 --m_clusterPreloadCount;
1153
1154 m_pos = pos; // consume payload
1155 assert((segment_stop < 0) || (m_pos <= segment_stop));
1156
1157 return 0; // success
1158 }
1159 }
1160
1161 if (status == 0) { // no entries found
1162 if (cluster_size < 0)
1163 return E_FILE_FORMAT_INVALID; // TODO: handle this
1164
1165 pos += cluster_size;
1166
1167 if ((total >= 0) && (pos >= total)) {
1168 m_pos = total;
1169 return 1; // no more clusters
1170 }
1171
1172 if ((segment_stop >= 0) && (pos >= segment_stop)) {
1173 m_pos = segment_stop;
1174 return 1; // no more clusters
1175 }
1176
1177 m_pos = pos;
1178 return 2; // try again
1179 }
1180
1181 // status > 0 means we have an entry
1182
1183 Cluster* const pCluster = Cluster::Create(this, idx, cluster_off);
1184 // element_size);
1185 assert(pCluster);
1186
1187 AppendCluster(pCluster);
1188 assert(m_clusters);
1189 assert(idx < m_clusterSize);
1190 assert(m_clusters[idx] == pCluster);
1191
1192 if (cluster_size >= 0) {
1193 pos += cluster_size;
1194
1195 m_pos = pos;
1196 assert((segment_stop < 0) || (m_pos <= segment_stop));
1197
1198 return 0;
1199 }
1200
1201 m_pUnknownSize = pCluster;
1202 m_pos = -pos;
1203
1204 return 0; // partial success, since we have a new cluster
1205
1206 // status == 0 means "no block entries found"
1207
1208 // pos designates start of payload
1209 // m_pos has NOT been adjusted yet (in case we need to come back here)
1210
1211 #if 0
1212
1213 if (cluster_size < 0) { //unknown size
1214 const long long payload_pos = pos; //absolute pos of cluster payload
1215
1216 for (;;) { //determine cluster size
1217 if ((total >= 0) && (pos >= total))
1218 break;
1219
1220 if ((segment_stop >= 0) && (pos >= segment_stop))
1221 break; //no more clusters
1222
1223 //Read ID
1224
1225 if ((pos + 1) > avail)
1226 {
1227 len = 1;
1228 return E_BUFFER_NOT_FULL;
1229 }
1230
1231 long long result = GetUIntLength(m_pReader, pos, len);
1232
1233 if (result < 0) //error
1234 return static_cast<long>(result);
1235
1236 if (result > 0) //weird
1237 return E_BUFFER_NOT_FULL;
1238
1239 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1240 return E_FILE_FORMAT_INVALID;
1241
1242 if ((pos + len) > avail)
1243 return E_BUFFER_NOT_FULL;
1244
1245 const long long idpos = pos;
1246 const long long id = ReadUInt(m_pReader, idpos, len);
1247
1248 if (id < 0) //error (or underflow)
1249 return static_cast<long>(id);
1250
1251 //This is the distinguished set of ID's we use to determine
1252 //that we have exhausted the sub-element's inside the cluster
1253 //whose ID we parsed earlier.
1254
1255 if (id == 0x0F43B675) //Cluster ID
1256 break;
1257
1258 if (id == 0x0C53BB6B) //Cues ID
1259 break;
1260
1261 switch (id)
1262 {
1263 case 0x20: //BlockGroup
1264 case 0x23: //Simple Block
1265 case 0x67: //TimeCode
1266 case 0x2B: //PrevSize
1267 break;
1268
1269 default:
1270 assert(false);
1271 break;
1272 }
1273
1274 pos += len; //consume ID (of sub-element)
1275
1276 //Read Size
1277
1278 if ((pos + 1) > avail)
1279 {
1280 len = 1;
1281 return E_BUFFER_NOT_FULL;
1282 }
1283
1284 result = GetUIntLength(m_pReader, pos, len);
1285
1286 if (result < 0) //error
1287 return static_cast<long>(result);
1288
1289 if (result > 0) //weird
1290 return E_BUFFER_NOT_FULL;
1291
1292 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1293 return E_FILE_FORMAT_INVALID;
1294
1295 if ((pos + len) > avail)
1296 return E_BUFFER_NOT_FULL;
1297
1298 const long long size = ReadUInt(m_pReader, pos, len);
1299
1300 if (size < 0) //error
1301 return static_cast<long>(size);
1302
1303 pos += len; //consume size field of element
1304
1305 //pos now points to start of sub-element's payload
1306
1307 if (size == 0) //weird
1308 continue;
1309
1310 const long long unknown_size = (1LL << (7 * len)) - 1;
1311
1312 if (size == unknown_size)
1313 return E_FILE_FORMAT_INVALID; //not allowed for sub-elements
1314
1315 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird
1316 return E_FILE_FORMAT_INVALID;
1317
1318 pos += size; //consume payload of sub-element
1319 assert((segment_stop < 0) || (pos <= segment_stop));
1320 } //determine cluster size
1321
1322 cluster_size = pos - payload_pos;
1323 assert(cluster_size >= 0);
1324
1325 pos = payload_pos; //reset and re-parse original cluster
1326 }
1327
1328 if (m_clusterPreloadCount > 0)
1329 {
1330 assert(idx < m_clusterSize);
1331
1332 Cluster* const pCluster = m_clusters[idx];
1333 assert(pCluster);
1334 assert(pCluster->m_index < 0);
1335
1336 const long long off = pCluster->GetPosition();
1337 assert(off >= 0);
1338
1339 if (off == cluster_off) //preloaded already
1340 return E_FILE_FORMAT_INVALID; //subtle
1341 }
1342
1343 m_pos = pos + cluster_size; //consume payload
1344 assert((segment_stop < 0) || (m_pos <= segment_stop));
1345
1346 return 2; //try to find another cluster
1347
1348 #endif
1349 }
1350
DoLoadClusterUnknownSize(long long & pos,long & len)1351 long Segment::DoLoadClusterUnknownSize(long long& pos, long& len) {
1352 assert(m_pos < 0);
1353 assert(m_pUnknownSize);
1354
1355 #if 0
1356 assert(m_pUnknownSize->GetElementSize() < 0); //TODO: verify this
1357
1358 const long long element_start = m_pUnknownSize->m_element_start;
1359
1360 pos = -m_pos;
1361 assert(pos > element_start);
1362
1363 //We have already consumed the (cluster) ID and size fields.
1364 //We just need to consume the blocks and other sub-elements
1365 //of this cluster, until we discover the boundary.
1366
1367 long long total, avail;
1368
1369 long status = m_pReader->Length(&total, &avail);
1370
1371 if (status < 0) //error
1372 return status;
1373
1374 assert((total < 0) || (avail <= total));
1375
1376 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1377
1378 long long element_size = -1;
1379
1380 for (;;) { //determine cluster size
1381 if ((total >= 0) && (pos >= total))
1382 {
1383 element_size = total - element_start;
1384 assert(element_size > 0);
1385
1386 break;
1387 }
1388
1389 if ((segment_stop >= 0) && (pos >= segment_stop))
1390 {
1391 element_size = segment_stop - element_start;
1392 assert(element_size > 0);
1393
1394 break;
1395 }
1396
1397 //Read ID
1398
1399 if ((pos + 1) > avail)
1400 {
1401 len = 1;
1402 return E_BUFFER_NOT_FULL;
1403 }
1404
1405 long long result = GetUIntLength(m_pReader, pos, len);
1406
1407 if (result < 0) //error
1408 return static_cast<long>(result);
1409
1410 if (result > 0) //weird
1411 return E_BUFFER_NOT_FULL;
1412
1413 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1414 return E_FILE_FORMAT_INVALID;
1415
1416 if ((pos + len) > avail)
1417 return E_BUFFER_NOT_FULL;
1418
1419 const long long idpos = pos;
1420 const long long id = ReadUInt(m_pReader, idpos, len);
1421
1422 if (id < 0) //error (or underflow)
1423 return static_cast<long>(id);
1424
1425 //This is the distinguished set of ID's we use to determine
1426 //that we have exhausted the sub-element's inside the cluster
1427 //whose ID we parsed earlier.
1428
1429 if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { //Cluster ID or Cues ID
1430 element_size = pos - element_start;
1431 assert(element_size > 0);
1432
1433 break;
1434 }
1435
1436 #ifdef _DEBUG
1437 switch (id)
1438 {
1439 case 0x20: //BlockGroup
1440 case 0x23: //Simple Block
1441 case 0x67: //TimeCode
1442 case 0x2B: //PrevSize
1443 break;
1444
1445 default:
1446 assert(false);
1447 break;
1448 }
1449 #endif
1450
1451 pos += len; //consume ID (of sub-element)
1452
1453 //Read Size
1454
1455 if ((pos + 1) > avail)
1456 {
1457 len = 1;
1458 return E_BUFFER_NOT_FULL;
1459 }
1460
1461 result = GetUIntLength(m_pReader, pos, len);
1462
1463 if (result < 0) //error
1464 return static_cast<long>(result);
1465
1466 if (result > 0) //weird
1467 return E_BUFFER_NOT_FULL;
1468
1469 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1470 return E_FILE_FORMAT_INVALID;
1471
1472 if ((pos + len) > avail)
1473 return E_BUFFER_NOT_FULL;
1474
1475 const long long size = ReadUInt(m_pReader, pos, len);
1476
1477 if (size < 0) //error
1478 return static_cast<long>(size);
1479
1480 pos += len; //consume size field of element
1481
1482 //pos now points to start of sub-element's payload
1483
1484 if (size == 0) //weird
1485 continue;
1486
1487 const long long unknown_size = (1LL << (7 * len)) - 1;
1488
1489 if (size == unknown_size)
1490 return E_FILE_FORMAT_INVALID; //not allowed for sub-elements
1491
1492 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird
1493 return E_FILE_FORMAT_INVALID;
1494
1495 pos += size; //consume payload of sub-element
1496 assert((segment_stop < 0) || (pos <= segment_stop));
1497 } //determine cluster size
1498
1499 assert(element_size >= 0);
1500
1501 m_pos = element_start + element_size;
1502 m_pUnknownSize = 0;
1503
1504 return 2; //continue parsing
1505 #else
1506 const long status = m_pUnknownSize->Parse(pos, len);
1507
1508 if (status < 0) // error or underflow
1509 return status;
1510
1511 if (status == 0) // parsed a block
1512 return 2; // continue parsing
1513
1514 assert(status > 0); // nothing left to parse of this cluster
1515
1516 const long long start = m_pUnknownSize->m_element_start;
1517
1518 const long long size = m_pUnknownSize->GetElementSize();
1519 assert(size >= 0);
1520
1521 pos = start + size;
1522 m_pos = pos;
1523
1524 m_pUnknownSize = 0;
1525
1526 return 2; // continue parsing
1527 #endif
1528 }
1529
AppendCluster(Cluster * pCluster)1530 void Segment::AppendCluster(Cluster* pCluster) {
1531 assert(pCluster);
1532 assert(pCluster->m_index >= 0);
1533
1534 const long count = m_clusterCount + m_clusterPreloadCount;
1535
1536 long& size = m_clusterSize;
1537 assert(size >= count);
1538
1539 const long idx = pCluster->m_index;
1540 assert(idx == m_clusterCount);
1541
1542 if (count >= size) {
1543 const long n = (size <= 0) ? 2048 : 2 * size;
1544
1545 Cluster** const qq = new Cluster* [n];
1546 Cluster** q = qq;
1547
1548 Cluster** p = m_clusters;
1549 Cluster** const pp = p + count;
1550
1551 while (p != pp)
1552 *q++ = *p++;
1553
1554 delete[] m_clusters;
1555
1556 m_clusters = qq;
1557 size = n;
1558 }
1559
1560 if (m_clusterPreloadCount > 0) {
1561 assert(m_clusters);
1562
1563 Cluster** const p = m_clusters + m_clusterCount;
1564 assert(*p);
1565 assert((*p)->m_index < 0);
1566
1567 Cluster** q = p + m_clusterPreloadCount;
1568 assert(q < (m_clusters + size));
1569
1570 for (;;) {
1571 Cluster** const qq = q - 1;
1572 assert((*qq)->m_index < 0);
1573
1574 *q = *qq;
1575 q = qq;
1576
1577 if (q == p)
1578 break;
1579 }
1580 }
1581
1582 m_clusters[idx] = pCluster;
1583 ++m_clusterCount;
1584 }
1585
PreloadCluster(Cluster * pCluster,ptrdiff_t idx)1586 void Segment::PreloadCluster(Cluster* pCluster, ptrdiff_t idx) {
1587 assert(pCluster);
1588 assert(pCluster->m_index < 0);
1589 assert(idx >= m_clusterCount);
1590
1591 const long count = m_clusterCount + m_clusterPreloadCount;
1592
1593 long& size = m_clusterSize;
1594 assert(size >= count);
1595
1596 if (count >= size) {
1597 const long n = (size <= 0) ? 2048 : 2 * size;
1598
1599 Cluster** const qq = new Cluster* [n];
1600 Cluster** q = qq;
1601
1602 Cluster** p = m_clusters;
1603 Cluster** const pp = p + count;
1604
1605 while (p != pp)
1606 *q++ = *p++;
1607
1608 delete[] m_clusters;
1609
1610 m_clusters = qq;
1611 size = n;
1612 }
1613
1614 assert(m_clusters);
1615
1616 Cluster** const p = m_clusters + idx;
1617
1618 Cluster** q = m_clusters + count;
1619 assert(q >= p);
1620 assert(q < (m_clusters + size));
1621
1622 while (q > p) {
1623 Cluster** const qq = q - 1;
1624 assert((*qq)->m_index < 0);
1625
1626 *q = *qq;
1627 q = qq;
1628 }
1629
1630 m_clusters[idx] = pCluster;
1631 ++m_clusterPreloadCount;
1632 }
1633
Load()1634 long Segment::Load() {
1635 assert(m_clusters == NULL);
1636 assert(m_clusterSize == 0);
1637 assert(m_clusterCount == 0);
1638 // assert(m_size >= 0);
1639
1640 // Outermost (level 0) segment object has been constructed,
1641 // and pos designates start of payload. We need to find the
1642 // inner (level 1) elements.
1643
1644 const long long header_status = ParseHeaders();
1645
1646 if (header_status < 0) // error
1647 return static_cast<long>(header_status);
1648
1649 if (header_status > 0) // underflow
1650 return E_BUFFER_NOT_FULL;
1651
1652 assert(m_pInfo);
1653 assert(m_pTracks);
1654
1655 for (;;) {
1656 const int status = LoadCluster();
1657
1658 if (status < 0) // error
1659 return status;
1660
1661 if (status >= 1) // no more clusters
1662 return 0;
1663 }
1664 }
1665
SeekHead(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)1666 SeekHead::SeekHead(Segment* pSegment, long long start, long long size_,
1667 long long element_start, long long element_size)
1668 : m_pSegment(pSegment),
1669 m_start(start),
1670 m_size(size_),
1671 m_element_start(element_start),
1672 m_element_size(element_size),
1673 m_entries(0),
1674 m_entry_count(0),
1675 m_void_elements(0),
1676 m_void_element_count(0) {}
1677
~SeekHead()1678 SeekHead::~SeekHead() {
1679 delete[] m_entries;
1680 delete[] m_void_elements;
1681 }
1682
Parse()1683 long SeekHead::Parse() {
1684 IMkvReader* const pReader = m_pSegment->m_pReader;
1685
1686 long long pos = m_start;
1687 const long long stop = m_start + m_size;
1688
1689 // first count the seek head entries
1690
1691 int entry_count = 0;
1692 int void_element_count = 0;
1693
1694 while (pos < stop) {
1695 long long id, size;
1696
1697 const long status = ParseElementHeader(pReader, pos, stop, id, size);
1698
1699 if (status < 0) // error
1700 return status;
1701
1702 if (id == 0x0DBB) // SeekEntry ID
1703 ++entry_count;
1704 else if (id == 0x6C) // Void ID
1705 ++void_element_count;
1706
1707 pos += size; // consume payload
1708 assert(pos <= stop);
1709 }
1710
1711 assert(pos == stop);
1712
1713 m_entries = new (std::nothrow) Entry[entry_count];
1714
1715 if (m_entries == NULL)
1716 return -1;
1717
1718 m_void_elements = new (std::nothrow) VoidElement[void_element_count];
1719
1720 if (m_void_elements == NULL)
1721 return -1;
1722
1723 // now parse the entries and void elements
1724
1725 Entry* pEntry = m_entries;
1726 VoidElement* pVoidElement = m_void_elements;
1727
1728 pos = m_start;
1729
1730 while (pos < stop) {
1731 const long long idpos = pos;
1732
1733 long long id, size;
1734
1735 const long status = ParseElementHeader(pReader, pos, stop, id, size);
1736
1737 if (status < 0) // error
1738 return status;
1739
1740 if (id == 0x0DBB) { // SeekEntry ID
1741 if (ParseEntry(pReader, pos, size, pEntry)) {
1742 Entry& e = *pEntry++;
1743
1744 e.element_start = idpos;
1745 e.element_size = (pos + size) - idpos;
1746 }
1747 } else if (id == 0x6C) { // Void ID
1748 VoidElement& e = *pVoidElement++;
1749
1750 e.element_start = idpos;
1751 e.element_size = (pos + size) - idpos;
1752 }
1753
1754 pos += size; // consume payload
1755 assert(pos <= stop);
1756 }
1757
1758 assert(pos == stop);
1759
1760 ptrdiff_t count_ = ptrdiff_t(pEntry - m_entries);
1761 assert(count_ >= 0);
1762 assert(count_ <= entry_count);
1763
1764 m_entry_count = static_cast<int>(count_);
1765
1766 count_ = ptrdiff_t(pVoidElement - m_void_elements);
1767 assert(count_ >= 0);
1768 assert(count_ <= void_element_count);
1769
1770 m_void_element_count = static_cast<int>(count_);
1771
1772 return 0;
1773 }
1774
GetCount() const1775 int SeekHead::GetCount() const { return m_entry_count; }
1776
GetEntry(int idx) const1777 const SeekHead::Entry* SeekHead::GetEntry(int idx) const {
1778 if (idx < 0)
1779 return 0;
1780
1781 if (idx >= m_entry_count)
1782 return 0;
1783
1784 return m_entries + idx;
1785 }
1786
GetVoidElementCount() const1787 int SeekHead::GetVoidElementCount() const { return m_void_element_count; }
1788
GetVoidElement(int idx) const1789 const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const {
1790 if (idx < 0)
1791 return 0;
1792
1793 if (idx >= m_void_element_count)
1794 return 0;
1795
1796 return m_void_elements + idx;
1797 }
1798
1799 #if 0
1800 void Segment::ParseCues(long long off)
1801 {
1802 if (m_pCues)
1803 return;
1804
1805 //odbgstream os;
1806 //os << "Segment::ParseCues (begin)" << endl;
1807
1808 long long pos = m_start + off;
1809 const long long element_start = pos;
1810 const long long stop = m_start + m_size;
1811
1812 long len;
1813
1814 long long result = GetUIntLength(m_pReader, pos, len);
1815 assert(result == 0);
1816 assert((pos + len) <= stop);
1817
1818 const long long idpos = pos;
1819
1820 const long long id = ReadUInt(m_pReader, idpos, len);
1821 assert(id == 0x0C53BB6B); //Cues ID
1822
1823 pos += len; //consume ID
1824 assert(pos < stop);
1825
1826 //Read Size
1827
1828 result = GetUIntLength(m_pReader, pos, len);
1829 assert(result == 0);
1830 assert((pos + len) <= stop);
1831
1832 const long long size = ReadUInt(m_pReader, pos, len);
1833 assert(size >= 0);
1834
1835 pos += len; //consume length of size of element
1836 assert((pos + size) <= stop);
1837
1838 const long long element_size = size + pos - element_start;
1839
1840 //Pos now points to start of payload
1841
1842 m_pCues = new Cues(this, pos, size, element_start, element_size);
1843 assert(m_pCues); //TODO
1844
1845 //os << "Segment::ParseCues (end)" << endl;
1846 }
1847 #else
ParseCues(long long off,long long & pos,long & len)1848 long Segment::ParseCues(long long off, long long& pos, long& len) {
1849 if (m_pCues)
1850 return 0; // success
1851
1852 if (off < 0)
1853 return -1;
1854
1855 long long total, avail;
1856
1857 const int status = m_pReader->Length(&total, &avail);
1858
1859 if (status < 0) // error
1860 return status;
1861
1862 assert((total < 0) || (avail <= total));
1863
1864 pos = m_start + off;
1865
1866 if ((total < 0) || (pos >= total))
1867 return 1; // don't bother parsing cues
1868
1869 const long long element_start = pos;
1870 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
1871
1872 if ((pos + 1) > avail) {
1873 len = 1;
1874 return E_BUFFER_NOT_FULL;
1875 }
1876
1877 long long result = GetUIntLength(m_pReader, pos, len);
1878
1879 if (result < 0) // error
1880 return static_cast<long>(result);
1881
1882 if (result > 0) // underflow (weird)
1883 {
1884 len = 1;
1885 return E_BUFFER_NOT_FULL;
1886 }
1887
1888 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1889 return E_FILE_FORMAT_INVALID;
1890
1891 if ((pos + len) > avail)
1892 return E_BUFFER_NOT_FULL;
1893
1894 const long long idpos = pos;
1895
1896 const long long id = ReadUInt(m_pReader, idpos, len);
1897
1898 if (id != 0x0C53BB6B) // Cues ID
1899 return E_FILE_FORMAT_INVALID;
1900
1901 pos += len; // consume ID
1902 assert((segment_stop < 0) || (pos <= segment_stop));
1903
1904 // Read Size
1905
1906 if ((pos + 1) > avail) {
1907 len = 1;
1908 return E_BUFFER_NOT_FULL;
1909 }
1910
1911 result = GetUIntLength(m_pReader, pos, len);
1912
1913 if (result < 0) // error
1914 return static_cast<long>(result);
1915
1916 if (result > 0) // underflow (weird)
1917 {
1918 len = 1;
1919 return E_BUFFER_NOT_FULL;
1920 }
1921
1922 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
1923 return E_FILE_FORMAT_INVALID;
1924
1925 if ((pos + len) > avail)
1926 return E_BUFFER_NOT_FULL;
1927
1928 const long long size = ReadUInt(m_pReader, pos, len);
1929
1930 if (size < 0) // error
1931 return static_cast<long>(size);
1932
1933 if (size == 0) // weird, although technically not illegal
1934 return 1; // done
1935
1936 pos += len; // consume length of size of element
1937 assert((segment_stop < 0) || (pos <= segment_stop));
1938
1939 // Pos now points to start of payload
1940
1941 const long long element_stop = pos + size;
1942
1943 if ((segment_stop >= 0) && (element_stop > segment_stop))
1944 return E_FILE_FORMAT_INVALID;
1945
1946 if ((total >= 0) && (element_stop > total))
1947 return 1; // don't bother parsing anymore
1948
1949 len = static_cast<long>(size);
1950
1951 if (element_stop > avail)
1952 return E_BUFFER_NOT_FULL;
1953
1954 const long long element_size = element_stop - element_start;
1955
1956 m_pCues =
1957 new (std::nothrow) Cues(this, pos, size, element_start, element_size);
1958 assert(m_pCues); // TODO
1959
1960 return 0; // success
1961 }
1962 #endif
1963
1964 #if 0
1965 void Segment::ParseSeekEntry(
1966 long long start,
1967 long long size_)
1968 {
1969 long long pos = start;
1970
1971 const long long stop = start + size_;
1972
1973 long len;
1974
1975 const long long seekIdId = ReadUInt(m_pReader, pos, len);
1976 //seekIdId;
1977 assert(seekIdId == 0x13AB); //SeekID ID
1978 assert((pos + len) <= stop);
1979
1980 pos += len; //consume id
1981
1982 const long long seekIdSize = ReadUInt(m_pReader, pos, len);
1983 assert(seekIdSize >= 0);
1984 assert((pos + len) <= stop);
1985
1986 pos += len; //consume size
1987
1988 const long long seekId = ReadUInt(m_pReader, pos, len); //payload
1989 assert(seekId >= 0);
1990 assert(len == seekIdSize);
1991 assert((pos + len) <= stop);
1992
1993 pos += seekIdSize; //consume payload
1994
1995 const long long seekPosId = ReadUInt(m_pReader, pos, len);
1996 //seekPosId;
1997 assert(seekPosId == 0x13AC); //SeekPos ID
1998 assert((pos + len) <= stop);
1999
2000 pos += len; //consume id
2001
2002 const long long seekPosSize = ReadUInt(m_pReader, pos, len);
2003 assert(seekPosSize >= 0);
2004 assert((pos + len) <= stop);
2005
2006 pos += len; //consume size
2007 assert((pos + seekPosSize) <= stop);
2008
2009 const long long seekOff = UnserializeUInt(m_pReader, pos, seekPosSize);
2010 assert(seekOff >= 0);
2011 assert(seekOff < m_size);
2012
2013 pos += seekPosSize; //consume payload
2014 assert(pos == stop);
2015
2016 const long long seekPos = m_start + seekOff;
2017 assert(seekPos < (m_start + m_size));
2018
2019 if (seekId == 0x0C53BB6B) //Cues ID
2020 ParseCues(seekOff);
2021 }
2022 #else
ParseEntry(IMkvReader * pReader,long long start,long long size_,Entry * pEntry)2023 bool SeekHead::ParseEntry(IMkvReader* pReader, long long start, long long size_,
2024 Entry* pEntry) {
2025 if (size_ <= 0)
2026 return false;
2027
2028 long long pos = start;
2029 const long long stop = start + size_;
2030
2031 long len;
2032
2033 // parse the container for the level-1 element ID
2034
2035 const long long seekIdId = ReadUInt(pReader, pos, len);
2036 // seekIdId;
2037
2038 if (seekIdId != 0x13AB) // SeekID ID
2039 return false;
2040
2041 if ((pos + len) > stop)
2042 return false;
2043
2044 pos += len; // consume SeekID id
2045
2046 const long long seekIdSize = ReadUInt(pReader, pos, len);
2047
2048 if (seekIdSize <= 0)
2049 return false;
2050
2051 if ((pos + len) > stop)
2052 return false;
2053
2054 pos += len; // consume size of field
2055
2056 if ((pos + seekIdSize) > stop)
2057 return false;
2058
2059 // Note that the SeekId payload really is serialized
2060 // as a "Matroska integer", not as a plain binary value.
2061 // In fact, Matroska requires that ID values in the
2062 // stream exactly match the binary representation as listed
2063 // in the Matroska specification.
2064 //
2065 // This parser is more liberal, and permits IDs to have
2066 // any width. (This could make the representation in the stream
2067 // different from what's in the spec, but it doesn't matter here,
2068 // since we always normalize "Matroska integer" values.)
2069
2070 pEntry->id = ReadUInt(pReader, pos, len); // payload
2071
2072 if (pEntry->id <= 0)
2073 return false;
2074
2075 if (len != seekIdSize)
2076 return false;
2077
2078 pos += seekIdSize; // consume SeekID payload
2079
2080 const long long seekPosId = ReadUInt(pReader, pos, len);
2081
2082 if (seekPosId != 0x13AC) // SeekPos ID
2083 return false;
2084
2085 if ((pos + len) > stop)
2086 return false;
2087
2088 pos += len; // consume id
2089
2090 const long long seekPosSize = ReadUInt(pReader, pos, len);
2091
2092 if (seekPosSize <= 0)
2093 return false;
2094
2095 if ((pos + len) > stop)
2096 return false;
2097
2098 pos += len; // consume size
2099
2100 if ((pos + seekPosSize) > stop)
2101 return false;
2102
2103 pEntry->pos = UnserializeUInt(pReader, pos, seekPosSize);
2104
2105 if (pEntry->pos < 0)
2106 return false;
2107
2108 pos += seekPosSize; // consume payload
2109
2110 if (pos != stop)
2111 return false;
2112
2113 return true;
2114 }
2115 #endif
2116
Cues(Segment * pSegment,long long start_,long long size_,long long element_start,long long element_size)2117 Cues::Cues(Segment* pSegment, long long start_, long long size_,
2118 long long element_start, long long element_size)
2119 : m_pSegment(pSegment),
2120 m_start(start_),
2121 m_size(size_),
2122 m_element_start(element_start),
2123 m_element_size(element_size),
2124 m_cue_points(NULL),
2125 m_count(0),
2126 m_preload_count(0),
2127 m_pos(start_) {}
2128
~Cues()2129 Cues::~Cues() {
2130 const long n = m_count + m_preload_count;
2131
2132 CuePoint** p = m_cue_points;
2133 CuePoint** const q = p + n;
2134
2135 while (p != q) {
2136 CuePoint* const pCP = *p++;
2137 assert(pCP);
2138
2139 delete pCP;
2140 }
2141
2142 delete[] m_cue_points;
2143 }
2144
GetCount() const2145 long Cues::GetCount() const {
2146 if (m_cue_points == NULL)
2147 return -1;
2148
2149 return m_count; // TODO: really ignore preload count?
2150 }
2151
DoneParsing() const2152 bool Cues::DoneParsing() const {
2153 const long long stop = m_start + m_size;
2154 return (m_pos >= stop);
2155 }
2156
Init() const2157 void Cues::Init() const {
2158 if (m_cue_points)
2159 return;
2160
2161 assert(m_count == 0);
2162 assert(m_preload_count == 0);
2163
2164 IMkvReader* const pReader = m_pSegment->m_pReader;
2165
2166 const long long stop = m_start + m_size;
2167 long long pos = m_start;
2168
2169 long cue_points_size = 0;
2170
2171 while (pos < stop) {
2172 const long long idpos = pos;
2173
2174 long len;
2175
2176 const long long id = ReadUInt(pReader, pos, len);
2177 assert(id >= 0); // TODO
2178 assert((pos + len) <= stop);
2179
2180 pos += len; // consume ID
2181
2182 const long long size = ReadUInt(pReader, pos, len);
2183 assert(size >= 0);
2184 assert((pos + len) <= stop);
2185
2186 pos += len; // consume Size field
2187 assert((pos + size) <= stop);
2188
2189 if (id == 0x3B) // CuePoint ID
2190 PreloadCuePoint(cue_points_size, idpos);
2191
2192 pos += size; // consume payload
2193 assert(pos <= stop);
2194 }
2195 }
2196
PreloadCuePoint(long & cue_points_size,long long pos) const2197 void Cues::PreloadCuePoint(long& cue_points_size, long long pos) const {
2198 assert(m_count == 0);
2199
2200 if (m_preload_count >= cue_points_size) {
2201 const long n = (cue_points_size <= 0) ? 2048 : 2 * cue_points_size;
2202
2203 CuePoint** const qq = new CuePoint* [n];
2204 CuePoint** q = qq; // beginning of target
2205
2206 CuePoint** p = m_cue_points; // beginning of source
2207 CuePoint** const pp = p + m_preload_count; // end of source
2208
2209 while (p != pp)
2210 *q++ = *p++;
2211
2212 delete[] m_cue_points;
2213
2214 m_cue_points = qq;
2215 cue_points_size = n;
2216 }
2217
2218 CuePoint* const pCP = new CuePoint(m_preload_count, pos);
2219 m_cue_points[m_preload_count++] = pCP;
2220 }
2221
LoadCuePoint() const2222 bool Cues::LoadCuePoint() const {
2223 // odbgstream os;
2224 // os << "Cues::LoadCuePoint" << endl;
2225
2226 const long long stop = m_start + m_size;
2227
2228 if (m_pos >= stop)
2229 return false; // nothing else to do
2230
2231 Init();
2232
2233 IMkvReader* const pReader = m_pSegment->m_pReader;
2234
2235 while (m_pos < stop) {
2236 const long long idpos = m_pos;
2237
2238 long len;
2239
2240 const long long id = ReadUInt(pReader, m_pos, len);
2241 assert(id >= 0); // TODO
2242 assert((m_pos + len) <= stop);
2243
2244 m_pos += len; // consume ID
2245
2246 const long long size = ReadUInt(pReader, m_pos, len);
2247 assert(size >= 0);
2248 assert((m_pos + len) <= stop);
2249
2250 m_pos += len; // consume Size field
2251 assert((m_pos + size) <= stop);
2252
2253 if (id != 0x3B) { // CuePoint ID
2254 m_pos += size; // consume payload
2255 assert(m_pos <= stop);
2256
2257 continue;
2258 }
2259
2260 assert(m_preload_count > 0);
2261
2262 CuePoint* const pCP = m_cue_points[m_count];
2263 assert(pCP);
2264 assert((pCP->GetTimeCode() >= 0) || (-pCP->GetTimeCode() == idpos));
2265 if (pCP->GetTimeCode() < 0 && (-pCP->GetTimeCode() != idpos))
2266 return false;
2267
2268 pCP->Load(pReader);
2269 ++m_count;
2270 --m_preload_count;
2271
2272 m_pos += size; // consume payload
2273 assert(m_pos <= stop);
2274
2275 return true; // yes, we loaded a cue point
2276 }
2277
2278 // return (m_pos < stop);
2279 return false; // no, we did not load a cue point
2280 }
2281
Find(long long time_ns,const Track * pTrack,const CuePoint * & pCP,const CuePoint::TrackPosition * & pTP) const2282 bool Cues::Find(long long time_ns, const Track* pTrack, const CuePoint*& pCP,
2283 const CuePoint::TrackPosition*& pTP) const {
2284 assert(time_ns >= 0);
2285 assert(pTrack);
2286
2287 #if 0
2288 LoadCuePoint(); //establish invariant
2289
2290 assert(m_cue_points);
2291 assert(m_count > 0);
2292
2293 CuePoint** const ii = m_cue_points;
2294 CuePoint** i = ii;
2295
2296 CuePoint** const jj = ii + m_count + m_preload_count;
2297 CuePoint** j = jj;
2298
2299 pCP = *i;
2300 assert(pCP);
2301
2302 if (time_ns <= pCP->GetTime(m_pSegment))
2303 {
2304 pTP = pCP->Find(pTrack);
2305 return (pTP != NULL);
2306 }
2307
2308 IMkvReader* const pReader = m_pSegment->m_pReader;
2309
2310 while (i < j)
2311 {
2312 //INVARIANT:
2313 //[ii, i) <= time_ns
2314 //[i, j) ?
2315 //[j, jj) > time_ns
2316
2317 CuePoint** const k = i + (j - i) / 2;
2318 assert(k < jj);
2319
2320 CuePoint* const pCP = *k;
2321 assert(pCP);
2322
2323 pCP->Load(pReader);
2324
2325 const long long t = pCP->GetTime(m_pSegment);
2326
2327 if (t <= time_ns)
2328 i = k + 1;
2329 else
2330 j = k;
2331
2332 assert(i <= j);
2333 }
2334
2335 assert(i == j);
2336 assert(i <= jj);
2337 assert(i > ii);
2338
2339 pCP = *--i;
2340 assert(pCP);
2341 assert(pCP->GetTime(m_pSegment) <= time_ns);
2342 #else
2343 if (m_cue_points == NULL)
2344 return false;
2345
2346 if (m_count == 0)
2347 return false;
2348
2349 CuePoint** const ii = m_cue_points;
2350 CuePoint** i = ii;
2351
2352 CuePoint** const jj = ii + m_count;
2353 CuePoint** j = jj;
2354
2355 pCP = *i;
2356 assert(pCP);
2357
2358 if (time_ns <= pCP->GetTime(m_pSegment)) {
2359 pTP = pCP->Find(pTrack);
2360 return (pTP != NULL);
2361 }
2362
2363 while (i < j) {
2364 // INVARIANT:
2365 //[ii, i) <= time_ns
2366 //[i, j) ?
2367 //[j, jj) > time_ns
2368
2369 CuePoint** const k = i + (j - i) / 2;
2370 assert(k < jj);
2371
2372 CuePoint* const pCP = *k;
2373 assert(pCP);
2374
2375 const long long t = pCP->GetTime(m_pSegment);
2376
2377 if (t <= time_ns)
2378 i = k + 1;
2379 else
2380 j = k;
2381
2382 assert(i <= j);
2383 }
2384
2385 assert(i == j);
2386 assert(i <= jj);
2387 assert(i > ii);
2388
2389 pCP = *--i;
2390 assert(pCP);
2391 assert(pCP->GetTime(m_pSegment) <= time_ns);
2392 #endif
2393
2394 // TODO: here and elsewhere, it's probably not correct to search
2395 // for the cue point with this time, and then search for a matching
2396 // track. In principle, the matching track could be on some earlier
2397 // cue point, and with our current algorithm, we'd miss it. To make
2398 // this bullet-proof, we'd need to create a secondary structure,
2399 // with a list of cue points that apply to a track, and then search
2400 // that track-based structure for a matching cue point.
2401
2402 pTP = pCP->Find(pTrack);
2403 return (pTP != NULL);
2404 }
2405
2406 #if 0
2407 bool Cues::FindNext(
2408 long long time_ns,
2409 const Track* pTrack,
2410 const CuePoint*& pCP,
2411 const CuePoint::TrackPosition*& pTP) const
2412 {
2413 pCP = 0;
2414 pTP = 0;
2415
2416 if (m_count == 0)
2417 return false;
2418
2419 assert(m_cue_points);
2420
2421 const CuePoint* const* const ii = m_cue_points;
2422 const CuePoint* const* i = ii;
2423
2424 const CuePoint* const* const jj = ii + m_count;
2425 const CuePoint* const* j = jj;
2426
2427 while (i < j)
2428 {
2429 //INVARIANT:
2430 //[ii, i) <= time_ns
2431 //[i, j) ?
2432 //[j, jj) > time_ns
2433
2434 const CuePoint* const* const k = i + (j - i) / 2;
2435 assert(k < jj);
2436
2437 pCP = *k;
2438 assert(pCP);
2439
2440 const long long t = pCP->GetTime(m_pSegment);
2441
2442 if (t <= time_ns)
2443 i = k + 1;
2444 else
2445 j = k;
2446
2447 assert(i <= j);
2448 }
2449
2450 assert(i == j);
2451 assert(i <= jj);
2452
2453 if (i >= jj) //time_ns is greater than max cue point
2454 return false;
2455
2456 pCP = *i;
2457 assert(pCP);
2458 assert(pCP->GetTime(m_pSegment) > time_ns);
2459
2460 pTP = pCP->Find(pTrack);
2461 return (pTP != NULL);
2462 }
2463 #endif
2464
GetFirst() const2465 const CuePoint* Cues::GetFirst() const {
2466 if (m_cue_points == NULL)
2467 return NULL;
2468
2469 if (m_count == 0)
2470 return NULL;
2471
2472 #if 0
2473 LoadCuePoint(); //init cues
2474
2475 const size_t count = m_count + m_preload_count;
2476
2477 if (count == 0) //weird
2478 return NULL;
2479 #endif
2480
2481 CuePoint* const* const pp = m_cue_points;
2482 assert(pp);
2483
2484 CuePoint* const pCP = pp[0];
2485 assert(pCP);
2486 assert(pCP->GetTimeCode() >= 0);
2487
2488 return pCP;
2489 }
2490
GetLast() const2491 const CuePoint* Cues::GetLast() const {
2492 if (m_cue_points == NULL)
2493 return NULL;
2494
2495 if (m_count <= 0)
2496 return NULL;
2497
2498 #if 0
2499 LoadCuePoint(); //init cues
2500
2501 const size_t count = m_count + m_preload_count;
2502
2503 if (count == 0) //weird
2504 return NULL;
2505
2506 const size_t index = count - 1;
2507
2508 CuePoint* const* const pp = m_cue_points;
2509 assert(pp);
2510
2511 CuePoint* const pCP = pp[index];
2512 assert(pCP);
2513
2514 pCP->Load(m_pSegment->m_pReader);
2515 assert(pCP->GetTimeCode() >= 0);
2516 #else
2517 const long index = m_count - 1;
2518
2519 CuePoint* const* const pp = m_cue_points;
2520 assert(pp);
2521
2522 CuePoint* const pCP = pp[index];
2523 assert(pCP);
2524 assert(pCP->GetTimeCode() >= 0);
2525 #endif
2526
2527 return pCP;
2528 }
2529
GetNext(const CuePoint * pCurr) const2530 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const {
2531 if (pCurr == NULL)
2532 return NULL;
2533
2534 assert(pCurr->GetTimeCode() >= 0);
2535 assert(m_cue_points);
2536 assert(m_count >= 1);
2537
2538 #if 0
2539 const size_t count = m_count + m_preload_count;
2540
2541 size_t index = pCurr->m_index;
2542 assert(index < count);
2543
2544 CuePoint* const* const pp = m_cue_points;
2545 assert(pp);
2546 assert(pp[index] == pCurr);
2547
2548 ++index;
2549
2550 if (index >= count)
2551 return NULL;
2552
2553 CuePoint* const pNext = pp[index];
2554 assert(pNext);
2555
2556 pNext->Load(m_pSegment->m_pReader);
2557 #else
2558 long index = pCurr->m_index;
2559 assert(index < m_count);
2560
2561 CuePoint* const* const pp = m_cue_points;
2562 assert(pp);
2563 assert(pp[index] == pCurr);
2564
2565 ++index;
2566
2567 if (index >= m_count)
2568 return NULL;
2569
2570 CuePoint* const pNext = pp[index];
2571 assert(pNext);
2572 assert(pNext->GetTimeCode() >= 0);
2573 #endif
2574
2575 return pNext;
2576 }
2577
GetBlock(const CuePoint * pCP,const CuePoint::TrackPosition * pTP) const2578 const BlockEntry* Cues::GetBlock(const CuePoint* pCP,
2579 const CuePoint::TrackPosition* pTP) const {
2580 if (pCP == NULL)
2581 return NULL;
2582
2583 if (pTP == NULL)
2584 return NULL;
2585
2586 return m_pSegment->GetBlock(*pCP, *pTP);
2587 }
2588
GetBlock(const CuePoint & cp,const CuePoint::TrackPosition & tp)2589 const BlockEntry* Segment::GetBlock(const CuePoint& cp,
2590 const CuePoint::TrackPosition& tp) {
2591 Cluster** const ii = m_clusters;
2592 Cluster** i = ii;
2593
2594 const long count = m_clusterCount + m_clusterPreloadCount;
2595
2596 Cluster** const jj = ii + count;
2597 Cluster** j = jj;
2598
2599 while (i < j) {
2600 // INVARIANT:
2601 //[ii, i) < pTP->m_pos
2602 //[i, j) ?
2603 //[j, jj) > pTP->m_pos
2604
2605 Cluster** const k = i + (j - i) / 2;
2606 assert(k < jj);
2607
2608 Cluster* const pCluster = *k;
2609 assert(pCluster);
2610
2611 // const long long pos_ = pCluster->m_pos;
2612 // assert(pos_);
2613 // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2614
2615 const long long pos = pCluster->GetPosition();
2616 assert(pos >= 0);
2617
2618 if (pos < tp.m_pos)
2619 i = k + 1;
2620 else if (pos > tp.m_pos)
2621 j = k;
2622 else
2623 return pCluster->GetEntry(cp, tp);
2624 }
2625
2626 assert(i == j);
2627 // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2628
2629 Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1);
2630 assert(pCluster);
2631
2632 const ptrdiff_t idx = i - m_clusters;
2633
2634 PreloadCluster(pCluster, idx);
2635 assert(m_clusters);
2636 assert(m_clusterPreloadCount > 0);
2637 assert(m_clusters[idx] == pCluster);
2638
2639 return pCluster->GetEntry(cp, tp);
2640 }
2641
FindOrPreloadCluster(long long requested_pos)2642 const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) {
2643 if (requested_pos < 0)
2644 return 0;
2645
2646 Cluster** const ii = m_clusters;
2647 Cluster** i = ii;
2648
2649 const long count = m_clusterCount + m_clusterPreloadCount;
2650
2651 Cluster** const jj = ii + count;
2652 Cluster** j = jj;
2653
2654 while (i < j) {
2655 // INVARIANT:
2656 //[ii, i) < pTP->m_pos
2657 //[i, j) ?
2658 //[j, jj) > pTP->m_pos
2659
2660 Cluster** const k = i + (j - i) / 2;
2661 assert(k < jj);
2662
2663 Cluster* const pCluster = *k;
2664 assert(pCluster);
2665
2666 // const long long pos_ = pCluster->m_pos;
2667 // assert(pos_);
2668 // const long long pos = pos_ * ((pos_ < 0) ? -1 : 1);
2669
2670 const long long pos = pCluster->GetPosition();
2671 assert(pos >= 0);
2672
2673 if (pos < requested_pos)
2674 i = k + 1;
2675 else if (pos > requested_pos)
2676 j = k;
2677 else
2678 return pCluster;
2679 }
2680
2681 assert(i == j);
2682 // assert(Cluster::HasBlockEntries(this, tp.m_pos));
2683
2684 Cluster* const pCluster = Cluster::Create(this, -1, requested_pos);
2685 //-1);
2686 assert(pCluster);
2687
2688 const ptrdiff_t idx = i - m_clusters;
2689
2690 PreloadCluster(pCluster, idx);
2691 assert(m_clusters);
2692 assert(m_clusterPreloadCount > 0);
2693 assert(m_clusters[idx] == pCluster);
2694
2695 return pCluster;
2696 }
2697
CuePoint(long idx,long long pos)2698 CuePoint::CuePoint(long idx, long long pos)
2699 : m_element_start(0),
2700 m_element_size(0),
2701 m_index(idx),
2702 m_timecode(-1 * pos),
2703 m_track_positions(NULL),
2704 m_track_positions_count(0) {
2705 assert(pos > 0);
2706 }
2707
~CuePoint()2708 CuePoint::~CuePoint() { delete[] m_track_positions; }
2709
Load(IMkvReader * pReader)2710 void CuePoint::Load(IMkvReader* pReader) {
2711 // odbgstream os;
2712 // os << "CuePoint::Load(begin): timecode=" << m_timecode << endl;
2713
2714 if (m_timecode >= 0) // already loaded
2715 return;
2716
2717 assert(m_track_positions == NULL);
2718 assert(m_track_positions_count == 0);
2719
2720 long long pos_ = -m_timecode;
2721 const long long element_start = pos_;
2722
2723 long long stop;
2724
2725 {
2726 long len;
2727
2728 const long long id = ReadUInt(pReader, pos_, len);
2729 assert(id == 0x3B); // CuePoint ID
2730 if (id != 0x3B)
2731 return;
2732
2733 pos_ += len; // consume ID
2734
2735 const long long size = ReadUInt(pReader, pos_, len);
2736 assert(size >= 0);
2737
2738 pos_ += len; // consume Size field
2739 // pos_ now points to start of payload
2740
2741 stop = pos_ + size;
2742 }
2743
2744 const long long element_size = stop - element_start;
2745
2746 long long pos = pos_;
2747
2748 // First count number of track positions
2749
2750 while (pos < stop) {
2751 long len;
2752
2753 const long long id = ReadUInt(pReader, pos, len);
2754 assert(id >= 0); // TODO
2755 assert((pos + len) <= stop);
2756
2757 pos += len; // consume ID
2758
2759 const long long size = ReadUInt(pReader, pos, len);
2760 assert(size >= 0);
2761 assert((pos + len) <= stop);
2762
2763 pos += len; // consume Size field
2764 assert((pos + size) <= stop);
2765
2766 if (id == 0x33) // CueTime ID
2767 m_timecode = UnserializeUInt(pReader, pos, size);
2768
2769 else if (id == 0x37) // CueTrackPosition(s) ID
2770 ++m_track_positions_count;
2771
2772 pos += size; // consume payload
2773 assert(pos <= stop);
2774 }
2775
2776 assert(m_timecode >= 0);
2777 assert(m_track_positions_count > 0);
2778
2779 // os << "CuePoint::Load(cont'd): idpos=" << idpos
2780 // << " timecode=" << m_timecode
2781 // << endl;
2782
2783 m_track_positions = new TrackPosition[m_track_positions_count];
2784
2785 // Now parse track positions
2786
2787 TrackPosition* p = m_track_positions;
2788 pos = pos_;
2789
2790 while (pos < stop) {
2791 long len;
2792
2793 const long long id = ReadUInt(pReader, pos, len);
2794 assert(id >= 0); // TODO
2795 assert((pos + len) <= stop);
2796
2797 pos += len; // consume ID
2798
2799 const long long size = ReadUInt(pReader, pos, len);
2800 assert(size >= 0);
2801 assert((pos + len) <= stop);
2802
2803 pos += len; // consume Size field
2804 assert((pos + size) <= stop);
2805
2806 if (id == 0x37) { // CueTrackPosition(s) ID
2807 TrackPosition& tp = *p++;
2808 tp.Parse(pReader, pos, size);
2809 }
2810
2811 pos += size; // consume payload
2812 assert(pos <= stop);
2813 }
2814
2815 assert(size_t(p - m_track_positions) == m_track_positions_count);
2816
2817 m_element_start = element_start;
2818 m_element_size = element_size;
2819 }
2820
Parse(IMkvReader * pReader,long long start_,long long size_)2821 void CuePoint::TrackPosition::Parse(IMkvReader* pReader, long long start_,
2822 long long size_) {
2823 const long long stop = start_ + size_;
2824 long long pos = start_;
2825
2826 m_track = -1;
2827 m_pos = -1;
2828 m_block = 1; // default
2829
2830 while (pos < stop) {
2831 long len;
2832
2833 const long long id = ReadUInt(pReader, pos, len);
2834 assert(id >= 0); // TODO
2835 assert((pos + len) <= stop);
2836
2837 pos += len; // consume ID
2838
2839 const long long size = ReadUInt(pReader, pos, len);
2840 assert(size >= 0);
2841 assert((pos + len) <= stop);
2842
2843 pos += len; // consume Size field
2844 assert((pos + size) <= stop);
2845
2846 if (id == 0x77) // CueTrack ID
2847 m_track = UnserializeUInt(pReader, pos, size);
2848
2849 else if (id == 0x71) // CueClusterPos ID
2850 m_pos = UnserializeUInt(pReader, pos, size);
2851
2852 else if (id == 0x1378) // CueBlockNumber
2853 m_block = UnserializeUInt(pReader, pos, size);
2854
2855 pos += size; // consume payload
2856 assert(pos <= stop);
2857 }
2858
2859 assert(m_pos >= 0);
2860 assert(m_track > 0);
2861 // assert(m_block > 0);
2862 }
2863
Find(const Track * pTrack) const2864 const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const {
2865 assert(pTrack);
2866
2867 const long long n = pTrack->GetNumber();
2868
2869 const TrackPosition* i = m_track_positions;
2870 const TrackPosition* const j = i + m_track_positions_count;
2871
2872 while (i != j) {
2873 const TrackPosition& p = *i++;
2874
2875 if (p.m_track == n)
2876 return &p;
2877 }
2878
2879 return NULL; // no matching track number found
2880 }
2881
GetTimeCode() const2882 long long CuePoint::GetTimeCode() const { return m_timecode; }
2883
GetTime(const Segment * pSegment) const2884 long long CuePoint::GetTime(const Segment* pSegment) const {
2885 assert(pSegment);
2886 assert(m_timecode >= 0);
2887
2888 const SegmentInfo* const pInfo = pSegment->GetInfo();
2889 assert(pInfo);
2890
2891 const long long scale = pInfo->GetTimeCodeScale();
2892 assert(scale >= 1);
2893
2894 const long long time = scale * m_timecode;
2895
2896 return time;
2897 }
2898
2899 #if 0
2900 long long Segment::Unparsed() const
2901 {
2902 if (m_size < 0)
2903 return LLONG_MAX;
2904
2905 const long long stop = m_start + m_size;
2906
2907 const long long result = stop - m_pos;
2908 assert(result >= 0);
2909
2910 return result;
2911 }
2912 #else
DoneParsing() const2913 bool Segment::DoneParsing() const {
2914 if (m_size < 0) {
2915 long long total, avail;
2916
2917 const int status = m_pReader->Length(&total, &avail);
2918
2919 if (status < 0) // error
2920 return true; // must assume done
2921
2922 if (total < 0)
2923 return false; // assume live stream
2924
2925 return (m_pos >= total);
2926 }
2927
2928 const long long stop = m_start + m_size;
2929
2930 return (m_pos >= stop);
2931 }
2932 #endif
2933
GetFirst() const2934 const Cluster* Segment::GetFirst() const {
2935 if ((m_clusters == NULL) || (m_clusterCount <= 0))
2936 return &m_eos;
2937
2938 Cluster* const pCluster = m_clusters[0];
2939 assert(pCluster);
2940
2941 return pCluster;
2942 }
2943
GetLast() const2944 const Cluster* Segment::GetLast() const {
2945 if ((m_clusters == NULL) || (m_clusterCount <= 0))
2946 return &m_eos;
2947
2948 const long idx = m_clusterCount - 1;
2949
2950 Cluster* const pCluster = m_clusters[idx];
2951 assert(pCluster);
2952
2953 return pCluster;
2954 }
2955
GetCount() const2956 unsigned long Segment::GetCount() const { return m_clusterCount; }
2957
GetNext(const Cluster * pCurr)2958 const Cluster* Segment::GetNext(const Cluster* pCurr) {
2959 assert(pCurr);
2960 assert(pCurr != &m_eos);
2961 assert(m_clusters);
2962
2963 long idx = pCurr->m_index;
2964
2965 if (idx >= 0) {
2966 assert(m_clusterCount > 0);
2967 assert(idx < m_clusterCount);
2968 assert(pCurr == m_clusters[idx]);
2969
2970 ++idx;
2971
2972 if (idx >= m_clusterCount)
2973 return &m_eos; // caller will LoadCluster as desired
2974
2975 Cluster* const pNext = m_clusters[idx];
2976 assert(pNext);
2977 assert(pNext->m_index >= 0);
2978 assert(pNext->m_index == idx);
2979
2980 return pNext;
2981 }
2982
2983 assert(m_clusterPreloadCount > 0);
2984
2985 long long pos = pCurr->m_element_start;
2986
2987 assert(m_size >= 0); // TODO
2988 const long long stop = m_start + m_size; // end of segment
2989
2990 {
2991 long len;
2992
2993 long long result = GetUIntLength(m_pReader, pos, len);
2994 assert(result == 0);
2995 assert((pos + len) <= stop); // TODO
2996 if (result != 0)
2997 return NULL;
2998
2999 const long long id = ReadUInt(m_pReader, pos, len);
3000 assert(id == 0x0F43B675); // Cluster ID
3001 if (id != 0x0F43B675)
3002 return NULL;
3003
3004 pos += len; // consume ID
3005
3006 // Read Size
3007 result = GetUIntLength(m_pReader, pos, len);
3008 assert(result == 0); // TODO
3009 assert((pos + len) <= stop); // TODO
3010
3011 const long long size = ReadUInt(m_pReader, pos, len);
3012 assert(size > 0); // TODO
3013 // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
3014
3015 pos += len; // consume length of size of element
3016 assert((pos + size) <= stop); // TODO
3017
3018 // Pos now points to start of payload
3019
3020 pos += size; // consume payload
3021 }
3022
3023 long long off_next = 0;
3024
3025 while (pos < stop) {
3026 long len;
3027
3028 long long result = GetUIntLength(m_pReader, pos, len);
3029 assert(result == 0);
3030 assert((pos + len) <= stop); // TODO
3031 if (result != 0)
3032 return NULL;
3033
3034 const long long idpos = pos; // pos of next (potential) cluster
3035
3036 const long long id = ReadUInt(m_pReader, idpos, len);
3037 assert(id > 0); // TODO
3038
3039 pos += len; // consume ID
3040
3041 // Read Size
3042 result = GetUIntLength(m_pReader, pos, len);
3043 assert(result == 0); // TODO
3044 assert((pos + len) <= stop); // TODO
3045
3046 const long long size = ReadUInt(m_pReader, pos, len);
3047 assert(size >= 0); // TODO
3048
3049 pos += len; // consume length of size of element
3050 assert((pos + size) <= stop); // TODO
3051
3052 // Pos now points to start of payload
3053
3054 if (size == 0) // weird
3055 continue;
3056
3057 if (id == 0x0F43B675) { // Cluster ID
3058 const long long off_next_ = idpos - m_start;
3059
3060 long long pos_;
3061 long len_;
3062
3063 const long status = Cluster::HasBlockEntries(this, off_next_, pos_, len_);
3064
3065 assert(status >= 0);
3066
3067 if (status > 0) {
3068 off_next = off_next_;
3069 break;
3070 }
3071 }
3072
3073 pos += size; // consume payload
3074 }
3075
3076 if (off_next <= 0)
3077 return 0;
3078
3079 Cluster** const ii = m_clusters + m_clusterCount;
3080 Cluster** i = ii;
3081
3082 Cluster** const jj = ii + m_clusterPreloadCount;
3083 Cluster** j = jj;
3084
3085 while (i < j) {
3086 // INVARIANT:
3087 //[0, i) < pos_next
3088 //[i, j) ?
3089 //[j, jj) > pos_next
3090
3091 Cluster** const k = i + (j - i) / 2;
3092 assert(k < jj);
3093
3094 Cluster* const pNext = *k;
3095 assert(pNext);
3096 assert(pNext->m_index < 0);
3097
3098 // const long long pos_ = pNext->m_pos;
3099 // assert(pos_);
3100 // pos = pos_ * ((pos_ < 0) ? -1 : 1);
3101
3102 pos = pNext->GetPosition();
3103
3104 if (pos < off_next)
3105 i = k + 1;
3106 else if (pos > off_next)
3107 j = k;
3108 else
3109 return pNext;
3110 }
3111
3112 assert(i == j);
3113
3114 Cluster* const pNext = Cluster::Create(this, -1, off_next);
3115 assert(pNext);
3116
3117 const ptrdiff_t idx_next = i - m_clusters; // insertion position
3118
3119 PreloadCluster(pNext, idx_next);
3120 assert(m_clusters);
3121 assert(idx_next < m_clusterSize);
3122 assert(m_clusters[idx_next] == pNext);
3123
3124 return pNext;
3125 }
3126
ParseNext(const Cluster * pCurr,const Cluster * & pResult,long long & pos,long & len)3127 long Segment::ParseNext(const Cluster* pCurr, const Cluster*& pResult,
3128 long long& pos, long& len) {
3129 assert(pCurr);
3130 assert(!pCurr->EOS());
3131 assert(m_clusters);
3132
3133 pResult = 0;
3134
3135 if (pCurr->m_index >= 0) { // loaded (not merely preloaded)
3136 assert(m_clusters[pCurr->m_index] == pCurr);
3137
3138 const long next_idx = pCurr->m_index + 1;
3139
3140 if (next_idx < m_clusterCount) {
3141 pResult = m_clusters[next_idx];
3142 return 0; // success
3143 }
3144
3145 // curr cluster is last among loaded
3146
3147 const long result = LoadCluster(pos, len);
3148
3149 if (result < 0) // error or underflow
3150 return result;
3151
3152 if (result > 0) // no more clusters
3153 {
3154 // pResult = &m_eos;
3155 return 1;
3156 }
3157
3158 pResult = GetLast();
3159 return 0; // success
3160 }
3161
3162 assert(m_pos > 0);
3163
3164 long long total, avail;
3165
3166 long status = m_pReader->Length(&total, &avail);
3167
3168 if (status < 0) // error
3169 return status;
3170
3171 assert((total < 0) || (avail <= total));
3172
3173 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
3174
3175 // interrogate curr cluster
3176
3177 pos = pCurr->m_element_start;
3178
3179 if (pCurr->m_element_size >= 0)
3180 pos += pCurr->m_element_size;
3181 else {
3182 if ((pos + 1) > avail) {
3183 len = 1;
3184 return E_BUFFER_NOT_FULL;
3185 }
3186
3187 long long result = GetUIntLength(m_pReader, pos, len);
3188
3189 if (result < 0) // error
3190 return static_cast<long>(result);
3191
3192 if (result > 0) // weird
3193 return E_BUFFER_NOT_FULL;
3194
3195 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3196 return E_FILE_FORMAT_INVALID;
3197
3198 if ((pos + len) > avail)
3199 return E_BUFFER_NOT_FULL;
3200
3201 const long long id = ReadUInt(m_pReader, pos, len);
3202
3203 if (id != 0x0F43B675) // weird: not Cluster ID
3204 return -1;
3205
3206 pos += len; // consume ID
3207
3208 // Read Size
3209
3210 if ((pos + 1) > avail) {
3211 len = 1;
3212 return E_BUFFER_NOT_FULL;
3213 }
3214
3215 result = GetUIntLength(m_pReader, pos, len);
3216
3217 if (result < 0) // error
3218 return static_cast<long>(result);
3219
3220 if (result > 0) // weird
3221 return E_BUFFER_NOT_FULL;
3222
3223 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3224 return E_FILE_FORMAT_INVALID;
3225
3226 if ((pos + len) > avail)
3227 return E_BUFFER_NOT_FULL;
3228
3229 const long long size = ReadUInt(m_pReader, pos, len);
3230
3231 if (size < 0) // error
3232 return static_cast<long>(size);
3233
3234 pos += len; // consume size field
3235
3236 const long long unknown_size = (1LL << (7 * len)) - 1;
3237
3238 if (size == unknown_size) // TODO: should never happen
3239 return E_FILE_FORMAT_INVALID; // TODO: resolve this
3240
3241 // assert((pCurr->m_size <= 0) || (pCurr->m_size == size));
3242
3243 if ((segment_stop >= 0) && ((pos + size) > segment_stop))
3244 return E_FILE_FORMAT_INVALID;
3245
3246 // Pos now points to start of payload
3247
3248 pos += size; // consume payload (that is, the current cluster)
3249 assert((segment_stop < 0) || (pos <= segment_stop));
3250
3251 // By consuming the payload, we are assuming that the curr
3252 // cluster isn't interesting. That is, we don't bother checking
3253 // whether the payload of the curr cluster is less than what
3254 // happens to be available (obtained via IMkvReader::Length).
3255 // Presumably the caller has already dispensed with the current
3256 // cluster, and really does want the next cluster.
3257 }
3258
3259 // pos now points to just beyond the last fully-loaded cluster
3260
3261 for (;;) {
3262 const long status = DoParseNext(pResult, pos, len);
3263
3264 if (status <= 1)
3265 return status;
3266 }
3267 }
3268
DoParseNext(const Cluster * & pResult,long long & pos,long & len)3269 long Segment::DoParseNext(const Cluster*& pResult, long long& pos, long& len) {
3270 long long total, avail;
3271
3272 long status = m_pReader->Length(&total, &avail);
3273
3274 if (status < 0) // error
3275 return status;
3276
3277 assert((total < 0) || (avail <= total));
3278
3279 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size;
3280
3281 // Parse next cluster. This is strictly a parsing activity.
3282 // Creation of a new cluster object happens later, after the
3283 // parsing is done.
3284
3285 long long off_next = 0;
3286 long long cluster_size = -1;
3287
3288 for (;;) {
3289 if ((total >= 0) && (pos >= total))
3290 return 1; // EOF
3291
3292 if ((segment_stop >= 0) && (pos >= segment_stop))
3293 return 1; // EOF
3294
3295 if ((pos + 1) > avail) {
3296 len = 1;
3297 return E_BUFFER_NOT_FULL;
3298 }
3299
3300 long long result = GetUIntLength(m_pReader, pos, len);
3301
3302 if (result < 0) // error
3303 return static_cast<long>(result);
3304
3305 if (result > 0) // weird
3306 return E_BUFFER_NOT_FULL;
3307
3308 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3309 return E_FILE_FORMAT_INVALID;
3310
3311 if ((pos + len) > avail)
3312 return E_BUFFER_NOT_FULL;
3313
3314 const long long idpos = pos; // absolute
3315 const long long idoff = pos - m_start; // relative
3316
3317 const long long id = ReadUInt(m_pReader, idpos, len); // absolute
3318
3319 if (id < 0) // error
3320 return static_cast<long>(id);
3321
3322 if (id == 0) // weird
3323 return -1; // generic error
3324
3325 pos += len; // consume ID
3326
3327 // Read Size
3328
3329 if ((pos + 1) > avail) {
3330 len = 1;
3331 return E_BUFFER_NOT_FULL;
3332 }
3333
3334 result = GetUIntLength(m_pReader, pos, len);
3335
3336 if (result < 0) // error
3337 return static_cast<long>(result);
3338
3339 if (result > 0) // weird
3340 return E_BUFFER_NOT_FULL;
3341
3342 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3343 return E_FILE_FORMAT_INVALID;
3344
3345 if ((pos + len) > avail)
3346 return E_BUFFER_NOT_FULL;
3347
3348 const long long size = ReadUInt(m_pReader, pos, len);
3349
3350 if (size < 0) // error
3351 return static_cast<long>(size);
3352
3353 pos += len; // consume length of size of element
3354
3355 // Pos now points to start of payload
3356
3357 if (size == 0) // weird
3358 continue;
3359
3360 const long long unknown_size = (1LL << (7 * len)) - 1;
3361
3362 if ((segment_stop >= 0) && (size != unknown_size) &&
3363 ((pos + size) > segment_stop)) {
3364 return E_FILE_FORMAT_INVALID;
3365 }
3366
3367 if (id == 0x0C53BB6B) { // Cues ID
3368 if (size == unknown_size)
3369 return E_FILE_FORMAT_INVALID;
3370
3371 const long long element_stop = pos + size;
3372
3373 if ((segment_stop >= 0) && (element_stop > segment_stop))
3374 return E_FILE_FORMAT_INVALID;
3375
3376 const long long element_start = idpos;
3377 const long long element_size = element_stop - element_start;
3378
3379 if (m_pCues == NULL) {
3380 m_pCues = new Cues(this, pos, size, element_start, element_size);
3381 assert(m_pCues); // TODO
3382 }
3383
3384 pos += size; // consume payload
3385 assert((segment_stop < 0) || (pos <= segment_stop));
3386
3387 continue;
3388 }
3389
3390 if (id != 0x0F43B675) { // not a Cluster ID
3391 if (size == unknown_size)
3392 return E_FILE_FORMAT_INVALID;
3393
3394 pos += size; // consume payload
3395 assert((segment_stop < 0) || (pos <= segment_stop));
3396
3397 continue;
3398 }
3399
3400 #if 0 // this is commented-out to support incremental cluster parsing
3401 len = static_cast<long>(size);
3402
3403 if (element_stop > avail)
3404 return E_BUFFER_NOT_FULL;
3405 #endif
3406
3407 // We have a cluster.
3408
3409 off_next = idoff;
3410
3411 if (size != unknown_size)
3412 cluster_size = size;
3413
3414 break;
3415 }
3416
3417 assert(off_next > 0); // have cluster
3418
3419 // We have parsed the next cluster.
3420 // We have not created a cluster object yet. What we need
3421 // to do now is determine whether it has already be preloaded
3422 //(in which case, an object for this cluster has already been
3423 // created), and if not, create a new cluster object.
3424
3425 Cluster** const ii = m_clusters + m_clusterCount;
3426 Cluster** i = ii;
3427
3428 Cluster** const jj = ii + m_clusterPreloadCount;
3429 Cluster** j = jj;
3430
3431 while (i < j) {
3432 // INVARIANT:
3433 //[0, i) < pos_next
3434 //[i, j) ?
3435 //[j, jj) > pos_next
3436
3437 Cluster** const k = i + (j - i) / 2;
3438 assert(k < jj);
3439
3440 const Cluster* const pNext = *k;
3441 assert(pNext);
3442 assert(pNext->m_index < 0);
3443
3444 pos = pNext->GetPosition();
3445 assert(pos >= 0);
3446
3447 if (pos < off_next)
3448 i = k + 1;
3449 else if (pos > off_next)
3450 j = k;
3451 else {
3452 pResult = pNext;
3453 return 0; // success
3454 }
3455 }
3456
3457 assert(i == j);
3458
3459 long long pos_;
3460 long len_;
3461
3462 status = Cluster::HasBlockEntries(this, off_next, pos_, len_);
3463
3464 if (status < 0) { // error or underflow
3465 pos = pos_;
3466 len = len_;
3467
3468 return status;
3469 }
3470
3471 if (status > 0) { // means "found at least one block entry"
3472 Cluster* const pNext = Cluster::Create(this,
3473 -1, // preloaded
3474 off_next);
3475 // element_size);
3476 assert(pNext);
3477
3478 const ptrdiff_t idx_next = i - m_clusters; // insertion position
3479
3480 PreloadCluster(pNext, idx_next);
3481 assert(m_clusters);
3482 assert(idx_next < m_clusterSize);
3483 assert(m_clusters[idx_next] == pNext);
3484
3485 pResult = pNext;
3486 return 0; // success
3487 }
3488
3489 // status == 0 means "no block entries found"
3490
3491 if (cluster_size < 0) { // unknown size
3492 const long long payload_pos = pos; // absolute pos of cluster payload
3493
3494 for (;;) { // determine cluster size
3495 if ((total >= 0) && (pos >= total))
3496 break;
3497
3498 if ((segment_stop >= 0) && (pos >= segment_stop))
3499 break; // no more clusters
3500
3501 // Read ID
3502
3503 if ((pos + 1) > avail) {
3504 len = 1;
3505 return E_BUFFER_NOT_FULL;
3506 }
3507
3508 long long result = GetUIntLength(m_pReader, pos, len);
3509
3510 if (result < 0) // error
3511 return static_cast<long>(result);
3512
3513 if (result > 0) // weird
3514 return E_BUFFER_NOT_FULL;
3515
3516 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3517 return E_FILE_FORMAT_INVALID;
3518
3519 if ((pos + len) > avail)
3520 return E_BUFFER_NOT_FULL;
3521
3522 const long long idpos = pos;
3523 const long long id = ReadUInt(m_pReader, idpos, len);
3524
3525 if (id < 0) // error (or underflow)
3526 return static_cast<long>(id);
3527
3528 // This is the distinguished set of ID's we use to determine
3529 // that we have exhausted the sub-element's inside the cluster
3530 // whose ID we parsed earlier.
3531
3532 if (id == 0x0F43B675) // Cluster ID
3533 break;
3534
3535 if (id == 0x0C53BB6B) // Cues ID
3536 break;
3537
3538 pos += len; // consume ID (of sub-element)
3539
3540 // Read Size
3541
3542 if ((pos + 1) > avail) {
3543 len = 1;
3544 return E_BUFFER_NOT_FULL;
3545 }
3546
3547 result = GetUIntLength(m_pReader, pos, len);
3548
3549 if (result < 0) // error
3550 return static_cast<long>(result);
3551
3552 if (result > 0) // weird
3553 return E_BUFFER_NOT_FULL;
3554
3555 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
3556 return E_FILE_FORMAT_INVALID;
3557
3558 if ((pos + len) > avail)
3559 return E_BUFFER_NOT_FULL;
3560
3561 const long long size = ReadUInt(m_pReader, pos, len);
3562
3563 if (size < 0) // error
3564 return static_cast<long>(size);
3565
3566 pos += len; // consume size field of element
3567
3568 // pos now points to start of sub-element's payload
3569
3570 if (size == 0) // weird
3571 continue;
3572
3573 const long long unknown_size = (1LL << (7 * len)) - 1;
3574
3575 if (size == unknown_size)
3576 return E_FILE_FORMAT_INVALID; // not allowed for sub-elements
3577
3578 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) // weird
3579 return E_FILE_FORMAT_INVALID;
3580
3581 pos += size; // consume payload of sub-element
3582 assert((segment_stop < 0) || (pos <= segment_stop));
3583 } // determine cluster size
3584
3585 cluster_size = pos - payload_pos;
3586 assert(cluster_size >= 0); // TODO: handle cluster_size = 0
3587
3588 pos = payload_pos; // reset and re-parse original cluster
3589 }
3590
3591 pos += cluster_size; // consume payload
3592 assert((segment_stop < 0) || (pos <= segment_stop));
3593
3594 return 2; // try to find a cluster that follows next
3595 }
3596
FindCluster(long long time_ns) const3597 const Cluster* Segment::FindCluster(long long time_ns) const {
3598 if ((m_clusters == NULL) || (m_clusterCount <= 0))
3599 return &m_eos;
3600
3601 {
3602 Cluster* const pCluster = m_clusters[0];
3603 assert(pCluster);
3604 assert(pCluster->m_index == 0);
3605
3606 if (time_ns <= pCluster->GetTime())
3607 return pCluster;
3608 }
3609
3610 // Binary search of cluster array
3611
3612 long i = 0;
3613 long j = m_clusterCount;
3614
3615 while (i < j) {
3616 // INVARIANT:
3617 //[0, i) <= time_ns
3618 //[i, j) ?
3619 //[j, m_clusterCount) > time_ns
3620
3621 const long k = i + (j - i) / 2;
3622 assert(k < m_clusterCount);
3623
3624 Cluster* const pCluster = m_clusters[k];
3625 assert(pCluster);
3626 assert(pCluster->m_index == k);
3627
3628 const long long t = pCluster->GetTime();
3629
3630 if (t <= time_ns)
3631 i = k + 1;
3632 else
3633 j = k;
3634
3635 assert(i <= j);
3636 }
3637
3638 assert(i == j);
3639 assert(i > 0);
3640 assert(i <= m_clusterCount);
3641
3642 const long k = i - 1;
3643
3644 Cluster* const pCluster = m_clusters[k];
3645 assert(pCluster);
3646 assert(pCluster->m_index == k);
3647 assert(pCluster->GetTime() <= time_ns);
3648
3649 return pCluster;
3650 }
3651
3652 #if 0
3653 const BlockEntry* Segment::Seek(
3654 long long time_ns,
3655 const Track* pTrack) const
3656 {
3657 assert(pTrack);
3658
3659 if ((m_clusters == NULL) || (m_clusterCount <= 0))
3660 return pTrack->GetEOS();
3661
3662 Cluster** const i = m_clusters;
3663 assert(i);
3664
3665 {
3666 Cluster* const pCluster = *i;
3667 assert(pCluster);
3668 assert(pCluster->m_index == 0); //m_clusterCount > 0
3669 assert(pCluster->m_pSegment == this);
3670
3671 if (time_ns <= pCluster->GetTime())
3672 return pCluster->GetEntry(pTrack);
3673 }
3674
3675 Cluster** const j = i + m_clusterCount;
3676
3677 if (pTrack->GetType() == 2) { //audio
3678 //TODO: we could decide to use cues for this, as we do for video.
3679 //But we only use it for video because looking around for a keyframe
3680 //can get expensive. Audio doesn't require anything special so a
3681 //straight cluster search is good enough (we assume).
3682
3683 Cluster** lo = i;
3684 Cluster** hi = j;
3685
3686 while (lo < hi)
3687 {
3688 //INVARIANT:
3689 //[i, lo) <= time_ns
3690 //[lo, hi) ?
3691 //[hi, j) > time_ns
3692
3693 Cluster** const mid = lo + (hi - lo) / 2;
3694 assert(mid < hi);
3695
3696 Cluster* const pCluster = *mid;
3697 assert(pCluster);
3698 assert(pCluster->m_index == long(mid - m_clusters));
3699 assert(pCluster->m_pSegment == this);
3700
3701 const long long t = pCluster->GetTime();
3702
3703 if (t <= time_ns)
3704 lo = mid + 1;
3705 else
3706 hi = mid;
3707
3708 assert(lo <= hi);
3709 }
3710
3711 assert(lo == hi);
3712 assert(lo > i);
3713 assert(lo <= j);
3714
3715 while (lo > i)
3716 {
3717 Cluster* const pCluster = *--lo;
3718 assert(pCluster);
3719 assert(pCluster->GetTime() <= time_ns);
3720
3721 const BlockEntry* const pBE = pCluster->GetEntry(pTrack);
3722
3723 if ((pBE != 0) && !pBE->EOS())
3724 return pBE;
3725
3726 //landed on empty cluster (no entries)
3727 }
3728
3729 return pTrack->GetEOS(); //weird
3730 }
3731
3732 assert(pTrack->GetType() == 1); //video
3733
3734 Cluster** lo = i;
3735 Cluster** hi = j;
3736
3737 while (lo < hi)
3738 {
3739 //INVARIANT:
3740 //[i, lo) <= time_ns
3741 //[lo, hi) ?
3742 //[hi, j) > time_ns
3743
3744 Cluster** const mid = lo + (hi - lo) / 2;
3745 assert(mid < hi);
3746
3747 Cluster* const pCluster = *mid;
3748 assert(pCluster);
3749
3750 const long long t = pCluster->GetTime();
3751
3752 if (t <= time_ns)
3753 lo = mid + 1;
3754 else
3755 hi = mid;
3756
3757 assert(lo <= hi);
3758 }
3759
3760 assert(lo == hi);
3761 assert(lo > i);
3762 assert(lo <= j);
3763
3764 Cluster* pCluster = *--lo;
3765 assert(pCluster);
3766 assert(pCluster->GetTime() <= time_ns);
3767
3768 {
3769 const BlockEntry* const pBE = pCluster->GetEntry(pTrack, time_ns);
3770
3771 if ((pBE != 0) && !pBE->EOS()) //found a keyframe
3772 return pBE;
3773 }
3774
3775 const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack);
3776
3777 while (lo != i)
3778 {
3779 pCluster = *--lo;
3780 assert(pCluster);
3781 assert(pCluster->GetTime() <= time_ns);
3782
3783 const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo);
3784
3785 if ((pBlockEntry != 0) && !pBlockEntry->EOS())
3786 return pBlockEntry;
3787 }
3788
3789 //weird: we're on the first cluster, but no keyframe found
3790 //should never happen but we must return something anyway
3791
3792 return pTrack->GetEOS();
3793 }
3794 #endif
3795
3796 #if 0
3797 bool Segment::SearchCues(
3798 long long time_ns,
3799 Track* pTrack,
3800 Cluster*& pCluster,
3801 const BlockEntry*& pBlockEntry,
3802 const CuePoint*& pCP,
3803 const CuePoint::TrackPosition*& pTP)
3804 {
3805 if (pTrack->GetType() != 1) //not video
3806 return false; //TODO: for now, just handle video stream
3807
3808 if (m_pCues == NULL)
3809 return false;
3810
3811 if (!m_pCues->Find(time_ns, pTrack, pCP, pTP))
3812 return false; //weird
3813
3814 assert(pCP);
3815 assert(pTP);
3816 assert(pTP->m_track == pTrack->GetNumber());
3817
3818 //We have the cue point and track position we want,
3819 //so we now need to search for the cluster having
3820 //the indicated position.
3821
3822 return GetCluster(pCP, pTP, pCluster, pBlockEntry);
3823 }
3824 #endif
3825
GetTracks() const3826 const Tracks* Segment::GetTracks() const { return m_pTracks; }
3827
GetInfo() const3828 const SegmentInfo* Segment::GetInfo() const { return m_pInfo; }
3829
GetCues() const3830 const Cues* Segment::GetCues() const { return m_pCues; }
3831
GetChapters() const3832 const Chapters* Segment::GetChapters() const { return m_pChapters; }
3833
GetSeekHead() const3834 const SeekHead* Segment::GetSeekHead() const { return m_pSeekHead; }
3835
GetDuration() const3836 long long Segment::GetDuration() const {
3837 assert(m_pInfo);
3838 return m_pInfo->GetDuration();
3839 }
3840
Chapters(Segment * pSegment,long long payload_start,long long payload_size,long long element_start,long long element_size)3841 Chapters::Chapters(Segment* pSegment, long long payload_start,
3842 long long payload_size, long long element_start,
3843 long long element_size)
3844 : m_pSegment(pSegment),
3845 m_start(payload_start),
3846 m_size(payload_size),
3847 m_element_start(element_start),
3848 m_element_size(element_size),
3849 m_editions(NULL),
3850 m_editions_size(0),
3851 m_editions_count(0) {}
3852
~Chapters()3853 Chapters::~Chapters() {
3854 while (m_editions_count > 0) {
3855 Edition& e = m_editions[--m_editions_count];
3856 e.Clear();
3857 }
3858 }
3859
Parse()3860 long Chapters::Parse() {
3861 IMkvReader* const pReader = m_pSegment->m_pReader;
3862
3863 long long pos = m_start; // payload start
3864 const long long stop = pos + m_size; // payload stop
3865
3866 while (pos < stop) {
3867 long long id, size;
3868
3869 long status = ParseElementHeader(pReader, pos, stop, id, size);
3870
3871 if (status < 0) // error
3872 return status;
3873
3874 if (size == 0) // weird
3875 continue;
3876
3877 if (id == 0x05B9) { // EditionEntry ID
3878 status = ParseEdition(pos, size);
3879
3880 if (status < 0) // error
3881 return status;
3882 }
3883
3884 pos += size;
3885 assert(pos <= stop);
3886 }
3887
3888 assert(pos == stop);
3889 return 0;
3890 }
3891
GetEditionCount() const3892 int Chapters::GetEditionCount() const { return m_editions_count; }
3893
GetEdition(int idx) const3894 const Chapters::Edition* Chapters::GetEdition(int idx) const {
3895 if (idx < 0)
3896 return NULL;
3897
3898 if (idx >= m_editions_count)
3899 return NULL;
3900
3901 return m_editions + idx;
3902 }
3903
ExpandEditionsArray()3904 bool Chapters::ExpandEditionsArray() {
3905 if (m_editions_size > m_editions_count)
3906 return true; // nothing else to do
3907
3908 const int size = (m_editions_size == 0) ? 1 : 2 * m_editions_size;
3909
3910 Edition* const editions = new (std::nothrow) Edition[size];
3911
3912 if (editions == NULL)
3913 return false;
3914
3915 for (int idx = 0; idx < m_editions_count; ++idx) {
3916 m_editions[idx].ShallowCopy(editions[idx]);
3917 }
3918
3919 delete[] m_editions;
3920 m_editions = editions;
3921
3922 m_editions_size = size;
3923 return true;
3924 }
3925
ParseEdition(long long pos,long long size)3926 long Chapters::ParseEdition(long long pos, long long size) {
3927 if (!ExpandEditionsArray())
3928 return -1;
3929
3930 Edition& e = m_editions[m_editions_count++];
3931 e.Init();
3932
3933 return e.Parse(m_pSegment->m_pReader, pos, size);
3934 }
3935
Edition()3936 Chapters::Edition::Edition() {}
3937
~Edition()3938 Chapters::Edition::~Edition() {}
3939
GetAtomCount() const3940 int Chapters::Edition::GetAtomCount() const { return m_atoms_count; }
3941
GetAtom(int index) const3942 const Chapters::Atom* Chapters::Edition::GetAtom(int index) const {
3943 if (index < 0)
3944 return NULL;
3945
3946 if (index >= m_atoms_count)
3947 return NULL;
3948
3949 return m_atoms + index;
3950 }
3951
Init()3952 void Chapters::Edition::Init() {
3953 m_atoms = NULL;
3954 m_atoms_size = 0;
3955 m_atoms_count = 0;
3956 }
3957
ShallowCopy(Edition & rhs) const3958 void Chapters::Edition::ShallowCopy(Edition& rhs) const {
3959 rhs.m_atoms = m_atoms;
3960 rhs.m_atoms_size = m_atoms_size;
3961 rhs.m_atoms_count = m_atoms_count;
3962 }
3963
Clear()3964 void Chapters::Edition::Clear() {
3965 while (m_atoms_count > 0) {
3966 Atom& a = m_atoms[--m_atoms_count];
3967 a.Clear();
3968 }
3969
3970 delete[] m_atoms;
3971 m_atoms = NULL;
3972
3973 m_atoms_size = 0;
3974 }
3975
Parse(IMkvReader * pReader,long long pos,long long size)3976 long Chapters::Edition::Parse(IMkvReader* pReader, long long pos,
3977 long long size) {
3978 const long long stop = pos + size;
3979
3980 while (pos < stop) {
3981 long long id, size;
3982
3983 long status = ParseElementHeader(pReader, pos, stop, id, size);
3984
3985 if (status < 0) // error
3986 return status;
3987
3988 if (size == 0) // weird
3989 continue;
3990
3991 if (id == 0x36) { // Atom ID
3992 status = ParseAtom(pReader, pos, size);
3993
3994 if (status < 0) // error
3995 return status;
3996 }
3997
3998 pos += size;
3999 assert(pos <= stop);
4000 }
4001
4002 assert(pos == stop);
4003 return 0;
4004 }
4005
ParseAtom(IMkvReader * pReader,long long pos,long long size)4006 long Chapters::Edition::ParseAtom(IMkvReader* pReader, long long pos,
4007 long long size) {
4008 if (!ExpandAtomsArray())
4009 return -1;
4010
4011 Atom& a = m_atoms[m_atoms_count++];
4012 a.Init();
4013
4014 return a.Parse(pReader, pos, size);
4015 }
4016
ExpandAtomsArray()4017 bool Chapters::Edition::ExpandAtomsArray() {
4018 if (m_atoms_size > m_atoms_count)
4019 return true; // nothing else to do
4020
4021 const int size = (m_atoms_size == 0) ? 1 : 2 * m_atoms_size;
4022
4023 Atom* const atoms = new (std::nothrow) Atom[size];
4024
4025 if (atoms == NULL)
4026 return false;
4027
4028 for (int idx = 0; idx < m_atoms_count; ++idx) {
4029 m_atoms[idx].ShallowCopy(atoms[idx]);
4030 }
4031
4032 delete[] m_atoms;
4033 m_atoms = atoms;
4034
4035 m_atoms_size = size;
4036 return true;
4037 }
4038
Atom()4039 Chapters::Atom::Atom() {}
4040
~Atom()4041 Chapters::Atom::~Atom() {}
4042
GetUID() const4043 unsigned long long Chapters::Atom::GetUID() const { return m_uid; }
4044
GetStringUID() const4045 const char* Chapters::Atom::GetStringUID() const { return m_string_uid; }
4046
GetStartTimecode() const4047 long long Chapters::Atom::GetStartTimecode() const { return m_start_timecode; }
4048
GetStopTimecode() const4049 long long Chapters::Atom::GetStopTimecode() const { return m_stop_timecode; }
4050
GetStartTime(const Chapters * pChapters) const4051 long long Chapters::Atom::GetStartTime(const Chapters* pChapters) const {
4052 return GetTime(pChapters, m_start_timecode);
4053 }
4054
GetStopTime(const Chapters * pChapters) const4055 long long Chapters::Atom::GetStopTime(const Chapters* pChapters) const {
4056 return GetTime(pChapters, m_stop_timecode);
4057 }
4058
GetDisplayCount() const4059 int Chapters::Atom::GetDisplayCount() const { return m_displays_count; }
4060
GetDisplay(int index) const4061 const Chapters::Display* Chapters::Atom::GetDisplay(int index) const {
4062 if (index < 0)
4063 return NULL;
4064
4065 if (index >= m_displays_count)
4066 return NULL;
4067
4068 return m_displays + index;
4069 }
4070
Init()4071 void Chapters::Atom::Init() {
4072 m_string_uid = NULL;
4073 m_uid = 0;
4074 m_start_timecode = -1;
4075 m_stop_timecode = -1;
4076
4077 m_displays = NULL;
4078 m_displays_size = 0;
4079 m_displays_count = 0;
4080 }
4081
ShallowCopy(Atom & rhs) const4082 void Chapters::Atom::ShallowCopy(Atom& rhs) const {
4083 rhs.m_string_uid = m_string_uid;
4084 rhs.m_uid = m_uid;
4085 rhs.m_start_timecode = m_start_timecode;
4086 rhs.m_stop_timecode = m_stop_timecode;
4087
4088 rhs.m_displays = m_displays;
4089 rhs.m_displays_size = m_displays_size;
4090 rhs.m_displays_count = m_displays_count;
4091 }
4092
Clear()4093 void Chapters::Atom::Clear() {
4094 delete[] m_string_uid;
4095 m_string_uid = NULL;
4096
4097 while (m_displays_count > 0) {
4098 Display& d = m_displays[--m_displays_count];
4099 d.Clear();
4100 }
4101
4102 delete[] m_displays;
4103 m_displays = NULL;
4104
4105 m_displays_size = 0;
4106 }
4107
Parse(IMkvReader * pReader,long long pos,long long size)4108 long Chapters::Atom::Parse(IMkvReader* pReader, long long pos, long long size) {
4109 const long long stop = pos + size;
4110
4111 while (pos < stop) {
4112 long long id, size;
4113
4114 long status = ParseElementHeader(pReader, pos, stop, id, size);
4115
4116 if (status < 0) // error
4117 return status;
4118
4119 if (size == 0) // weird
4120 continue;
4121
4122 if (id == 0x00) { // Display ID
4123 status = ParseDisplay(pReader, pos, size);
4124
4125 if (status < 0) // error
4126 return status;
4127 } else if (id == 0x1654) { // StringUID ID
4128 status = UnserializeString(pReader, pos, size, m_string_uid);
4129
4130 if (status < 0) // error
4131 return status;
4132 } else if (id == 0x33C4) { // UID ID
4133 long long val;
4134 status = UnserializeInt(pReader, pos, size, val);
4135
4136 if (status < 0) // error
4137 return status;
4138
4139 m_uid = static_cast<unsigned long long>(val);
4140 } else if (id == 0x11) { // TimeStart ID
4141 const long long val = UnserializeUInt(pReader, pos, size);
4142
4143 if (val < 0) // error
4144 return static_cast<long>(val);
4145
4146 m_start_timecode = val;
4147 } else if (id == 0x12) { // TimeEnd ID
4148 const long long val = UnserializeUInt(pReader, pos, size);
4149
4150 if (val < 0) // error
4151 return static_cast<long>(val);
4152
4153 m_stop_timecode = val;
4154 }
4155
4156 pos += size;
4157 assert(pos <= stop);
4158 }
4159
4160 assert(pos == stop);
4161 return 0;
4162 }
4163
GetTime(const Chapters * pChapters,long long timecode)4164 long long Chapters::Atom::GetTime(const Chapters* pChapters,
4165 long long timecode) {
4166 if (pChapters == NULL)
4167 return -1;
4168
4169 Segment* const pSegment = pChapters->m_pSegment;
4170
4171 if (pSegment == NULL) // weird
4172 return -1;
4173
4174 const SegmentInfo* const pInfo = pSegment->GetInfo();
4175
4176 if (pInfo == NULL)
4177 return -1;
4178
4179 const long long timecode_scale = pInfo->GetTimeCodeScale();
4180
4181 if (timecode_scale < 1) // weird
4182 return -1;
4183
4184 if (timecode < 0)
4185 return -1;
4186
4187 const long long result = timecode_scale * timecode;
4188
4189 return result;
4190 }
4191
ParseDisplay(IMkvReader * pReader,long long pos,long long size)4192 long Chapters::Atom::ParseDisplay(IMkvReader* pReader, long long pos,
4193 long long size) {
4194 if (!ExpandDisplaysArray())
4195 return -1;
4196
4197 Display& d = m_displays[m_displays_count++];
4198 d.Init();
4199
4200 return d.Parse(pReader, pos, size);
4201 }
4202
ExpandDisplaysArray()4203 bool Chapters::Atom::ExpandDisplaysArray() {
4204 if (m_displays_size > m_displays_count)
4205 return true; // nothing else to do
4206
4207 const int size = (m_displays_size == 0) ? 1 : 2 * m_displays_size;
4208
4209 Display* const displays = new (std::nothrow) Display[size];
4210
4211 if (displays == NULL)
4212 return false;
4213
4214 for (int idx = 0; idx < m_displays_count; ++idx) {
4215 m_displays[idx].ShallowCopy(displays[idx]);
4216 }
4217
4218 delete[] m_displays;
4219 m_displays = displays;
4220
4221 m_displays_size = size;
4222 return true;
4223 }
4224
Display()4225 Chapters::Display::Display() {}
4226
~Display()4227 Chapters::Display::~Display() {}
4228
GetString() const4229 const char* Chapters::Display::GetString() const { return m_string; }
4230
GetLanguage() const4231 const char* Chapters::Display::GetLanguage() const { return m_language; }
4232
GetCountry() const4233 const char* Chapters::Display::GetCountry() const { return m_country; }
4234
Init()4235 void Chapters::Display::Init() {
4236 m_string = NULL;
4237 m_language = NULL;
4238 m_country = NULL;
4239 }
4240
ShallowCopy(Display & rhs) const4241 void Chapters::Display::ShallowCopy(Display& rhs) const {
4242 rhs.m_string = m_string;
4243 rhs.m_language = m_language;
4244 rhs.m_country = m_country;
4245 }
4246
Clear()4247 void Chapters::Display::Clear() {
4248 delete[] m_string;
4249 m_string = NULL;
4250
4251 delete[] m_language;
4252 m_language = NULL;
4253
4254 delete[] m_country;
4255 m_country = NULL;
4256 }
4257
Parse(IMkvReader * pReader,long long pos,long long size)4258 long Chapters::Display::Parse(IMkvReader* pReader, long long pos,
4259 long long size) {
4260 const long long stop = pos + size;
4261
4262 while (pos < stop) {
4263 long long id, size;
4264
4265 long status = ParseElementHeader(pReader, pos, stop, id, size);
4266
4267 if (status < 0) // error
4268 return status;
4269
4270 if (size == 0) // weird
4271 continue;
4272
4273 if (id == 0x05) { // ChapterString ID
4274 status = UnserializeString(pReader, pos, size, m_string);
4275
4276 if (status)
4277 return status;
4278 } else if (id == 0x037C) { // ChapterLanguage ID
4279 status = UnserializeString(pReader, pos, size, m_language);
4280
4281 if (status)
4282 return status;
4283 } else if (id == 0x037E) { // ChapterCountry ID
4284 status = UnserializeString(pReader, pos, size, m_country);
4285
4286 if (status)
4287 return status;
4288 }
4289
4290 pos += size;
4291 assert(pos <= stop);
4292 }
4293
4294 assert(pos == stop);
4295 return 0;
4296 }
4297
SegmentInfo(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)4298 SegmentInfo::SegmentInfo(Segment* pSegment, long long start, long long size_,
4299 long long element_start, long long element_size)
4300 : m_pSegment(pSegment),
4301 m_start(start),
4302 m_size(size_),
4303 m_element_start(element_start),
4304 m_element_size(element_size),
4305 m_pMuxingAppAsUTF8(NULL),
4306 m_pWritingAppAsUTF8(NULL),
4307 m_pTitleAsUTF8(NULL) {}
4308
~SegmentInfo()4309 SegmentInfo::~SegmentInfo() {
4310 delete[] m_pMuxingAppAsUTF8;
4311 m_pMuxingAppAsUTF8 = NULL;
4312
4313 delete[] m_pWritingAppAsUTF8;
4314 m_pWritingAppAsUTF8 = NULL;
4315
4316 delete[] m_pTitleAsUTF8;
4317 m_pTitleAsUTF8 = NULL;
4318 }
4319
Parse()4320 long SegmentInfo::Parse() {
4321 assert(m_pMuxingAppAsUTF8 == NULL);
4322 assert(m_pWritingAppAsUTF8 == NULL);
4323 assert(m_pTitleAsUTF8 == NULL);
4324
4325 IMkvReader* const pReader = m_pSegment->m_pReader;
4326
4327 long long pos = m_start;
4328 const long long stop = m_start + m_size;
4329
4330 m_timecodeScale = 1000000;
4331 m_duration = -1;
4332
4333 while (pos < stop) {
4334 long long id, size;
4335
4336 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4337
4338 if (status < 0) // error
4339 return status;
4340
4341 if (id == 0x0AD7B1) { // Timecode Scale
4342 m_timecodeScale = UnserializeUInt(pReader, pos, size);
4343
4344 if (m_timecodeScale <= 0)
4345 return E_FILE_FORMAT_INVALID;
4346 } else if (id == 0x0489) { // Segment duration
4347 const long status = UnserializeFloat(pReader, pos, size, m_duration);
4348
4349 if (status < 0)
4350 return status;
4351
4352 if (m_duration < 0)
4353 return E_FILE_FORMAT_INVALID;
4354 } else if (id == 0x0D80) { // MuxingApp
4355 const long status =
4356 UnserializeString(pReader, pos, size, m_pMuxingAppAsUTF8);
4357
4358 if (status)
4359 return status;
4360 } else if (id == 0x1741) { // WritingApp
4361 const long status =
4362 UnserializeString(pReader, pos, size, m_pWritingAppAsUTF8);
4363
4364 if (status)
4365 return status;
4366 } else if (id == 0x3BA9) { // Title
4367 const long status = UnserializeString(pReader, pos, size, m_pTitleAsUTF8);
4368
4369 if (status)
4370 return status;
4371 }
4372
4373 pos += size;
4374 assert(pos <= stop);
4375 }
4376
4377 assert(pos == stop);
4378
4379 return 0;
4380 }
4381
GetTimeCodeScale() const4382 long long SegmentInfo::GetTimeCodeScale() const { return m_timecodeScale; }
4383
GetDuration() const4384 long long SegmentInfo::GetDuration() const {
4385 if (m_duration < 0)
4386 return -1;
4387
4388 assert(m_timecodeScale >= 1);
4389
4390 const double dd = double(m_duration) * double(m_timecodeScale);
4391 const long long d = static_cast<long long>(dd);
4392
4393 return d;
4394 }
4395
GetMuxingAppAsUTF8() const4396 const char* SegmentInfo::GetMuxingAppAsUTF8() const {
4397 return m_pMuxingAppAsUTF8;
4398 }
4399
GetWritingAppAsUTF8() const4400 const char* SegmentInfo::GetWritingAppAsUTF8() const {
4401 return m_pWritingAppAsUTF8;
4402 }
4403
GetTitleAsUTF8() const4404 const char* SegmentInfo::GetTitleAsUTF8() const { return m_pTitleAsUTF8; }
4405
4406 ///////////////////////////////////////////////////////////////
4407 // ContentEncoding element
ContentCompression()4408 ContentEncoding::ContentCompression::ContentCompression()
4409 : algo(0), settings(NULL), settings_len(0) {}
4410
~ContentCompression()4411 ContentEncoding::ContentCompression::~ContentCompression() {
4412 delete[] settings;
4413 }
4414
ContentEncryption()4415 ContentEncoding::ContentEncryption::ContentEncryption()
4416 : algo(0),
4417 key_id(NULL),
4418 key_id_len(0),
4419 signature(NULL),
4420 signature_len(0),
4421 sig_key_id(NULL),
4422 sig_key_id_len(0),
4423 sig_algo(0),
4424 sig_hash_algo(0) {}
4425
~ContentEncryption()4426 ContentEncoding::ContentEncryption::~ContentEncryption() {
4427 delete[] key_id;
4428 delete[] signature;
4429 delete[] sig_key_id;
4430 }
4431
ContentEncoding()4432 ContentEncoding::ContentEncoding()
4433 : compression_entries_(NULL),
4434 compression_entries_end_(NULL),
4435 encryption_entries_(NULL),
4436 encryption_entries_end_(NULL),
4437 encoding_order_(0),
4438 encoding_scope_(1),
4439 encoding_type_(0) {}
4440
~ContentEncoding()4441 ContentEncoding::~ContentEncoding() {
4442 ContentCompression** comp_i = compression_entries_;
4443 ContentCompression** const comp_j = compression_entries_end_;
4444
4445 while (comp_i != comp_j) {
4446 ContentCompression* const comp = *comp_i++;
4447 delete comp;
4448 }
4449
4450 delete[] compression_entries_;
4451
4452 ContentEncryption** enc_i = encryption_entries_;
4453 ContentEncryption** const enc_j = encryption_entries_end_;
4454
4455 while (enc_i != enc_j) {
4456 ContentEncryption* const enc = *enc_i++;
4457 delete enc;
4458 }
4459
4460 delete[] encryption_entries_;
4461 }
4462
4463 const ContentEncoding::ContentCompression*
GetCompressionByIndex(unsigned long idx) const4464 ContentEncoding::GetCompressionByIndex(unsigned long idx) const {
4465 const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4466 assert(count >= 0);
4467
4468 if (idx >= static_cast<unsigned long>(count))
4469 return NULL;
4470
4471 return compression_entries_[idx];
4472 }
4473
GetCompressionCount() const4474 unsigned long ContentEncoding::GetCompressionCount() const {
4475 const ptrdiff_t count = compression_entries_end_ - compression_entries_;
4476 assert(count >= 0);
4477
4478 return static_cast<unsigned long>(count);
4479 }
4480
GetEncryptionByIndex(unsigned long idx) const4481 const ContentEncoding::ContentEncryption* ContentEncoding::GetEncryptionByIndex(
4482 unsigned long idx) const {
4483 const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4484 assert(count >= 0);
4485
4486 if (idx >= static_cast<unsigned long>(count))
4487 return NULL;
4488
4489 return encryption_entries_[idx];
4490 }
4491
GetEncryptionCount() const4492 unsigned long ContentEncoding::GetEncryptionCount() const {
4493 const ptrdiff_t count = encryption_entries_end_ - encryption_entries_;
4494 assert(count >= 0);
4495
4496 return static_cast<unsigned long>(count);
4497 }
4498
ParseContentEncAESSettingsEntry(long long start,long long size,IMkvReader * pReader,ContentEncAESSettings * aes)4499 long ContentEncoding::ParseContentEncAESSettingsEntry(
4500 long long start, long long size, IMkvReader* pReader,
4501 ContentEncAESSettings* aes) {
4502 assert(pReader);
4503 assert(aes);
4504
4505 long long pos = start;
4506 const long long stop = start + size;
4507
4508 while (pos < stop) {
4509 long long id, size;
4510 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4511 if (status < 0) // error
4512 return status;
4513
4514 if (id == 0x7E8) {
4515 // AESSettingsCipherMode
4516 aes->cipher_mode = UnserializeUInt(pReader, pos, size);
4517 if (aes->cipher_mode != 1)
4518 return E_FILE_FORMAT_INVALID;
4519 }
4520
4521 pos += size; // consume payload
4522 assert(pos <= stop);
4523 }
4524
4525 return 0;
4526 }
4527
ParseContentEncodingEntry(long long start,long long size,IMkvReader * pReader)4528 long ContentEncoding::ParseContentEncodingEntry(long long start, long long size,
4529 IMkvReader* pReader) {
4530 assert(pReader);
4531
4532 long long pos = start;
4533 const long long stop = start + size;
4534
4535 // Count ContentCompression and ContentEncryption elements.
4536 int compression_count = 0;
4537 int encryption_count = 0;
4538
4539 while (pos < stop) {
4540 long long id, size;
4541 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4542 if (status < 0) // error
4543 return status;
4544
4545 if (id == 0x1034) // ContentCompression ID
4546 ++compression_count;
4547
4548 if (id == 0x1035) // ContentEncryption ID
4549 ++encryption_count;
4550
4551 pos += size; // consume payload
4552 assert(pos <= stop);
4553 }
4554
4555 if (compression_count <= 0 && encryption_count <= 0)
4556 return -1;
4557
4558 if (compression_count > 0) {
4559 compression_entries_ =
4560 new (std::nothrow) ContentCompression* [compression_count];
4561 if (!compression_entries_)
4562 return -1;
4563 compression_entries_end_ = compression_entries_;
4564 }
4565
4566 if (encryption_count > 0) {
4567 encryption_entries_ =
4568 new (std::nothrow) ContentEncryption* [encryption_count];
4569 if (!encryption_entries_) {
4570 delete[] compression_entries_;
4571 return -1;
4572 }
4573 encryption_entries_end_ = encryption_entries_;
4574 }
4575
4576 pos = start;
4577 while (pos < stop) {
4578 long long id, size;
4579 long status = ParseElementHeader(pReader, pos, stop, id, size);
4580 if (status < 0) // error
4581 return status;
4582
4583 if (id == 0x1031) {
4584 // ContentEncodingOrder
4585 encoding_order_ = UnserializeUInt(pReader, pos, size);
4586 } else if (id == 0x1032) {
4587 // ContentEncodingScope
4588 encoding_scope_ = UnserializeUInt(pReader, pos, size);
4589 if (encoding_scope_ < 1)
4590 return -1;
4591 } else if (id == 0x1033) {
4592 // ContentEncodingType
4593 encoding_type_ = UnserializeUInt(pReader, pos, size);
4594 } else if (id == 0x1034) {
4595 // ContentCompression ID
4596 ContentCompression* const compression =
4597 new (std::nothrow) ContentCompression();
4598 if (!compression)
4599 return -1;
4600
4601 status = ParseCompressionEntry(pos, size, pReader, compression);
4602 if (status) {
4603 delete compression;
4604 return status;
4605 }
4606 *compression_entries_end_++ = compression;
4607 } else if (id == 0x1035) {
4608 // ContentEncryption ID
4609 ContentEncryption* const encryption =
4610 new (std::nothrow) ContentEncryption();
4611 if (!encryption)
4612 return -1;
4613
4614 status = ParseEncryptionEntry(pos, size, pReader, encryption);
4615 if (status) {
4616 delete encryption;
4617 return status;
4618 }
4619 *encryption_entries_end_++ = encryption;
4620 }
4621
4622 pos += size; // consume payload
4623 assert(pos <= stop);
4624 }
4625
4626 assert(pos == stop);
4627 return 0;
4628 }
4629
ParseCompressionEntry(long long start,long long size,IMkvReader * pReader,ContentCompression * compression)4630 long ContentEncoding::ParseCompressionEntry(long long start, long long size,
4631 IMkvReader* pReader,
4632 ContentCompression* compression) {
4633 assert(pReader);
4634 assert(compression);
4635
4636 long long pos = start;
4637 const long long stop = start + size;
4638
4639 bool valid = false;
4640
4641 while (pos < stop) {
4642 long long id, size;
4643 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4644 if (status < 0) // error
4645 return status;
4646
4647 if (id == 0x254) {
4648 // ContentCompAlgo
4649 long long algo = UnserializeUInt(pReader, pos, size);
4650 if (algo < 0)
4651 return E_FILE_FORMAT_INVALID;
4652 compression->algo = algo;
4653 valid = true;
4654 } else if (id == 0x255) {
4655 // ContentCompSettings
4656 if (size <= 0)
4657 return E_FILE_FORMAT_INVALID;
4658
4659 const size_t buflen = static_cast<size_t>(size);
4660 typedef unsigned char* buf_t;
4661 const buf_t buf = new (std::nothrow) unsigned char[buflen];
4662 if (buf == NULL)
4663 return -1;
4664
4665 const int read_status =
4666 pReader->Read(pos, static_cast<long>(buflen), buf);
4667 if (read_status) {
4668 delete[] buf;
4669 return status;
4670 }
4671
4672 compression->settings = buf;
4673 compression->settings_len = buflen;
4674 }
4675
4676 pos += size; // consume payload
4677 assert(pos <= stop);
4678 }
4679
4680 // ContentCompAlgo is mandatory
4681 if (!valid)
4682 return E_FILE_FORMAT_INVALID;
4683
4684 return 0;
4685 }
4686
ParseEncryptionEntry(long long start,long long size,IMkvReader * pReader,ContentEncryption * encryption)4687 long ContentEncoding::ParseEncryptionEntry(long long start, long long size,
4688 IMkvReader* pReader,
4689 ContentEncryption* encryption) {
4690 assert(pReader);
4691 assert(encryption);
4692
4693 long long pos = start;
4694 const long long stop = start + size;
4695
4696 while (pos < stop) {
4697 long long id, size;
4698 const long status = ParseElementHeader(pReader, pos, stop, id, size);
4699 if (status < 0) // error
4700 return status;
4701
4702 if (id == 0x7E1) {
4703 // ContentEncAlgo
4704 encryption->algo = UnserializeUInt(pReader, pos, size);
4705 if (encryption->algo != 5)
4706 return E_FILE_FORMAT_INVALID;
4707 } else if (id == 0x7E2) {
4708 // ContentEncKeyID
4709 delete[] encryption -> key_id;
4710 encryption->key_id = NULL;
4711 encryption->key_id_len = 0;
4712
4713 if (size <= 0)
4714 return E_FILE_FORMAT_INVALID;
4715
4716 const size_t buflen = static_cast<size_t>(size);
4717 typedef unsigned char* buf_t;
4718 const buf_t buf = new (std::nothrow) unsigned char[buflen];
4719 if (buf == NULL)
4720 return -1;
4721
4722 const int read_status =
4723 pReader->Read(pos, static_cast<long>(buflen), buf);
4724 if (read_status) {
4725 delete[] buf;
4726 return status;
4727 }
4728
4729 encryption->key_id = buf;
4730 encryption->key_id_len = buflen;
4731 } else if (id == 0x7E3) {
4732 // ContentSignature
4733 delete[] encryption -> signature;
4734 encryption->signature = NULL;
4735 encryption->signature_len = 0;
4736
4737 if (size <= 0)
4738 return E_FILE_FORMAT_INVALID;
4739
4740 const size_t buflen = static_cast<size_t>(size);
4741 typedef unsigned char* buf_t;
4742 const buf_t buf = new (std::nothrow) unsigned char[buflen];
4743 if (buf == NULL)
4744 return -1;
4745
4746 const int read_status =
4747 pReader->Read(pos, static_cast<long>(buflen), buf);
4748 if (read_status) {
4749 delete[] buf;
4750 return status;
4751 }
4752
4753 encryption->signature = buf;
4754 encryption->signature_len = buflen;
4755 } else if (id == 0x7E4) {
4756 // ContentSigKeyID
4757 delete[] encryption -> sig_key_id;
4758 encryption->sig_key_id = NULL;
4759 encryption->sig_key_id_len = 0;
4760
4761 if (size <= 0)
4762 return E_FILE_FORMAT_INVALID;
4763
4764 const size_t buflen = static_cast<size_t>(size);
4765 typedef unsigned char* buf_t;
4766 const buf_t buf = new (std::nothrow) unsigned char[buflen];
4767 if (buf == NULL)
4768 return -1;
4769
4770 const int read_status =
4771 pReader->Read(pos, static_cast<long>(buflen), buf);
4772 if (read_status) {
4773 delete[] buf;
4774 return status;
4775 }
4776
4777 encryption->sig_key_id = buf;
4778 encryption->sig_key_id_len = buflen;
4779 } else if (id == 0x7E5) {
4780 // ContentSigAlgo
4781 encryption->sig_algo = UnserializeUInt(pReader, pos, size);
4782 } else if (id == 0x7E6) {
4783 // ContentSigHashAlgo
4784 encryption->sig_hash_algo = UnserializeUInt(pReader, pos, size);
4785 } else if (id == 0x7E7) {
4786 // ContentEncAESSettings
4787 const long status = ParseContentEncAESSettingsEntry(
4788 pos, size, pReader, &encryption->aes_settings);
4789 if (status)
4790 return status;
4791 }
4792
4793 pos += size; // consume payload
4794 assert(pos <= stop);
4795 }
4796
4797 return 0;
4798 }
4799
Track(Segment * pSegment,long long element_start,long long element_size)4800 Track::Track(Segment* pSegment, long long element_start, long long element_size)
4801 : m_pSegment(pSegment),
4802 m_element_start(element_start),
4803 m_element_size(element_size),
4804 content_encoding_entries_(NULL),
4805 content_encoding_entries_end_(NULL) {}
4806
~Track()4807 Track::~Track() {
4808 Info& info = const_cast<Info&>(m_info);
4809 info.Clear();
4810
4811 ContentEncoding** i = content_encoding_entries_;
4812 ContentEncoding** const j = content_encoding_entries_end_;
4813
4814 while (i != j) {
4815 ContentEncoding* const encoding = *i++;
4816 delete encoding;
4817 }
4818
4819 delete[] content_encoding_entries_;
4820 }
4821
Create(Segment * pSegment,const Info & info,long long element_start,long long element_size,Track * & pResult)4822 long Track::Create(Segment* pSegment, const Info& info, long long element_start,
4823 long long element_size, Track*& pResult) {
4824 if (pResult)
4825 return -1;
4826
4827 Track* const pTrack =
4828 new (std::nothrow) Track(pSegment, element_start, element_size);
4829
4830 if (pTrack == NULL)
4831 return -1; // generic error
4832
4833 const int status = info.Copy(pTrack->m_info);
4834
4835 if (status) { // error
4836 delete pTrack;
4837 return status;
4838 }
4839
4840 pResult = pTrack;
4841 return 0; // success
4842 }
4843
Info()4844 Track::Info::Info()
4845 : uid(0),
4846 defaultDuration(0),
4847 codecDelay(0),
4848 seekPreRoll(0),
4849 nameAsUTF8(NULL),
4850 language(NULL),
4851 codecId(NULL),
4852 codecNameAsUTF8(NULL),
4853 codecPrivate(NULL),
4854 codecPrivateSize(0),
4855 lacing(false) {}
4856
~Info()4857 Track::Info::~Info() { Clear(); }
4858
Clear()4859 void Track::Info::Clear() {
4860 delete[] nameAsUTF8;
4861 nameAsUTF8 = NULL;
4862
4863 delete[] language;
4864 language = NULL;
4865
4866 delete[] codecId;
4867 codecId = NULL;
4868
4869 delete[] codecPrivate;
4870 codecPrivate = NULL;
4871 codecPrivateSize = 0;
4872
4873 delete[] codecNameAsUTF8;
4874 codecNameAsUTF8 = NULL;
4875 }
4876
CopyStr(char * Info::* str,Info & dst_) const4877 int Track::Info::CopyStr(char* Info::*str, Info& dst_) const {
4878 if (str == static_cast<char * Info::*>(NULL))
4879 return -1;
4880
4881 char*& dst = dst_.*str;
4882
4883 if (dst) // should be NULL already
4884 return -1;
4885
4886 const char* const src = this->*str;
4887
4888 if (src == NULL)
4889 return 0;
4890
4891 const size_t len = strlen(src);
4892
4893 dst = new (std::nothrow) char[len + 1];
4894
4895 if (dst == NULL)
4896 return -1;
4897
4898 strcpy(dst, src);
4899
4900 return 0;
4901 }
4902
Copy(Info & dst) const4903 int Track::Info::Copy(Info& dst) const {
4904 if (&dst == this)
4905 return 0;
4906
4907 dst.type = type;
4908 dst.number = number;
4909 dst.defaultDuration = defaultDuration;
4910 dst.codecDelay = codecDelay;
4911 dst.seekPreRoll = seekPreRoll;
4912 dst.uid = uid;
4913 dst.lacing = lacing;
4914 dst.settings = settings;
4915
4916 // We now copy the string member variables from src to dst.
4917 // This involves memory allocation so in principle the operation
4918 // can fail (indeed, that's why we have Info::Copy), so we must
4919 // report this to the caller. An error return from this function
4920 // therefore implies that the copy was only partially successful.
4921
4922 if (int status = CopyStr(&Info::nameAsUTF8, dst))
4923 return status;
4924
4925 if (int status = CopyStr(&Info::language, dst))
4926 return status;
4927
4928 if (int status = CopyStr(&Info::codecId, dst))
4929 return status;
4930
4931 if (int status = CopyStr(&Info::codecNameAsUTF8, dst))
4932 return status;
4933
4934 if (codecPrivateSize > 0) {
4935 if (codecPrivate == NULL)
4936 return -1;
4937
4938 if (dst.codecPrivate)
4939 return -1;
4940
4941 if (dst.codecPrivateSize != 0)
4942 return -1;
4943
4944 dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize];
4945
4946 if (dst.codecPrivate == NULL)
4947 return -1;
4948
4949 memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize);
4950 dst.codecPrivateSize = codecPrivateSize;
4951 }
4952
4953 return 0;
4954 }
4955
GetEOS() const4956 const BlockEntry* Track::GetEOS() const { return &m_eos; }
4957
GetType() const4958 long Track::GetType() const { return m_info.type; }
4959
GetNumber() const4960 long Track::GetNumber() const { return m_info.number; }
4961
GetUid() const4962 unsigned long long Track::GetUid() const { return m_info.uid; }
4963
GetNameAsUTF8() const4964 const char* Track::GetNameAsUTF8() const { return m_info.nameAsUTF8; }
4965
GetLanguage() const4966 const char* Track::GetLanguage() const { return m_info.language; }
4967
GetCodecNameAsUTF8() const4968 const char* Track::GetCodecNameAsUTF8() const { return m_info.codecNameAsUTF8; }
4969
GetCodecId() const4970 const char* Track::GetCodecId() const { return m_info.codecId; }
4971
GetCodecPrivate(size_t & size) const4972 const unsigned char* Track::GetCodecPrivate(size_t& size) const {
4973 size = m_info.codecPrivateSize;
4974 return m_info.codecPrivate;
4975 }
4976
GetLacing() const4977 bool Track::GetLacing() const { return m_info.lacing; }
4978
GetDefaultDuration() const4979 unsigned long long Track::GetDefaultDuration() const {
4980 return m_info.defaultDuration;
4981 }
4982
GetCodecDelay() const4983 unsigned long long Track::GetCodecDelay() const { return m_info.codecDelay; }
4984
GetSeekPreRoll() const4985 unsigned long long Track::GetSeekPreRoll() const { return m_info.seekPreRoll; }
4986
GetFirst(const BlockEntry * & pBlockEntry) const4987 long Track::GetFirst(const BlockEntry*& pBlockEntry) const {
4988 const Cluster* pCluster = m_pSegment->GetFirst();
4989
4990 for (int i = 0;;) {
4991 if (pCluster == NULL) {
4992 pBlockEntry = GetEOS();
4993 return 1;
4994 }
4995
4996 if (pCluster->EOS()) {
4997 #if 0
4998 if (m_pSegment->Unparsed() <= 0) { //all clusters have been loaded
4999 pBlockEntry = GetEOS();
5000 return 1;
5001 }
5002 #else
5003 if (m_pSegment->DoneParsing()) {
5004 pBlockEntry = GetEOS();
5005 return 1;
5006 }
5007 #endif
5008
5009 pBlockEntry = 0;
5010 return E_BUFFER_NOT_FULL;
5011 }
5012
5013 long status = pCluster->GetFirst(pBlockEntry);
5014
5015 if (status < 0) // error
5016 return status;
5017
5018 if (pBlockEntry == 0) { // empty cluster
5019 pCluster = m_pSegment->GetNext(pCluster);
5020 continue;
5021 }
5022
5023 for (;;) {
5024 const Block* const pBlock = pBlockEntry->GetBlock();
5025 assert(pBlock);
5026
5027 const long long tn = pBlock->GetTrackNumber();
5028
5029 if ((tn == m_info.number) && VetEntry(pBlockEntry))
5030 return 0;
5031
5032 const BlockEntry* pNextEntry;
5033
5034 status = pCluster->GetNext(pBlockEntry, pNextEntry);
5035
5036 if (status < 0) // error
5037 return status;
5038
5039 if (pNextEntry == 0)
5040 break;
5041
5042 pBlockEntry = pNextEntry;
5043 }
5044
5045 ++i;
5046
5047 if (i >= 100)
5048 break;
5049
5050 pCluster = m_pSegment->GetNext(pCluster);
5051 }
5052
5053 // NOTE: if we get here, it means that we didn't find a block with
5054 // a matching track number. We interpret that as an error (which
5055 // might be too conservative).
5056
5057 pBlockEntry = GetEOS(); // so we can return a non-NULL value
5058 return 1;
5059 }
5060
GetNext(const BlockEntry * pCurrEntry,const BlockEntry * & pNextEntry) const5061 long Track::GetNext(const BlockEntry* pCurrEntry,
5062 const BlockEntry*& pNextEntry) const {
5063 assert(pCurrEntry);
5064 assert(!pCurrEntry->EOS()); //?
5065
5066 const Block* const pCurrBlock = pCurrEntry->GetBlock();
5067 assert(pCurrBlock && pCurrBlock->GetTrackNumber() == m_info.number);
5068 if (!pCurrBlock || pCurrBlock->GetTrackNumber() != m_info.number)
5069 return -1;
5070
5071 const Cluster* pCluster = pCurrEntry->GetCluster();
5072 assert(pCluster);
5073 assert(!pCluster->EOS());
5074
5075 long status = pCluster->GetNext(pCurrEntry, pNextEntry);
5076
5077 if (status < 0) // error
5078 return status;
5079
5080 for (int i = 0;;) {
5081 while (pNextEntry) {
5082 const Block* const pNextBlock = pNextEntry->GetBlock();
5083 assert(pNextBlock);
5084
5085 if (pNextBlock->GetTrackNumber() == m_info.number)
5086 return 0;
5087
5088 pCurrEntry = pNextEntry;
5089
5090 status = pCluster->GetNext(pCurrEntry, pNextEntry);
5091
5092 if (status < 0) // error
5093 return status;
5094 }
5095
5096 pCluster = m_pSegment->GetNext(pCluster);
5097
5098 if (pCluster == NULL) {
5099 pNextEntry = GetEOS();
5100 return 1;
5101 }
5102
5103 if (pCluster->EOS()) {
5104 #if 0
5105 if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded
5106 {
5107 pNextEntry = GetEOS();
5108 return 1;
5109 }
5110 #else
5111 if (m_pSegment->DoneParsing()) {
5112 pNextEntry = GetEOS();
5113 return 1;
5114 }
5115 #endif
5116
5117 // TODO: there is a potential O(n^2) problem here: we tell the
5118 // caller to (pre)load another cluster, which he does, but then he
5119 // calls GetNext again, which repeats the same search. This is
5120 // a pathological case, since the only way it can happen is if
5121 // there exists a long sequence of clusters none of which contain a
5122 // block from this track. One way around this problem is for the
5123 // caller to be smarter when he loads another cluster: don't call
5124 // us back until you have a cluster that contains a block from this
5125 // track. (Of course, that's not cheap either, since our caller
5126 // would have to scan the each cluster as it's loaded, so that
5127 // would just push back the problem.)
5128
5129 pNextEntry = NULL;
5130 return E_BUFFER_NOT_FULL;
5131 }
5132
5133 status = pCluster->GetFirst(pNextEntry);
5134
5135 if (status < 0) // error
5136 return status;
5137
5138 if (pNextEntry == NULL) // empty cluster
5139 continue;
5140
5141 ++i;
5142
5143 if (i >= 100)
5144 break;
5145 }
5146
5147 // NOTE: if we get here, it means that we didn't find a block with
5148 // a matching track number after lots of searching, so we give
5149 // up trying.
5150
5151 pNextEntry = GetEOS(); // so we can return a non-NULL value
5152 return 1;
5153 }
5154
VetEntry(const BlockEntry * pBlockEntry) const5155 bool Track::VetEntry(const BlockEntry* pBlockEntry) const {
5156 assert(pBlockEntry);
5157 const Block* const pBlock = pBlockEntry->GetBlock();
5158 assert(pBlock);
5159 assert(pBlock->GetTrackNumber() == m_info.number);
5160 if (!pBlock || pBlock->GetTrackNumber() != m_info.number)
5161 return false;
5162
5163 // This function is used during a seek to determine whether the
5164 // frame is a valid seek target. This default function simply
5165 // returns true, which means all frames are valid seek targets.
5166 // It gets overridden by the VideoTrack class, because only video
5167 // keyframes can be used as seek target.
5168
5169 return true;
5170 }
5171
Seek(long long time_ns,const BlockEntry * & pResult) const5172 long Track::Seek(long long time_ns, const BlockEntry*& pResult) const {
5173 const long status = GetFirst(pResult);
5174
5175 if (status < 0) // buffer underflow, etc
5176 return status;
5177
5178 assert(pResult);
5179
5180 if (pResult->EOS())
5181 return 0;
5182
5183 const Cluster* pCluster = pResult->GetCluster();
5184 assert(pCluster);
5185 assert(pCluster->GetIndex() >= 0);
5186
5187 if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5188 return 0;
5189
5190 Cluster** const clusters = m_pSegment->m_clusters;
5191 assert(clusters);
5192
5193 const long count = m_pSegment->GetCount(); // loaded only, not preloaded
5194 assert(count > 0);
5195
5196 Cluster** const i = clusters + pCluster->GetIndex();
5197 assert(i);
5198 assert(*i == pCluster);
5199 assert(pCluster->GetTime() <= time_ns);
5200
5201 Cluster** const j = clusters + count;
5202
5203 Cluster** lo = i;
5204 Cluster** hi = j;
5205
5206 while (lo < hi) {
5207 // INVARIANT:
5208 //[i, lo) <= time_ns
5209 //[lo, hi) ?
5210 //[hi, j) > time_ns
5211
5212 Cluster** const mid = lo + (hi - lo) / 2;
5213 assert(mid < hi);
5214
5215 pCluster = *mid;
5216 assert(pCluster);
5217 assert(pCluster->GetIndex() >= 0);
5218 assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5219
5220 const long long t = pCluster->GetTime();
5221
5222 if (t <= time_ns)
5223 lo = mid + 1;
5224 else
5225 hi = mid;
5226
5227 assert(lo <= hi);
5228 }
5229
5230 assert(lo == hi);
5231 assert(lo > i);
5232 assert(lo <= j);
5233
5234 while (lo > i) {
5235 pCluster = *--lo;
5236 assert(pCluster);
5237 assert(pCluster->GetTime() <= time_ns);
5238
5239 pResult = pCluster->GetEntry(this);
5240
5241 if ((pResult != 0) && !pResult->EOS())
5242 return 0;
5243
5244 // landed on empty cluster (no entries)
5245 }
5246
5247 pResult = GetEOS(); // weird
5248 return 0;
5249 }
5250
GetContentEncodingByIndex(unsigned long idx) const5251 const ContentEncoding* Track::GetContentEncodingByIndex(
5252 unsigned long idx) const {
5253 const ptrdiff_t count =
5254 content_encoding_entries_end_ - content_encoding_entries_;
5255 assert(count >= 0);
5256
5257 if (idx >= static_cast<unsigned long>(count))
5258 return NULL;
5259
5260 return content_encoding_entries_[idx];
5261 }
5262
GetContentEncodingCount() const5263 unsigned long Track::GetContentEncodingCount() const {
5264 const ptrdiff_t count =
5265 content_encoding_entries_end_ - content_encoding_entries_;
5266 assert(count >= 0);
5267
5268 return static_cast<unsigned long>(count);
5269 }
5270
ParseContentEncodingsEntry(long long start,long long size)5271 long Track::ParseContentEncodingsEntry(long long start, long long size) {
5272 IMkvReader* const pReader = m_pSegment->m_pReader;
5273 assert(pReader);
5274
5275 long long pos = start;
5276 const long long stop = start + size;
5277
5278 // Count ContentEncoding elements.
5279 int count = 0;
5280 while (pos < stop) {
5281 long long id, size;
5282 const long status = ParseElementHeader(pReader, pos, stop, id, size);
5283 if (status < 0) // error
5284 return status;
5285
5286 // pos now designates start of element
5287 if (id == 0x2240) // ContentEncoding ID
5288 ++count;
5289
5290 pos += size; // consume payload
5291 assert(pos <= stop);
5292 }
5293
5294 if (count <= 0)
5295 return -1;
5296
5297 content_encoding_entries_ = new (std::nothrow) ContentEncoding* [count];
5298 if (!content_encoding_entries_)
5299 return -1;
5300
5301 content_encoding_entries_end_ = content_encoding_entries_;
5302
5303 pos = start;
5304 while (pos < stop) {
5305 long long id, size;
5306 long status = ParseElementHeader(pReader, pos, stop, id, size);
5307 if (status < 0) // error
5308 return status;
5309
5310 // pos now designates start of element
5311 if (id == 0x2240) { // ContentEncoding ID
5312 ContentEncoding* const content_encoding =
5313 new (std::nothrow) ContentEncoding();
5314 if (!content_encoding)
5315 return -1;
5316
5317 status = content_encoding->ParseContentEncodingEntry(pos, size, pReader);
5318 if (status) {
5319 delete content_encoding;
5320 return status;
5321 }
5322
5323 *content_encoding_entries_end_++ = content_encoding;
5324 }
5325
5326 pos += size; // consume payload
5327 assert(pos <= stop);
5328 }
5329
5330 assert(pos == stop);
5331
5332 return 0;
5333 }
5334
EOSBlock()5335 Track::EOSBlock::EOSBlock() : BlockEntry(NULL, LONG_MIN) {}
5336
GetKind() const5337 BlockEntry::Kind Track::EOSBlock::GetKind() const { return kBlockEOS; }
5338
GetBlock() const5339 const Block* Track::EOSBlock::GetBlock() const { return NULL; }
5340
VideoTrack(Segment * pSegment,long long element_start,long long element_size)5341 VideoTrack::VideoTrack(Segment* pSegment, long long element_start,
5342 long long element_size)
5343 : Track(pSegment, element_start, element_size) {}
5344
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,VideoTrack * & pResult)5345 long VideoTrack::Parse(Segment* pSegment, const Info& info,
5346 long long element_start, long long element_size,
5347 VideoTrack*& pResult) {
5348 if (pResult)
5349 return -1;
5350
5351 if (info.type != Track::kVideo)
5352 return -1;
5353
5354 long long width = 0;
5355 long long height = 0;
5356 double rate = 0.0;
5357
5358 IMkvReader* const pReader = pSegment->m_pReader;
5359
5360 const Settings& s = info.settings;
5361 assert(s.start >= 0);
5362 assert(s.size >= 0);
5363
5364 long long pos = s.start;
5365 assert(pos >= 0);
5366
5367 const long long stop = pos + s.size;
5368
5369 while (pos < stop) {
5370 long long id, size;
5371
5372 const long status = ParseElementHeader(pReader, pos, stop, id, size);
5373
5374 if (status < 0) // error
5375 return status;
5376
5377 if (id == 0x30) { // pixel width
5378 width = UnserializeUInt(pReader, pos, size);
5379
5380 if (width <= 0)
5381 return E_FILE_FORMAT_INVALID;
5382 } else if (id == 0x3A) { // pixel height
5383 height = UnserializeUInt(pReader, pos, size);
5384
5385 if (height <= 0)
5386 return E_FILE_FORMAT_INVALID;
5387 } else if (id == 0x0383E3) { // frame rate
5388 const long status = UnserializeFloat(pReader, pos, size, rate);
5389
5390 if (status < 0)
5391 return status;
5392
5393 if (rate <= 0)
5394 return E_FILE_FORMAT_INVALID;
5395 }
5396
5397 pos += size; // consume payload
5398 assert(pos <= stop);
5399 }
5400
5401 assert(pos == stop);
5402
5403 VideoTrack* const pTrack =
5404 new (std::nothrow) VideoTrack(pSegment, element_start, element_size);
5405
5406 if (pTrack == NULL)
5407 return -1; // generic error
5408
5409 const int status = info.Copy(pTrack->m_info);
5410
5411 if (status) { // error
5412 delete pTrack;
5413 return status;
5414 }
5415
5416 pTrack->m_width = width;
5417 pTrack->m_height = height;
5418 pTrack->m_rate = rate;
5419
5420 pResult = pTrack;
5421 return 0; // success
5422 }
5423
VetEntry(const BlockEntry * pBlockEntry) const5424 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const {
5425 return Track::VetEntry(pBlockEntry) && pBlockEntry->GetBlock()->IsKey();
5426 }
5427
Seek(long long time_ns,const BlockEntry * & pResult) const5428 long VideoTrack::Seek(long long time_ns, const BlockEntry*& pResult) const {
5429 const long status = GetFirst(pResult);
5430
5431 if (status < 0) // buffer underflow, etc
5432 return status;
5433
5434 assert(pResult);
5435
5436 if (pResult->EOS())
5437 return 0;
5438
5439 const Cluster* pCluster = pResult->GetCluster();
5440 assert(pCluster);
5441 assert(pCluster->GetIndex() >= 0);
5442
5443 if (time_ns <= pResult->GetBlock()->GetTime(pCluster))
5444 return 0;
5445
5446 Cluster** const clusters = m_pSegment->m_clusters;
5447 assert(clusters);
5448
5449 const long count = m_pSegment->GetCount(); // loaded only, not pre-loaded
5450 assert(count > 0);
5451
5452 Cluster** const i = clusters + pCluster->GetIndex();
5453 assert(i);
5454 assert(*i == pCluster);
5455 assert(pCluster->GetTime() <= time_ns);
5456
5457 Cluster** const j = clusters + count;
5458
5459 Cluster** lo = i;
5460 Cluster** hi = j;
5461
5462 while (lo < hi) {
5463 // INVARIANT:
5464 //[i, lo) <= time_ns
5465 //[lo, hi) ?
5466 //[hi, j) > time_ns
5467
5468 Cluster** const mid = lo + (hi - lo) / 2;
5469 assert(mid < hi);
5470
5471 pCluster = *mid;
5472 assert(pCluster);
5473 assert(pCluster->GetIndex() >= 0);
5474 assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters));
5475
5476 const long long t = pCluster->GetTime();
5477
5478 if (t <= time_ns)
5479 lo = mid + 1;
5480 else
5481 hi = mid;
5482
5483 assert(lo <= hi);
5484 }
5485
5486 assert(lo == hi);
5487 assert(lo > i);
5488 assert(lo <= j);
5489
5490 pCluster = *--lo;
5491 assert(pCluster);
5492 assert(pCluster->GetTime() <= time_ns);
5493
5494 pResult = pCluster->GetEntry(this, time_ns);
5495
5496 if ((pResult != 0) && !pResult->EOS()) // found a keyframe
5497 return 0;
5498
5499 while (lo != i) {
5500 pCluster = *--lo;
5501 assert(pCluster);
5502 assert(pCluster->GetTime() <= time_ns);
5503
5504 #if 0
5505 //TODO:
5506 //We need to handle the case when a cluster
5507 //contains multiple keyframes. Simply returning
5508 //the largest keyframe on the cluster isn't
5509 //good enough.
5510 pResult = pCluster->GetMaxKey(this);
5511 #else
5512 pResult = pCluster->GetEntry(this, time_ns);
5513 #endif
5514
5515 if ((pResult != 0) && !pResult->EOS())
5516 return 0;
5517 }
5518
5519 // weird: we're on the first cluster, but no keyframe found
5520 // should never happen but we must return something anyway
5521
5522 pResult = GetEOS();
5523 return 0;
5524 }
5525
GetWidth() const5526 long long VideoTrack::GetWidth() const { return m_width; }
5527
GetHeight() const5528 long long VideoTrack::GetHeight() const { return m_height; }
5529
GetFrameRate() const5530 double VideoTrack::GetFrameRate() const { return m_rate; }
5531
AudioTrack(Segment * pSegment,long long element_start,long long element_size)5532 AudioTrack::AudioTrack(Segment* pSegment, long long element_start,
5533 long long element_size)
5534 : Track(pSegment, element_start, element_size) {}
5535
Parse(Segment * pSegment,const Info & info,long long element_start,long long element_size,AudioTrack * & pResult)5536 long AudioTrack::Parse(Segment* pSegment, const Info& info,
5537 long long element_start, long long element_size,
5538 AudioTrack*& pResult) {
5539 if (pResult)
5540 return -1;
5541
5542 if (info.type != Track::kAudio)
5543 return -1;
5544
5545 IMkvReader* const pReader = pSegment->m_pReader;
5546
5547 const Settings& s = info.settings;
5548 assert(s.start >= 0);
5549 assert(s.size >= 0);
5550
5551 long long pos = s.start;
5552 assert(pos >= 0);
5553
5554 const long long stop = pos + s.size;
5555
5556 double rate = 8000.0; // MKV default
5557 long long channels = 1;
5558 long long bit_depth = 0;
5559
5560 while (pos < stop) {
5561 long long id, size;
5562
5563 long status = ParseElementHeader(pReader, pos, stop, id, size);
5564
5565 if (status < 0) // error
5566 return status;
5567
5568 if (id == 0x35) { // Sample Rate
5569 status = UnserializeFloat(pReader, pos, size, rate);
5570
5571 if (status < 0)
5572 return status;
5573
5574 if (rate <= 0)
5575 return E_FILE_FORMAT_INVALID;
5576 } else if (id == 0x1F) { // Channel Count
5577 channels = UnserializeUInt(pReader, pos, size);
5578
5579 if (channels <= 0)
5580 return E_FILE_FORMAT_INVALID;
5581 } else if (id == 0x2264) { // Bit Depth
5582 bit_depth = UnserializeUInt(pReader, pos, size);
5583
5584 if (bit_depth <= 0)
5585 return E_FILE_FORMAT_INVALID;
5586 }
5587
5588 pos += size; // consume payload
5589 assert(pos <= stop);
5590 }
5591
5592 assert(pos == stop);
5593
5594 AudioTrack* const pTrack =
5595 new (std::nothrow) AudioTrack(pSegment, element_start, element_size);
5596
5597 if (pTrack == NULL)
5598 return -1; // generic error
5599
5600 const int status = info.Copy(pTrack->m_info);
5601
5602 if (status) {
5603 delete pTrack;
5604 return status;
5605 }
5606
5607 pTrack->m_rate = rate;
5608 pTrack->m_channels = channels;
5609 pTrack->m_bitDepth = bit_depth;
5610
5611 pResult = pTrack;
5612 return 0; // success
5613 }
5614
GetSamplingRate() const5615 double AudioTrack::GetSamplingRate() const { return m_rate; }
5616
GetChannels() const5617 long long AudioTrack::GetChannels() const { return m_channels; }
5618
GetBitDepth() const5619 long long AudioTrack::GetBitDepth() const { return m_bitDepth; }
5620
Tracks(Segment * pSegment,long long start,long long size_,long long element_start,long long element_size)5621 Tracks::Tracks(Segment* pSegment, long long start, long long size_,
5622 long long element_start, long long element_size)
5623 : m_pSegment(pSegment),
5624 m_start(start),
5625 m_size(size_),
5626 m_element_start(element_start),
5627 m_element_size(element_size),
5628 m_trackEntries(NULL),
5629 m_trackEntriesEnd(NULL) {}
5630
Parse()5631 long Tracks::Parse() {
5632 assert(m_trackEntries == NULL);
5633 assert(m_trackEntriesEnd == NULL);
5634
5635 const long long stop = m_start + m_size;
5636 IMkvReader* const pReader = m_pSegment->m_pReader;
5637
5638 int count = 0;
5639 long long pos = m_start;
5640
5641 while (pos < stop) {
5642 long long id, size;
5643
5644 const long status = ParseElementHeader(pReader, pos, stop, id, size);
5645
5646 if (status < 0) // error
5647 return status;
5648
5649 if (size == 0) // weird
5650 continue;
5651
5652 if (id == 0x2E) // TrackEntry ID
5653 ++count;
5654
5655 pos += size; // consume payload
5656 assert(pos <= stop);
5657 }
5658
5659 assert(pos == stop);
5660
5661 if (count <= 0)
5662 return 0; // success
5663
5664 m_trackEntries = new (std::nothrow) Track* [count];
5665
5666 if (m_trackEntries == NULL)
5667 return -1;
5668
5669 m_trackEntriesEnd = m_trackEntries;
5670
5671 pos = m_start;
5672
5673 while (pos < stop) {
5674 const long long element_start = pos;
5675
5676 long long id, payload_size;
5677
5678 const long status =
5679 ParseElementHeader(pReader, pos, stop, id, payload_size);
5680
5681 if (status < 0) // error
5682 return status;
5683
5684 if (payload_size == 0) // weird
5685 continue;
5686
5687 const long long payload_stop = pos + payload_size;
5688 assert(payload_stop <= stop); // checked in ParseElement
5689
5690 const long long element_size = payload_stop - element_start;
5691
5692 if (id == 0x2E) { // TrackEntry ID
5693 Track*& pTrack = *m_trackEntriesEnd;
5694 pTrack = NULL;
5695
5696 const long status = ParseTrackEntry(pos, payload_size, element_start,
5697 element_size, pTrack);
5698
5699 if (status)
5700 return status;
5701
5702 if (pTrack)
5703 ++m_trackEntriesEnd;
5704 }
5705
5706 pos = payload_stop;
5707 assert(pos <= stop);
5708 }
5709
5710 assert(pos == stop);
5711
5712 return 0; // success
5713 }
5714
GetTracksCount() const5715 unsigned long Tracks::GetTracksCount() const {
5716 const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries;
5717 assert(result >= 0);
5718
5719 return static_cast<unsigned long>(result);
5720 }
5721
ParseTrackEntry(long long track_start,long long track_size,long long element_start,long long element_size,Track * & pResult) const5722 long Tracks::ParseTrackEntry(long long track_start, long long track_size,
5723 long long element_start, long long element_size,
5724 Track*& pResult) const {
5725 if (pResult)
5726 return -1;
5727
5728 IMkvReader* const pReader = m_pSegment->m_pReader;
5729
5730 long long pos = track_start;
5731 const long long track_stop = track_start + track_size;
5732
5733 Track::Info info;
5734
5735 info.type = 0;
5736 info.number = 0;
5737 info.uid = 0;
5738 info.defaultDuration = 0;
5739
5740 Track::Settings v;
5741 v.start = -1;
5742 v.size = -1;
5743
5744 Track::Settings a;
5745 a.start = -1;
5746 a.size = -1;
5747
5748 Track::Settings e; // content_encodings_settings;
5749 e.start = -1;
5750 e.size = -1;
5751
5752 long long lacing = 1; // default is true
5753
5754 while (pos < track_stop) {
5755 long long id, size;
5756
5757 const long status = ParseElementHeader(pReader, pos, track_stop, id, size);
5758
5759 if (status < 0) // error
5760 return status;
5761
5762 if (size < 0)
5763 return E_FILE_FORMAT_INVALID;
5764
5765 const long long start = pos;
5766
5767 if (id == 0x60) { // VideoSettings ID
5768 v.start = start;
5769 v.size = size;
5770 } else if (id == 0x61) { // AudioSettings ID
5771 a.start = start;
5772 a.size = size;
5773 } else if (id == 0x2D80) { // ContentEncodings ID
5774 e.start = start;
5775 e.size = size;
5776 } else if (id == 0x33C5) { // Track UID
5777 if (size > 8)
5778 return E_FILE_FORMAT_INVALID;
5779
5780 info.uid = 0;
5781
5782 long long pos_ = start;
5783 const long long pos_end = start + size;
5784
5785 while (pos_ != pos_end) {
5786 unsigned char b;
5787
5788 const int status = pReader->Read(pos_, 1, &b);
5789
5790 if (status)
5791 return status;
5792
5793 info.uid <<= 8;
5794 info.uid |= b;
5795
5796 ++pos_;
5797 }
5798 } else if (id == 0x57) { // Track Number
5799 const long long num = UnserializeUInt(pReader, pos, size);
5800
5801 if ((num <= 0) || (num > 127))
5802 return E_FILE_FORMAT_INVALID;
5803
5804 info.number = static_cast<long>(num);
5805 } else if (id == 0x03) { // Track Type
5806 const long long type = UnserializeUInt(pReader, pos, size);
5807
5808 if ((type <= 0) || (type > 254))
5809 return E_FILE_FORMAT_INVALID;
5810
5811 info.type = static_cast<long>(type);
5812 } else if (id == 0x136E) { // Track Name
5813 const long status =
5814 UnserializeString(pReader, pos, size, info.nameAsUTF8);
5815
5816 if (status)
5817 return status;
5818 } else if (id == 0x02B59C) { // Track Language
5819 const long status = UnserializeString(pReader, pos, size, info.language);
5820
5821 if (status)
5822 return status;
5823 } else if (id == 0x03E383) { // Default Duration
5824 const long long duration = UnserializeUInt(pReader, pos, size);
5825
5826 if (duration < 0)
5827 return E_FILE_FORMAT_INVALID;
5828
5829 info.defaultDuration = static_cast<unsigned long long>(duration);
5830 } else if (id == 0x06) { // CodecID
5831 const long status = UnserializeString(pReader, pos, size, info.codecId);
5832
5833 if (status)
5834 return status;
5835 } else if (id == 0x1C) { // lacing
5836 lacing = UnserializeUInt(pReader, pos, size);
5837
5838 if ((lacing < 0) || (lacing > 1))
5839 return E_FILE_FORMAT_INVALID;
5840 } else if (id == 0x23A2) { // Codec Private
5841 delete[] info.codecPrivate;
5842 info.codecPrivate = NULL;
5843 info.codecPrivateSize = 0;
5844
5845 const size_t buflen = static_cast<size_t>(size);
5846
5847 if (buflen) {
5848 typedef unsigned char* buf_t;
5849
5850 const buf_t buf = new (std::nothrow) unsigned char[buflen];
5851
5852 if (buf == NULL)
5853 return -1;
5854
5855 const int status = pReader->Read(pos, static_cast<long>(buflen), buf);
5856
5857 if (status) {
5858 delete[] buf;
5859 return status;
5860 }
5861
5862 info.codecPrivate = buf;
5863 info.codecPrivateSize = buflen;
5864 }
5865 } else if (id == 0x058688) { // Codec Name
5866 const long status =
5867 UnserializeString(pReader, pos, size, info.codecNameAsUTF8);
5868
5869 if (status)
5870 return status;
5871 } else if (id == 0x16AA) { // Codec Delay
5872 info.codecDelay = UnserializeUInt(pReader, pos, size);
5873 } else if (id == 0x16BB) { // Seek Pre Roll
5874 info.seekPreRoll = UnserializeUInt(pReader, pos, size);
5875 }
5876
5877 pos += size; // consume payload
5878 assert(pos <= track_stop);
5879 }
5880
5881 assert(pos == track_stop);
5882
5883 if (info.number <= 0) // not specified
5884 return E_FILE_FORMAT_INVALID;
5885
5886 if (GetTrackByNumber(info.number))
5887 return E_FILE_FORMAT_INVALID;
5888
5889 if (info.type <= 0) // not specified
5890 return E_FILE_FORMAT_INVALID;
5891
5892 info.lacing = (lacing > 0) ? true : false;
5893
5894 if (info.type == Track::kVideo) {
5895 if (v.start < 0)
5896 return E_FILE_FORMAT_INVALID;
5897
5898 if (a.start >= 0)
5899 return E_FILE_FORMAT_INVALID;
5900
5901 info.settings = v;
5902
5903 VideoTrack* pTrack = NULL;
5904
5905 const long status = VideoTrack::Parse(m_pSegment, info, element_start,
5906 element_size, pTrack);
5907
5908 if (status)
5909 return status;
5910
5911 pResult = pTrack;
5912 assert(pResult);
5913
5914 if (e.start >= 0)
5915 pResult->ParseContentEncodingsEntry(e.start, e.size);
5916 } else if (info.type == Track::kAudio) {
5917 if (a.start < 0)
5918 return E_FILE_FORMAT_INVALID;
5919
5920 if (v.start >= 0)
5921 return E_FILE_FORMAT_INVALID;
5922
5923 info.settings = a;
5924
5925 AudioTrack* pTrack = NULL;
5926
5927 const long status = AudioTrack::Parse(m_pSegment, info, element_start,
5928 element_size, pTrack);
5929
5930 if (status)
5931 return status;
5932
5933 pResult = pTrack;
5934 assert(pResult);
5935
5936 if (e.start >= 0)
5937 pResult->ParseContentEncodingsEntry(e.start, e.size);
5938 } else {
5939 // neither video nor audio - probably metadata or subtitles
5940
5941 if (a.start >= 0)
5942 return E_FILE_FORMAT_INVALID;
5943
5944 if (v.start >= 0)
5945 return E_FILE_FORMAT_INVALID;
5946
5947 if (info.type == Track::kMetadata && e.start >= 0)
5948 return E_FILE_FORMAT_INVALID;
5949
5950 info.settings.start = -1;
5951 info.settings.size = 0;
5952
5953 Track* pTrack = NULL;
5954
5955 const long status =
5956 Track::Create(m_pSegment, info, element_start, element_size, pTrack);
5957
5958 if (status)
5959 return status;
5960
5961 pResult = pTrack;
5962 assert(pResult);
5963 }
5964
5965 return 0; // success
5966 }
5967
~Tracks()5968 Tracks::~Tracks() {
5969 Track** i = m_trackEntries;
5970 Track** const j = m_trackEntriesEnd;
5971
5972 while (i != j) {
5973 Track* const pTrack = *i++;
5974 delete pTrack;
5975 }
5976
5977 delete[] m_trackEntries;
5978 }
5979
GetTrackByNumber(long tn) const5980 const Track* Tracks::GetTrackByNumber(long tn) const {
5981 if (tn < 0)
5982 return NULL;
5983
5984 Track** i = m_trackEntries;
5985 Track** const j = m_trackEntriesEnd;
5986
5987 while (i != j) {
5988 Track* const pTrack = *i++;
5989
5990 if (pTrack == NULL)
5991 continue;
5992
5993 if (tn == pTrack->GetNumber())
5994 return pTrack;
5995 }
5996
5997 return NULL; // not found
5998 }
5999
GetTrackByIndex(unsigned long idx) const6000 const Track* Tracks::GetTrackByIndex(unsigned long idx) const {
6001 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries;
6002
6003 if (idx >= static_cast<unsigned long>(count))
6004 return NULL;
6005
6006 return m_trackEntries[idx];
6007 }
6008
6009 #if 0
6010 long long Cluster::Unparsed() const
6011 {
6012 if (m_timecode < 0) //not even partially loaded
6013 return LLONG_MAX;
6014
6015 assert(m_pos >= m_element_start);
6016 //assert(m_element_size > m_size);
6017
6018 const long long element_stop = m_element_start + m_element_size;
6019 assert(m_pos <= element_stop);
6020
6021 const long long result = element_stop - m_pos;
6022 assert(result >= 0);
6023
6024 return result;
6025 }
6026 #endif
6027
Load(long long & pos,long & len) const6028 long Cluster::Load(long long& pos, long& len) const {
6029 assert(m_pSegment);
6030 assert(m_pos >= m_element_start);
6031
6032 if (m_timecode >= 0) // at least partially loaded
6033 return 0;
6034
6035 assert(m_pos == m_element_start);
6036 assert(m_element_size < 0);
6037
6038 IMkvReader* const pReader = m_pSegment->m_pReader;
6039
6040 long long total, avail;
6041
6042 const int status = pReader->Length(&total, &avail);
6043
6044 if (status < 0) // error
6045 return status;
6046
6047 assert((total < 0) || (avail <= total));
6048 assert((total < 0) || (m_pos <= total)); // TODO: verify this
6049
6050 pos = m_pos;
6051
6052 long long cluster_size = -1;
6053
6054 {
6055 if ((pos + 1) > avail) {
6056 len = 1;
6057 return E_BUFFER_NOT_FULL;
6058 }
6059
6060 long long result = GetUIntLength(pReader, pos, len);
6061
6062 if (result < 0) // error or underflow
6063 return static_cast<long>(result);
6064
6065 if (result > 0) // underflow (weird)
6066 return E_BUFFER_NOT_FULL;
6067
6068 // if ((pos + len) > segment_stop)
6069 // return E_FILE_FORMAT_INVALID;
6070
6071 if ((pos + len) > avail)
6072 return E_BUFFER_NOT_FULL;
6073
6074 const long long id_ = ReadUInt(pReader, pos, len);
6075
6076 if (id_ < 0) // error
6077 return static_cast<long>(id_);
6078
6079 if (id_ != 0x0F43B675) // Cluster ID
6080 return E_FILE_FORMAT_INVALID;
6081
6082 pos += len; // consume id
6083
6084 // read cluster size
6085
6086 if ((pos + 1) > avail) {
6087 len = 1;
6088 return E_BUFFER_NOT_FULL;
6089 }
6090
6091 result = GetUIntLength(pReader, pos, len);
6092
6093 if (result < 0) // error
6094 return static_cast<long>(result);
6095
6096 if (result > 0) // weird
6097 return E_BUFFER_NOT_FULL;
6098
6099 // if ((pos + len) > segment_stop)
6100 // return E_FILE_FORMAT_INVALID;
6101
6102 if ((pos + len) > avail)
6103 return E_BUFFER_NOT_FULL;
6104
6105 const long long size = ReadUInt(pReader, pos, len);
6106
6107 if (size < 0) // error
6108 return static_cast<long>(cluster_size);
6109
6110 if (size == 0)
6111 return E_FILE_FORMAT_INVALID; // TODO: verify this
6112
6113 pos += len; // consume length of size of element
6114
6115 const long long unknown_size = (1LL << (7 * len)) - 1;
6116
6117 if (size != unknown_size)
6118 cluster_size = size;
6119 }
6120
6121 // pos points to start of payload
6122
6123 #if 0
6124 len = static_cast<long>(size_);
6125
6126 if (cluster_stop > avail)
6127 return E_BUFFER_NOT_FULL;
6128 #endif
6129
6130 long long timecode = -1;
6131 long long new_pos = -1;
6132 bool bBlock = false;
6133
6134 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size;
6135
6136 for (;;) {
6137 if ((cluster_stop >= 0) && (pos >= cluster_stop))
6138 break;
6139
6140 // Parse ID
6141
6142 if ((pos + 1) > avail) {
6143 len = 1;
6144 return E_BUFFER_NOT_FULL;
6145 }
6146
6147 long long result = GetUIntLength(pReader, pos, len);
6148
6149 if (result < 0) // error
6150 return static_cast<long>(result);
6151
6152 if (result > 0) // weird
6153 return E_BUFFER_NOT_FULL;
6154
6155 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6156 return E_FILE_FORMAT_INVALID;
6157
6158 if ((pos + len) > avail)
6159 return E_BUFFER_NOT_FULL;
6160
6161 const long long id = ReadUInt(pReader, pos, len);
6162
6163 if (id < 0) // error
6164 return static_cast<long>(id);
6165
6166 if (id == 0)
6167 return E_FILE_FORMAT_INVALID;
6168
6169 // This is the distinguished set of ID's we use to determine
6170 // that we have exhausted the sub-element's inside the cluster
6171 // whose ID we parsed earlier.
6172
6173 if (id == 0x0F43B675) // Cluster ID
6174 break;
6175
6176 if (id == 0x0C53BB6B) // Cues ID
6177 break;
6178
6179 pos += len; // consume ID field
6180
6181 // Parse Size
6182
6183 if ((pos + 1) > avail) {
6184 len = 1;
6185 return E_BUFFER_NOT_FULL;
6186 }
6187
6188 result = GetUIntLength(pReader, pos, len);
6189
6190 if (result < 0) // error
6191 return static_cast<long>(result);
6192
6193 if (result > 0) // weird
6194 return E_BUFFER_NOT_FULL;
6195
6196 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6197 return E_FILE_FORMAT_INVALID;
6198
6199 if ((pos + len) > avail)
6200 return E_BUFFER_NOT_FULL;
6201
6202 const long long size = ReadUInt(pReader, pos, len);
6203
6204 if (size < 0) // error
6205 return static_cast<long>(size);
6206
6207 const long long unknown_size = (1LL << (7 * len)) - 1;
6208
6209 if (size == unknown_size)
6210 return E_FILE_FORMAT_INVALID;
6211
6212 pos += len; // consume size field
6213
6214 if ((cluster_stop >= 0) && (pos > cluster_stop))
6215 return E_FILE_FORMAT_INVALID;
6216
6217 // pos now points to start of payload
6218
6219 if (size == 0) // weird
6220 continue;
6221
6222 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
6223 return E_FILE_FORMAT_INVALID;
6224
6225 if (id == 0x67) { // TimeCode ID
6226 len = static_cast<long>(size);
6227
6228 if ((pos + size) > avail)
6229 return E_BUFFER_NOT_FULL;
6230
6231 timecode = UnserializeUInt(pReader, pos, size);
6232
6233 if (timecode < 0) // error (or underflow)
6234 return static_cast<long>(timecode);
6235
6236 new_pos = pos + size;
6237
6238 if (bBlock)
6239 break;
6240 } else if (id == 0x20) { // BlockGroup ID
6241 bBlock = true;
6242 break;
6243 } else if (id == 0x23) { // SimpleBlock ID
6244 bBlock = true;
6245 break;
6246 }
6247
6248 pos += size; // consume payload
6249 assert((cluster_stop < 0) || (pos <= cluster_stop));
6250 }
6251
6252 assert((cluster_stop < 0) || (pos <= cluster_stop));
6253
6254 if (timecode < 0) // no timecode found
6255 return E_FILE_FORMAT_INVALID;
6256
6257 if (!bBlock)
6258 return E_FILE_FORMAT_INVALID;
6259
6260 m_pos = new_pos; // designates position just beyond timecode payload
6261 m_timecode = timecode; // m_timecode >= 0 means we're partially loaded
6262
6263 if (cluster_size >= 0)
6264 m_element_size = cluster_stop - m_element_start;
6265
6266 return 0;
6267 }
6268
Parse(long long & pos,long & len) const6269 long Cluster::Parse(long long& pos, long& len) const {
6270 long status = Load(pos, len);
6271
6272 if (status < 0)
6273 return status;
6274
6275 assert(m_pos >= m_element_start);
6276 assert(m_timecode >= 0);
6277 // assert(m_size > 0);
6278 // assert(m_element_size > m_size);
6279
6280 const long long cluster_stop =
6281 (m_element_size < 0) ? -1 : m_element_start + m_element_size;
6282
6283 if ((cluster_stop >= 0) && (m_pos >= cluster_stop))
6284 return 1; // nothing else to do
6285
6286 IMkvReader* const pReader = m_pSegment->m_pReader;
6287
6288 long long total, avail;
6289
6290 status = pReader->Length(&total, &avail);
6291
6292 if (status < 0) // error
6293 return status;
6294
6295 assert((total < 0) || (avail <= total));
6296
6297 pos = m_pos;
6298
6299 for (;;) {
6300 if ((cluster_stop >= 0) && (pos >= cluster_stop))
6301 break;
6302
6303 if ((total >= 0) && (pos >= total)) {
6304 if (m_element_size < 0)
6305 m_element_size = pos - m_element_start;
6306
6307 break;
6308 }
6309
6310 // Parse ID
6311
6312 if ((pos + 1) > avail) {
6313 len = 1;
6314 return E_BUFFER_NOT_FULL;
6315 }
6316
6317 long long result = GetUIntLength(pReader, pos, len);
6318
6319 if (result < 0) // error
6320 return static_cast<long>(result);
6321
6322 if (result > 0) // weird
6323 return E_BUFFER_NOT_FULL;
6324
6325 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6326 return E_FILE_FORMAT_INVALID;
6327
6328 if ((pos + len) > avail)
6329 return E_BUFFER_NOT_FULL;
6330
6331 const long long id = ReadUInt(pReader, pos, len);
6332
6333 if (id < 0) // error
6334 return static_cast<long>(id);
6335
6336 if (id == 0) // weird
6337 return E_FILE_FORMAT_INVALID;
6338
6339 // This is the distinguished set of ID's we use to determine
6340 // that we have exhausted the sub-element's inside the cluster
6341 // whose ID we parsed earlier.
6342
6343 if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) { // Cluster or Cues ID
6344 if (m_element_size < 0)
6345 m_element_size = pos - m_element_start;
6346
6347 break;
6348 }
6349
6350 pos += len; // consume ID field
6351
6352 // Parse Size
6353
6354 if ((pos + 1) > avail) {
6355 len = 1;
6356 return E_BUFFER_NOT_FULL;
6357 }
6358
6359 result = GetUIntLength(pReader, pos, len);
6360
6361 if (result < 0) // error
6362 return static_cast<long>(result);
6363
6364 if (result > 0) // weird
6365 return E_BUFFER_NOT_FULL;
6366
6367 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
6368 return E_FILE_FORMAT_INVALID;
6369
6370 if ((pos + len) > avail)
6371 return E_BUFFER_NOT_FULL;
6372
6373 const long long size = ReadUInt(pReader, pos, len);
6374
6375 if (size < 0) // error
6376 return static_cast<long>(size);
6377
6378 const long long unknown_size = (1LL << (7 * len)) - 1;
6379
6380 if (size == unknown_size)
6381 return E_FILE_FORMAT_INVALID;
6382
6383 pos += len; // consume size field
6384
6385 if ((cluster_stop >= 0) && (pos > cluster_stop))
6386 return E_FILE_FORMAT_INVALID;
6387
6388 // pos now points to start of payload
6389
6390 if (size == 0) // weird
6391 continue;
6392
6393 // const long long block_start = pos;
6394 const long long block_stop = pos + size;
6395
6396 if (cluster_stop >= 0) {
6397 if (block_stop > cluster_stop) {
6398 if ((id == 0x20) || (id == 0x23))
6399 return E_FILE_FORMAT_INVALID;
6400
6401 pos = cluster_stop;
6402 break;
6403 }
6404 } else if ((total >= 0) && (block_stop > total)) {
6405 m_element_size = total - m_element_start;
6406 pos = total;
6407 break;
6408 } else if (block_stop > avail) {
6409 len = static_cast<long>(size);
6410 return E_BUFFER_NOT_FULL;
6411 }
6412
6413 Cluster* const this_ = const_cast<Cluster*>(this);
6414
6415 if (id == 0x20) // BlockGroup
6416 return this_->ParseBlockGroup(size, pos, len);
6417
6418 if (id == 0x23) // SimpleBlock
6419 return this_->ParseSimpleBlock(size, pos, len);
6420
6421 pos += size; // consume payload
6422 assert((cluster_stop < 0) || (pos <= cluster_stop));
6423 }
6424
6425 assert(m_element_size > 0);
6426
6427 m_pos = pos;
6428 assert((cluster_stop < 0) || (m_pos <= cluster_stop));
6429
6430 if (m_entries_count > 0) {
6431 const long idx = m_entries_count - 1;
6432
6433 const BlockEntry* const pLast = m_entries[idx];
6434 assert(pLast);
6435
6436 const Block* const pBlock = pLast->GetBlock();
6437 assert(pBlock);
6438
6439 const long long start = pBlock->m_start;
6440
6441 if ((total >= 0) && (start > total))
6442 return -1; // defend against trucated stream
6443
6444 const long long size = pBlock->m_size;
6445
6446 const long long stop = start + size;
6447 assert((cluster_stop < 0) || (stop <= cluster_stop));
6448
6449 if ((total >= 0) && (stop > total))
6450 return -1; // defend against trucated stream
6451 }
6452
6453 return 1; // no more entries
6454 }
6455
ParseSimpleBlock(long long block_size,long long & pos,long & len)6456 long Cluster::ParseSimpleBlock(long long block_size, long long& pos,
6457 long& len) {
6458 const long long block_start = pos;
6459 const long long block_stop = pos + block_size;
6460
6461 IMkvReader* const pReader = m_pSegment->m_pReader;
6462
6463 long long total, avail;
6464
6465 long status = pReader->Length(&total, &avail);
6466
6467 if (status < 0) // error
6468 return status;
6469
6470 assert((total < 0) || (avail <= total));
6471
6472 // parse track number
6473
6474 if ((pos + 1) > avail) {
6475 len = 1;
6476 return E_BUFFER_NOT_FULL;
6477 }
6478
6479 long long result = GetUIntLength(pReader, pos, len);
6480
6481 if (result < 0) // error
6482 return static_cast<long>(result);
6483
6484 if (result > 0) // weird
6485 return E_BUFFER_NOT_FULL;
6486
6487 if ((pos + len) > block_stop)
6488 return E_FILE_FORMAT_INVALID;
6489
6490 if ((pos + len) > avail)
6491 return E_BUFFER_NOT_FULL;
6492
6493 const long long track = ReadUInt(pReader, pos, len);
6494
6495 if (track < 0) // error
6496 return static_cast<long>(track);
6497
6498 if (track == 0)
6499 return E_FILE_FORMAT_INVALID;
6500
6501 #if 0
6502 //TODO(matthewjheaney)
6503 //This turned out to be too conservative. The problem is that
6504 //if we see a track header in the tracks element with an unsupported
6505 //track type, we throw that track header away, so it is not present
6506 //in the track map. But even though we don't understand the track
6507 //header, there are still blocks in the cluster with that track
6508 //number. It was our decision to ignore that track header, so it's
6509 //up to us to deal with blocks associated with that track -- we
6510 //cannot simply report an error since technically there's nothing
6511 //wrong with the file.
6512 //
6513 //For now we go ahead and finish the parse, creating a block entry
6514 //for this block. This is somewhat wasteful, because without a
6515 //track header there's nothing you can do with the block. What
6516 //we really need here is a special return value that indicates to
6517 //the caller that he should ignore this particular block, and
6518 //continue parsing.
6519
6520 const Tracks* const pTracks = m_pSegment->GetTracks();
6521 assert(pTracks);
6522
6523 const long tn = static_cast<long>(track);
6524
6525 const Track* const pTrack = pTracks->GetTrackByNumber(tn);
6526
6527 if (pTrack == NULL)
6528 return E_FILE_FORMAT_INVALID;
6529 #endif
6530
6531 pos += len; // consume track number
6532
6533 if ((pos + 2) > block_stop)
6534 return E_FILE_FORMAT_INVALID;
6535
6536 if ((pos + 2) > avail) {
6537 len = 2;
6538 return E_BUFFER_NOT_FULL;
6539 }
6540
6541 pos += 2; // consume timecode
6542
6543 if ((pos + 1) > block_stop)
6544 return E_FILE_FORMAT_INVALID;
6545
6546 if ((pos + 1) > avail) {
6547 len = 1;
6548 return E_BUFFER_NOT_FULL;
6549 }
6550
6551 unsigned char flags;
6552
6553 status = pReader->Read(pos, 1, &flags);
6554
6555 if (status < 0) { // error or underflow
6556 len = 1;
6557 return status;
6558 }
6559
6560 ++pos; // consume flags byte
6561 assert(pos <= avail);
6562
6563 if (pos >= block_stop)
6564 return E_FILE_FORMAT_INVALID;
6565
6566 const int lacing = int(flags & 0x06) >> 1;
6567
6568 if ((lacing != 0) && (block_stop > avail)) {
6569 len = static_cast<long>(block_stop - pos);
6570 return E_BUFFER_NOT_FULL;
6571 }
6572
6573 status = CreateBlock(0x23, // simple block id
6574 block_start, block_size,
6575 0); // DiscardPadding
6576
6577 if (status != 0)
6578 return status;
6579
6580 m_pos = block_stop;
6581
6582 return 0; // success
6583 }
6584
ParseBlockGroup(long long payload_size,long long & pos,long & len)6585 long Cluster::ParseBlockGroup(long long payload_size, long long& pos,
6586 long& len) {
6587 const long long payload_start = pos;
6588 const long long payload_stop = pos + payload_size;
6589
6590 IMkvReader* const pReader = m_pSegment->m_pReader;
6591
6592 long long total, avail;
6593
6594 long status = pReader->Length(&total, &avail);
6595
6596 if (status < 0) // error
6597 return status;
6598
6599 assert((total < 0) || (avail <= total));
6600
6601 if ((total >= 0) && (payload_stop > total))
6602 return E_FILE_FORMAT_INVALID;
6603
6604 if (payload_stop > avail) {
6605 len = static_cast<long>(payload_size);
6606 return E_BUFFER_NOT_FULL;
6607 }
6608
6609 long long discard_padding = 0;
6610
6611 while (pos < payload_stop) {
6612 // parse sub-block element ID
6613
6614 if ((pos + 1) > avail) {
6615 len = 1;
6616 return E_BUFFER_NOT_FULL;
6617 }
6618
6619 long long result = GetUIntLength(pReader, pos, len);
6620
6621 if (result < 0) // error
6622 return static_cast<long>(result);
6623
6624 if (result > 0) // weird
6625 return E_BUFFER_NOT_FULL;
6626
6627 if ((pos + len) > payload_stop)
6628 return E_FILE_FORMAT_INVALID;
6629
6630 if ((pos + len) > avail)
6631 return E_BUFFER_NOT_FULL;
6632
6633 const long long id = ReadUInt(pReader, pos, len);
6634
6635 if (id < 0) // error
6636 return static_cast<long>(id);
6637
6638 if (id == 0) // not a value ID
6639 return E_FILE_FORMAT_INVALID;
6640
6641 pos += len; // consume ID field
6642
6643 // Parse Size
6644
6645 if ((pos + 1) > avail) {
6646 len = 1;
6647 return E_BUFFER_NOT_FULL;
6648 }
6649
6650 result = GetUIntLength(pReader, pos, len);
6651
6652 if (result < 0) // error
6653 return static_cast<long>(result);
6654
6655 if (result > 0) // weird
6656 return E_BUFFER_NOT_FULL;
6657
6658 if ((pos + len) > payload_stop)
6659 return E_FILE_FORMAT_INVALID;
6660
6661 if ((pos + len) > avail)
6662 return E_BUFFER_NOT_FULL;
6663
6664 const long long size = ReadUInt(pReader, pos, len);
6665
6666 if (size < 0) // error
6667 return static_cast<long>(size);
6668
6669 pos += len; // consume size field
6670
6671 // pos now points to start of sub-block group payload
6672
6673 if (pos > payload_stop)
6674 return E_FILE_FORMAT_INVALID;
6675
6676 if (size == 0) // weird
6677 continue;
6678
6679 const long long unknown_size = (1LL << (7 * len)) - 1;
6680
6681 if (size == unknown_size)
6682 return E_FILE_FORMAT_INVALID;
6683
6684 if (id == 0x35A2) { // DiscardPadding
6685 status = UnserializeInt(pReader, pos, size, discard_padding);
6686
6687 if (status < 0) // error
6688 return status;
6689 }
6690
6691 if (id != 0x21) { // sub-part of BlockGroup is not a Block
6692 pos += size; // consume sub-part of block group
6693
6694 if (pos > payload_stop)
6695 return E_FILE_FORMAT_INVALID;
6696
6697 continue;
6698 }
6699
6700 const long long block_stop = pos + size;
6701
6702 if (block_stop > payload_stop)
6703 return E_FILE_FORMAT_INVALID;
6704
6705 // parse track number
6706
6707 if ((pos + 1) > avail) {
6708 len = 1;
6709 return E_BUFFER_NOT_FULL;
6710 }
6711
6712 result = GetUIntLength(pReader, pos, len);
6713
6714 if (result < 0) // error
6715 return static_cast<long>(result);
6716
6717 if (result > 0) // weird
6718 return E_BUFFER_NOT_FULL;
6719
6720 if ((pos + len) > block_stop)
6721 return E_FILE_FORMAT_INVALID;
6722
6723 if ((pos + len) > avail)
6724 return E_BUFFER_NOT_FULL;
6725
6726 const long long track = ReadUInt(pReader, pos, len);
6727
6728 if (track < 0) // error
6729 return static_cast<long>(track);
6730
6731 if (track == 0)
6732 return E_FILE_FORMAT_INVALID;
6733
6734 #if 0
6735 //TODO(matthewjheaney)
6736 //This turned out to be too conservative. The problem is that
6737 //if we see a track header in the tracks element with an unsupported
6738 //track type, we throw that track header away, so it is not present
6739 //in the track map. But even though we don't understand the track
6740 //header, there are still blocks in the cluster with that track
6741 //number. It was our decision to ignore that track header, so it's
6742 //up to us to deal with blocks associated with that track -- we
6743 //cannot simply report an error since technically there's nothing
6744 //wrong with the file.
6745 //
6746 //For now we go ahead and finish the parse, creating a block entry
6747 //for this block. This is somewhat wasteful, because without a
6748 //track header there's nothing you can do with the block. What
6749 //we really need here is a special return value that indicates to
6750 //the caller that he should ignore this particular block, and
6751 //continue parsing.
6752
6753 const Tracks* const pTracks = m_pSegment->GetTracks();
6754 assert(pTracks);
6755
6756 const long tn = static_cast<long>(track);
6757
6758 const Track* const pTrack = pTracks->GetTrackByNumber(tn);
6759
6760 if (pTrack == NULL)
6761 return E_FILE_FORMAT_INVALID;
6762 #endif
6763
6764 pos += len; // consume track number
6765
6766 if ((pos + 2) > block_stop)
6767 return E_FILE_FORMAT_INVALID;
6768
6769 if ((pos + 2) > avail) {
6770 len = 2;
6771 return E_BUFFER_NOT_FULL;
6772 }
6773
6774 pos += 2; // consume timecode
6775
6776 if ((pos + 1) > block_stop)
6777 return E_FILE_FORMAT_INVALID;
6778
6779 if ((pos + 1) > avail) {
6780 len = 1;
6781 return E_BUFFER_NOT_FULL;
6782 }
6783
6784 unsigned char flags;
6785
6786 status = pReader->Read(pos, 1, &flags);
6787
6788 if (status < 0) { // error or underflow
6789 len = 1;
6790 return status;
6791 }
6792
6793 ++pos; // consume flags byte
6794 assert(pos <= avail);
6795
6796 if (pos >= block_stop)
6797 return E_FILE_FORMAT_INVALID;
6798
6799 const int lacing = int(flags & 0x06) >> 1;
6800
6801 if ((lacing != 0) && (block_stop > avail)) {
6802 len = static_cast<long>(block_stop - pos);
6803 return E_BUFFER_NOT_FULL;
6804 }
6805
6806 pos = block_stop; // consume block-part of block group
6807 assert(pos <= payload_stop);
6808 }
6809
6810 assert(pos == payload_stop);
6811
6812 status = CreateBlock(0x20, // BlockGroup ID
6813 payload_start, payload_size, discard_padding);
6814 if (status != 0)
6815 return status;
6816
6817 m_pos = payload_stop;
6818
6819 return 0; // success
6820 }
6821
GetEntry(long index,const mkvparser::BlockEntry * & pEntry) const6822 long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const {
6823 assert(m_pos >= m_element_start);
6824
6825 pEntry = NULL;
6826
6827 if (index < 0)
6828 return -1; // generic error
6829
6830 if (m_entries_count < 0)
6831 return E_BUFFER_NOT_FULL;
6832
6833 assert(m_entries);
6834 assert(m_entries_size > 0);
6835 assert(m_entries_count <= m_entries_size);
6836
6837 if (index < m_entries_count) {
6838 pEntry = m_entries[index];
6839 assert(pEntry);
6840
6841 return 1; // found entry
6842 }
6843
6844 if (m_element_size < 0) // we don't know cluster end yet
6845 return E_BUFFER_NOT_FULL; // underflow
6846
6847 const long long element_stop = m_element_start + m_element_size;
6848
6849 if (m_pos >= element_stop)
6850 return 0; // nothing left to parse
6851
6852 return E_BUFFER_NOT_FULL; // underflow, since more remains to be parsed
6853 }
6854
Create(Segment * pSegment,long idx,long long off)6855 Cluster* Cluster::Create(Segment* pSegment, long idx, long long off)
6856 // long long element_size)
6857 {
6858 assert(pSegment);
6859 assert(off >= 0);
6860
6861 const long long element_start = pSegment->m_start + off;
6862
6863 Cluster* const pCluster = new Cluster(pSegment, idx, element_start);
6864 // element_size);
6865 assert(pCluster);
6866
6867 return pCluster;
6868 }
6869
Cluster()6870 Cluster::Cluster()
6871 : m_pSegment(NULL),
6872 m_element_start(0),
6873 m_index(0),
6874 m_pos(0),
6875 m_element_size(0),
6876 m_timecode(0),
6877 m_entries(NULL),
6878 m_entries_size(0),
6879 m_entries_count(0) // means "no entries"
6880 {}
6881
Cluster(Segment * pSegment,long idx,long long element_start)6882 Cluster::Cluster(Segment* pSegment, long idx, long long element_start
6883 /* long long element_size */)
6884 : m_pSegment(pSegment),
6885 m_element_start(element_start),
6886 m_index(idx),
6887 m_pos(element_start),
6888 m_element_size(-1 /* element_size */),
6889 m_timecode(-1),
6890 m_entries(NULL),
6891 m_entries_size(0),
6892 m_entries_count(-1) // means "has not been parsed yet"
6893 {}
6894
~Cluster()6895 Cluster::~Cluster() {
6896 if (m_entries_count <= 0)
6897 return;
6898
6899 BlockEntry** i = m_entries;
6900 BlockEntry** const j = m_entries + m_entries_count;
6901
6902 while (i != j) {
6903 BlockEntry* p = *i++;
6904 assert(p);
6905
6906 delete p;
6907 }
6908
6909 delete[] m_entries;
6910 }
6911
EOS() const6912 bool Cluster::EOS() const { return (m_pSegment == NULL); }
6913
GetIndex() const6914 long Cluster::GetIndex() const { return m_index; }
6915
GetPosition() const6916 long long Cluster::GetPosition() const {
6917 const long long pos = m_element_start - m_pSegment->m_start;
6918 assert(pos >= 0);
6919
6920 return pos;
6921 }
6922
GetElementSize() const6923 long long Cluster::GetElementSize() const { return m_element_size; }
6924
6925 #if 0
6926 bool Cluster::HasBlockEntries(
6927 const Segment* pSegment,
6928 long long off) {
6929 assert(pSegment);
6930 assert(off >= 0); //relative to start of segment payload
6931
6932 IMkvReader* const pReader = pSegment->m_pReader;
6933
6934 long long pos = pSegment->m_start + off; //absolute
6935 long long size;
6936
6937 {
6938 long len;
6939
6940 const long long id = ReadUInt(pReader, pos, len);
6941 (void)id;
6942 assert(id >= 0);
6943 assert(id == 0x0F43B675); //Cluster ID
6944
6945 pos += len; //consume id
6946
6947 size = ReadUInt(pReader, pos, len);
6948 assert(size > 0);
6949
6950 pos += len; //consume size
6951
6952 //pos now points to start of payload
6953 }
6954
6955 const long long stop = pos + size;
6956
6957 while (pos < stop)
6958 {
6959 long len;
6960
6961 const long long id = ReadUInt(pReader, pos, len);
6962 assert(id >= 0); //TODO
6963 assert((pos + len) <= stop);
6964
6965 pos += len; //consume id
6966
6967 const long long size = ReadUInt(pReader, pos, len);
6968 assert(size >= 0); //TODO
6969 assert((pos + len) <= stop);
6970
6971 pos += len; //consume size
6972
6973 if (id == 0x20) //BlockGroup ID
6974 return true;
6975
6976 if (id == 0x23) //SimpleBlock ID
6977 return true;
6978
6979 pos += size; //consume payload
6980 assert(pos <= stop);
6981 }
6982
6983 return false;
6984 }
6985 #endif
6986
HasBlockEntries(const Segment * pSegment,long long off,long long & pos,long & len)6987 long Cluster::HasBlockEntries(
6988 const Segment* pSegment,
6989 long long off, // relative to start of segment payload
6990 long long& pos, long& len) {
6991 assert(pSegment);
6992 assert(off >= 0); // relative to segment
6993
6994 IMkvReader* const pReader = pSegment->m_pReader;
6995
6996 long long total, avail;
6997
6998 long status = pReader->Length(&total, &avail);
6999
7000 if (status < 0) // error
7001 return status;
7002
7003 assert((total < 0) || (avail <= total));
7004
7005 pos = pSegment->m_start + off; // absolute
7006
7007 if ((total >= 0) && (pos >= total))
7008 return 0; // we don't even have a complete cluster
7009
7010 const long long segment_stop =
7011 (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size;
7012
7013 long long cluster_stop = -1; // interpreted later to mean "unknown size"
7014
7015 {
7016 if ((pos + 1) > avail) {
7017 len = 1;
7018 return E_BUFFER_NOT_FULL;
7019 }
7020
7021 long long result = GetUIntLength(pReader, pos, len);
7022
7023 if (result < 0) // error
7024 return static_cast<long>(result);
7025
7026 if (result > 0) // need more data
7027 return E_BUFFER_NOT_FULL;
7028
7029 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
7030 return E_FILE_FORMAT_INVALID;
7031
7032 if ((total >= 0) && ((pos + len) > total))
7033 return 0;
7034
7035 if ((pos + len) > avail)
7036 return E_BUFFER_NOT_FULL;
7037
7038 const long long id = ReadUInt(pReader, pos, len);
7039
7040 if (id < 0) // error
7041 return static_cast<long>(id);
7042
7043 if (id != 0x0F43B675) // weird: not cluster ID
7044 return -1; // generic error
7045
7046 pos += len; // consume Cluster ID field
7047
7048 // read size field
7049
7050 if ((pos + 1) > avail) {
7051 len = 1;
7052 return E_BUFFER_NOT_FULL;
7053 }
7054
7055 result = GetUIntLength(pReader, pos, len);
7056
7057 if (result < 0) // error
7058 return static_cast<long>(result);
7059
7060 if (result > 0) // weird
7061 return E_BUFFER_NOT_FULL;
7062
7063 if ((segment_stop >= 0) && ((pos + len) > segment_stop))
7064 return E_FILE_FORMAT_INVALID;
7065
7066 if ((total >= 0) && ((pos + len) > total))
7067 return 0;
7068
7069 if ((pos + len) > avail)
7070 return E_BUFFER_NOT_FULL;
7071
7072 const long long size = ReadUInt(pReader, pos, len);
7073
7074 if (size < 0) // error
7075 return static_cast<long>(size);
7076
7077 if (size == 0)
7078 return 0; // cluster does not have entries
7079
7080 pos += len; // consume size field
7081
7082 // pos now points to start of payload
7083
7084 const long long unknown_size = (1LL << (7 * len)) - 1;
7085
7086 if (size != unknown_size) {
7087 cluster_stop = pos + size;
7088 assert(cluster_stop >= 0);
7089
7090 if ((segment_stop >= 0) && (cluster_stop > segment_stop))
7091 return E_FILE_FORMAT_INVALID;
7092
7093 if ((total >= 0) && (cluster_stop > total))
7094 // return E_FILE_FORMAT_INVALID; //too conservative
7095 return 0; // cluster does not have any entries
7096 }
7097 }
7098
7099 for (;;) {
7100 if ((cluster_stop >= 0) && (pos >= cluster_stop))
7101 return 0; // no entries detected
7102
7103 if ((pos + 1) > avail) {
7104 len = 1;
7105 return E_BUFFER_NOT_FULL;
7106 }
7107
7108 long long result = GetUIntLength(pReader, pos, len);
7109
7110 if (result < 0) // error
7111 return static_cast<long>(result);
7112
7113 if (result > 0) // need more data
7114 return E_BUFFER_NOT_FULL;
7115
7116 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7117 return E_FILE_FORMAT_INVALID;
7118
7119 if ((pos + len) > avail)
7120 return E_BUFFER_NOT_FULL;
7121
7122 const long long id = ReadUInt(pReader, pos, len);
7123
7124 if (id < 0) // error
7125 return static_cast<long>(id);
7126
7127 // This is the distinguished set of ID's we use to determine
7128 // that we have exhausted the sub-element's inside the cluster
7129 // whose ID we parsed earlier.
7130
7131 if (id == 0x0F43B675) // Cluster ID
7132 return 0; // no entries found
7133
7134 if (id == 0x0C53BB6B) // Cues ID
7135 return 0; // no entries found
7136
7137 pos += len; // consume id field
7138
7139 if ((cluster_stop >= 0) && (pos >= cluster_stop))
7140 return E_FILE_FORMAT_INVALID;
7141
7142 // read size field
7143
7144 if ((pos + 1) > avail) {
7145 len = 1;
7146 return E_BUFFER_NOT_FULL;
7147 }
7148
7149 result = GetUIntLength(pReader, pos, len);
7150
7151 if (result < 0) // error
7152 return static_cast<long>(result);
7153
7154 if (result > 0) // underflow
7155 return E_BUFFER_NOT_FULL;
7156
7157 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop))
7158 return E_FILE_FORMAT_INVALID;
7159
7160 if ((pos + len) > avail)
7161 return E_BUFFER_NOT_FULL;
7162
7163 const long long size = ReadUInt(pReader, pos, len);
7164
7165 if (size < 0) // error
7166 return static_cast<long>(size);
7167
7168 pos += len; // consume size field
7169
7170 // pos now points to start of payload
7171
7172 if ((cluster_stop >= 0) && (pos > cluster_stop))
7173 return E_FILE_FORMAT_INVALID;
7174
7175 if (size == 0) // weird
7176 continue;
7177
7178 const long long unknown_size = (1LL << (7 * len)) - 1;
7179
7180 if (size == unknown_size)
7181 return E_FILE_FORMAT_INVALID; // not supported inside cluster
7182
7183 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop))
7184 return E_FILE_FORMAT_INVALID;
7185
7186 if (id == 0x20) // BlockGroup ID
7187 return 1; // have at least one entry
7188
7189 if (id == 0x23) // SimpleBlock ID
7190 return 1; // have at least one entry
7191
7192 pos += size; // consume payload
7193 assert((cluster_stop < 0) || (pos <= cluster_stop));
7194 }
7195 }
7196
GetTimeCode() const7197 long long Cluster::GetTimeCode() const {
7198 long long pos;
7199 long len;
7200
7201 const long status = Load(pos, len);
7202
7203 if (status < 0) // error
7204 return status;
7205
7206 return m_timecode;
7207 }
7208
GetTime() const7209 long long Cluster::GetTime() const {
7210 const long long tc = GetTimeCode();
7211
7212 if (tc < 0)
7213 return tc;
7214
7215 const SegmentInfo* const pInfo = m_pSegment->GetInfo();
7216 assert(pInfo);
7217
7218 const long long scale = pInfo->GetTimeCodeScale();
7219 assert(scale >= 1);
7220
7221 const long long t = m_timecode * scale;
7222
7223 return t;
7224 }
7225
GetFirstTime() const7226 long long Cluster::GetFirstTime() const {
7227 const BlockEntry* pEntry;
7228
7229 const long status = GetFirst(pEntry);
7230
7231 if (status < 0) // error
7232 return status;
7233
7234 if (pEntry == NULL) // empty cluster
7235 return GetTime();
7236
7237 const Block* const pBlock = pEntry->GetBlock();
7238 assert(pBlock);
7239
7240 return pBlock->GetTime(this);
7241 }
7242
GetLastTime() const7243 long long Cluster::GetLastTime() const {
7244 const BlockEntry* pEntry;
7245
7246 const long status = GetLast(pEntry);
7247
7248 if (status < 0) // error
7249 return status;
7250
7251 if (pEntry == NULL) // empty cluster
7252 return GetTime();
7253
7254 const Block* const pBlock = pEntry->GetBlock();
7255 assert(pBlock);
7256
7257 return pBlock->GetTime(this);
7258 }
7259
CreateBlock(long long id,long long pos,long long size,long long discard_padding)7260 long Cluster::CreateBlock(long long id,
7261 long long pos, // absolute pos of payload
7262 long long size, long long discard_padding) {
7263 assert((id == 0x20) || (id == 0x23)); // BlockGroup or SimpleBlock
7264
7265 if (m_entries_count < 0) { // haven't parsed anything yet
7266 assert(m_entries == NULL);
7267 assert(m_entries_size == 0);
7268
7269 m_entries_size = 1024;
7270 m_entries = new BlockEntry* [m_entries_size];
7271
7272 m_entries_count = 0;
7273 } else {
7274 assert(m_entries);
7275 assert(m_entries_size > 0);
7276 assert(m_entries_count <= m_entries_size);
7277
7278 if (m_entries_count >= m_entries_size) {
7279 const long entries_size = 2 * m_entries_size;
7280
7281 BlockEntry** const entries = new BlockEntry* [entries_size];
7282 assert(entries);
7283
7284 BlockEntry** src = m_entries;
7285 BlockEntry** const src_end = src + m_entries_count;
7286
7287 BlockEntry** dst = entries;
7288
7289 while (src != src_end)
7290 *dst++ = *src++;
7291
7292 delete[] m_entries;
7293
7294 m_entries = entries;
7295 m_entries_size = entries_size;
7296 }
7297 }
7298
7299 if (id == 0x20) // BlockGroup ID
7300 return CreateBlockGroup(pos, size, discard_padding);
7301 else // SimpleBlock ID
7302 return CreateSimpleBlock(pos, size);
7303 }
7304
CreateBlockGroup(long long start_offset,long long size,long long discard_padding)7305 long Cluster::CreateBlockGroup(long long start_offset, long long size,
7306 long long discard_padding) {
7307 assert(m_entries);
7308 assert(m_entries_size > 0);
7309 assert(m_entries_count >= 0);
7310 assert(m_entries_count < m_entries_size);
7311
7312 IMkvReader* const pReader = m_pSegment->m_pReader;
7313
7314 long long pos = start_offset;
7315 const long long stop = start_offset + size;
7316
7317 // For WebM files, there is a bias towards previous reference times
7318 //(in order to support alt-ref frames, which refer back to the previous
7319 // keyframe). Normally a 0 value is not possible, but here we tenatively
7320 // allow 0 as the value of a reference frame, with the interpretation
7321 // that this is a "previous" reference time.
7322
7323 long long prev = 1; // nonce
7324 long long next = 0; // nonce
7325 long long duration = -1; // really, this is unsigned
7326
7327 long long bpos = -1;
7328 long long bsize = -1;
7329
7330 while (pos < stop) {
7331 long len;
7332 const long long id = ReadUInt(pReader, pos, len);
7333 assert(id >= 0); // TODO
7334 assert((pos + len) <= stop);
7335
7336 pos += len; // consume ID
7337
7338 const long long size = ReadUInt(pReader, pos, len);
7339 assert(size >= 0); // TODO
7340 assert((pos + len) <= stop);
7341
7342 pos += len; // consume size
7343
7344 if (id == 0x21) { // Block ID
7345 if (bpos < 0) { // Block ID
7346 bpos = pos;
7347 bsize = size;
7348 }
7349 } else if (id == 0x1B) { // Duration ID
7350 assert(size <= 8);
7351
7352 duration = UnserializeUInt(pReader, pos, size);
7353 assert(duration >= 0); // TODO
7354 } else if (id == 0x7B) { // ReferenceBlock
7355 assert(size <= 8);
7356 const long size_ = static_cast<long>(size);
7357
7358 long long time;
7359
7360 long status = UnserializeInt(pReader, pos, size_, time);
7361 assert(status == 0);
7362 if (status != 0)
7363 return -1;
7364
7365 if (time <= 0) // see note above
7366 prev = time;
7367 else // weird
7368 next = time;
7369 }
7370
7371 pos += size; // consume payload
7372 assert(pos <= stop);
7373 }
7374
7375 assert(pos == stop);
7376 assert(bpos >= 0);
7377 assert(bsize >= 0);
7378
7379 const long idx = m_entries_count;
7380
7381 BlockEntry** const ppEntry = m_entries + idx;
7382 BlockEntry*& pEntry = *ppEntry;
7383
7384 pEntry = new (std::nothrow)
7385 BlockGroup(this, idx, bpos, bsize, prev, next, duration, discard_padding);
7386
7387 if (pEntry == NULL)
7388 return -1; // generic error
7389
7390 BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
7391
7392 const long status = p->Parse();
7393
7394 if (status == 0) { // success
7395 ++m_entries_count;
7396 return 0;
7397 }
7398
7399 delete pEntry;
7400 pEntry = 0;
7401
7402 return status;
7403 }
7404
CreateSimpleBlock(long long st,long long sz)7405 long Cluster::CreateSimpleBlock(long long st, long long sz) {
7406 assert(m_entries);
7407 assert(m_entries_size > 0);
7408 assert(m_entries_count >= 0);
7409 assert(m_entries_count < m_entries_size);
7410
7411 const long idx = m_entries_count;
7412
7413 BlockEntry** const ppEntry = m_entries + idx;
7414 BlockEntry*& pEntry = *ppEntry;
7415
7416 pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
7417
7418 if (pEntry == NULL)
7419 return -1; // generic error
7420
7421 SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
7422
7423 const long status = p->Parse();
7424
7425 if (status == 0) {
7426 ++m_entries_count;
7427 return 0;
7428 }
7429
7430 delete pEntry;
7431 pEntry = 0;
7432
7433 return status;
7434 }
7435
GetFirst(const BlockEntry * & pFirst) const7436 long Cluster::GetFirst(const BlockEntry*& pFirst) const {
7437 if (m_entries_count <= 0) {
7438 long long pos;
7439 long len;
7440
7441 const long status = Parse(pos, len);
7442
7443 if (status < 0) { // error
7444 pFirst = NULL;
7445 return status;
7446 }
7447
7448 if (m_entries_count <= 0) { // empty cluster
7449 pFirst = NULL;
7450 return 0;
7451 }
7452 }
7453
7454 assert(m_entries);
7455
7456 pFirst = m_entries[0];
7457 assert(pFirst);
7458
7459 return 0; // success
7460 }
7461
GetLast(const BlockEntry * & pLast) const7462 long Cluster::GetLast(const BlockEntry*& pLast) const {
7463 for (;;) {
7464 long long pos;
7465 long len;
7466
7467 const long status = Parse(pos, len);
7468
7469 if (status < 0) { // error
7470 pLast = NULL;
7471 return status;
7472 }
7473
7474 if (status > 0) // no new block
7475 break;
7476 }
7477
7478 if (m_entries_count <= 0) {
7479 pLast = NULL;
7480 return 0;
7481 }
7482
7483 assert(m_entries);
7484
7485 const long idx = m_entries_count - 1;
7486
7487 pLast = m_entries[idx];
7488 assert(pLast);
7489
7490 return 0;
7491 }
7492
GetNext(const BlockEntry * pCurr,const BlockEntry * & pNext) const7493 long Cluster::GetNext(const BlockEntry* pCurr, const BlockEntry*& pNext) const {
7494 assert(pCurr);
7495 assert(m_entries);
7496 assert(m_entries_count > 0);
7497
7498 size_t idx = pCurr->GetIndex();
7499 assert(idx < size_t(m_entries_count));
7500 assert(m_entries[idx] == pCurr);
7501
7502 ++idx;
7503
7504 if (idx >= size_t(m_entries_count)) {
7505 long long pos;
7506 long len;
7507
7508 const long status = Parse(pos, len);
7509
7510 if (status < 0) { // error
7511 pNext = NULL;
7512 return status;
7513 }
7514
7515 if (status > 0) {
7516 pNext = NULL;
7517 return 0;
7518 }
7519
7520 assert(m_entries);
7521 assert(m_entries_count > 0);
7522 assert(idx < size_t(m_entries_count));
7523 }
7524
7525 pNext = m_entries[idx];
7526 assert(pNext);
7527
7528 return 0;
7529 }
7530
GetEntryCount() const7531 long Cluster::GetEntryCount() const { return m_entries_count; }
7532
GetEntry(const Track * pTrack,long long time_ns) const7533 const BlockEntry* Cluster::GetEntry(const Track* pTrack,
7534 long long time_ns) const {
7535 assert(pTrack);
7536
7537 if (m_pSegment == NULL) // this is the special EOS cluster
7538 return pTrack->GetEOS();
7539
7540 #if 0
7541
7542 LoadBlockEntries();
7543
7544 if ((m_entries == NULL) || (m_entries_count <= 0))
7545 return NULL; //return EOS here?
7546
7547 const BlockEntry* pResult = pTrack->GetEOS();
7548
7549 BlockEntry** i = m_entries;
7550 assert(i);
7551
7552 BlockEntry** const j = i + m_entries_count;
7553
7554 while (i != j)
7555 {
7556 const BlockEntry* const pEntry = *i++;
7557 assert(pEntry);
7558 assert(!pEntry->EOS());
7559
7560 const Block* const pBlock = pEntry->GetBlock();
7561 assert(pBlock);
7562
7563 if (pBlock->GetTrackNumber() != pTrack->GetNumber())
7564 continue;
7565
7566 if (pTrack->VetEntry(pEntry))
7567 {
7568 if (time_ns < 0) //just want first candidate block
7569 return pEntry;
7570
7571 const long long ns = pBlock->GetTime(this);
7572
7573 if (ns > time_ns)
7574 break;
7575
7576 pResult = pEntry;
7577 }
7578 else if (time_ns >= 0)
7579 {
7580 const long long ns = pBlock->GetTime(this);
7581
7582 if (ns > time_ns)
7583 break;
7584 }
7585 }
7586
7587 return pResult;
7588
7589 #else
7590
7591 const BlockEntry* pResult = pTrack->GetEOS();
7592
7593 long index = 0;
7594
7595 for (;;) {
7596 if (index >= m_entries_count) {
7597 long long pos;
7598 long len;
7599
7600 const long status = Parse(pos, len);
7601 assert(status >= 0);
7602
7603 if (status > 0) // completely parsed, and no more entries
7604 return pResult;
7605
7606 if (status < 0) // should never happen
7607 return 0;
7608
7609 assert(m_entries);
7610 assert(index < m_entries_count);
7611 }
7612
7613 const BlockEntry* const pEntry = m_entries[index];
7614 assert(pEntry);
7615 assert(!pEntry->EOS());
7616
7617 const Block* const pBlock = pEntry->GetBlock();
7618 assert(pBlock);
7619
7620 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) {
7621 ++index;
7622 continue;
7623 }
7624
7625 if (pTrack->VetEntry(pEntry)) {
7626 if (time_ns < 0) // just want first candidate block
7627 return pEntry;
7628
7629 const long long ns = pBlock->GetTime(this);
7630
7631 if (ns > time_ns)
7632 return pResult;
7633
7634 pResult = pEntry; // have a candidate
7635 } else if (time_ns >= 0) {
7636 const long long ns = pBlock->GetTime(this);
7637
7638 if (ns > time_ns)
7639 return pResult;
7640 }
7641
7642 ++index;
7643 }
7644
7645 #endif
7646 }
7647
GetEntry(const CuePoint & cp,const CuePoint::TrackPosition & tp) const7648 const BlockEntry* Cluster::GetEntry(const CuePoint& cp,
7649 const CuePoint::TrackPosition& tp) const {
7650 assert(m_pSegment);
7651
7652 #if 0
7653
7654 LoadBlockEntries();
7655
7656 if (m_entries == NULL)
7657 return NULL;
7658
7659 const long long count = m_entries_count;
7660
7661 if (count <= 0)
7662 return NULL;
7663
7664 const long long tc = cp.GetTimeCode();
7665
7666 if ((tp.m_block > 0) && (tp.m_block <= count))
7667 {
7668 const size_t block = static_cast<size_t>(tp.m_block);
7669 const size_t index = block - 1;
7670
7671 const BlockEntry* const pEntry = m_entries[index];
7672 assert(pEntry);
7673 assert(!pEntry->EOS());
7674
7675 const Block* const pBlock = pEntry->GetBlock();
7676 assert(pBlock);
7677
7678 if ((pBlock->GetTrackNumber() == tp.m_track) &&
7679 (pBlock->GetTimeCode(this) == tc))
7680 {
7681 return pEntry;
7682 }
7683 }
7684
7685 const BlockEntry* const* i = m_entries;
7686 const BlockEntry* const* const j = i + count;
7687
7688 while (i != j)
7689 {
7690 #ifdef _DEBUG
7691 const ptrdiff_t idx = i - m_entries;
7692 idx;
7693 #endif
7694
7695 const BlockEntry* const pEntry = *i++;
7696 assert(pEntry);
7697 assert(!pEntry->EOS());
7698
7699 const Block* const pBlock = pEntry->GetBlock();
7700 assert(pBlock);
7701
7702 if (pBlock->GetTrackNumber() != tp.m_track)
7703 continue;
7704
7705 const long long tc_ = pBlock->GetTimeCode(this);
7706 assert(tc_ >= 0);
7707
7708 if (tc_ < tc)
7709 continue;
7710
7711 if (tc_ > tc)
7712 return NULL;
7713
7714 const Tracks* const pTracks = m_pSegment->GetTracks();
7715 assert(pTracks);
7716
7717 const long tn = static_cast<long>(tp.m_track);
7718 const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7719
7720 if (pTrack == NULL)
7721 return NULL;
7722
7723 const long long type = pTrack->GetType();
7724
7725 if (type == 2) //audio
7726 return pEntry;
7727
7728 if (type != 1) //not video
7729 return NULL;
7730
7731 if (!pBlock->IsKey())
7732 return NULL;
7733
7734 return pEntry;
7735 }
7736
7737 return NULL;
7738
7739 #else
7740
7741 const long long tc = cp.GetTimeCode();
7742
7743 if (tp.m_block > 0) {
7744 const long block = static_cast<long>(tp.m_block);
7745 const long index = block - 1;
7746
7747 while (index >= m_entries_count) {
7748 long long pos;
7749 long len;
7750
7751 const long status = Parse(pos, len);
7752
7753 if (status < 0) // TODO: can this happen?
7754 return NULL;
7755
7756 if (status > 0) // nothing remains to be parsed
7757 return NULL;
7758 }
7759
7760 const BlockEntry* const pEntry = m_entries[index];
7761 assert(pEntry);
7762 assert(!pEntry->EOS());
7763
7764 const Block* const pBlock = pEntry->GetBlock();
7765 assert(pBlock);
7766
7767 if ((pBlock->GetTrackNumber() == tp.m_track) &&
7768 (pBlock->GetTimeCode(this) == tc)) {
7769 return pEntry;
7770 }
7771 }
7772
7773 long index = 0;
7774
7775 for (;;) {
7776 if (index >= m_entries_count) {
7777 long long pos;
7778 long len;
7779
7780 const long status = Parse(pos, len);
7781
7782 if (status < 0) // TODO: can this happen?
7783 return NULL;
7784
7785 if (status > 0) // nothing remains to be parsed
7786 return NULL;
7787
7788 assert(m_entries);
7789 assert(index < m_entries_count);
7790 }
7791
7792 const BlockEntry* const pEntry = m_entries[index];
7793 assert(pEntry);
7794 assert(!pEntry->EOS());
7795
7796 const Block* const pBlock = pEntry->GetBlock();
7797 assert(pBlock);
7798
7799 if (pBlock->GetTrackNumber() != tp.m_track) {
7800 ++index;
7801 continue;
7802 }
7803
7804 const long long tc_ = pBlock->GetTimeCode(this);
7805
7806 if (tc_ < tc) {
7807 ++index;
7808 continue;
7809 }
7810
7811 if (tc_ > tc)
7812 return NULL;
7813
7814 const Tracks* const pTracks = m_pSegment->GetTracks();
7815 assert(pTracks);
7816
7817 const long tn = static_cast<long>(tp.m_track);
7818 const Track* const pTrack = pTracks->GetTrackByNumber(tn);
7819
7820 if (pTrack == NULL)
7821 return NULL;
7822
7823 const long long type = pTrack->GetType();
7824
7825 if (type == 2) // audio
7826 return pEntry;
7827
7828 if (type != 1) // not video
7829 return NULL;
7830
7831 if (!pBlock->IsKey())
7832 return NULL;
7833
7834 return pEntry;
7835 }
7836
7837 #endif
7838 }
7839
7840 #if 0
7841 const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const
7842 {
7843 assert(pTrack);
7844
7845 if (m_pSegment == NULL) //EOS
7846 return pTrack->GetEOS();
7847
7848 LoadBlockEntries();
7849
7850 if ((m_entries == NULL) || (m_entries_count <= 0))
7851 return pTrack->GetEOS();
7852
7853 BlockEntry** i = m_entries + m_entries_count;
7854 BlockEntry** const j = m_entries;
7855
7856 while (i != j)
7857 {
7858 const BlockEntry* const pEntry = *--i;
7859 assert(pEntry);
7860 assert(!pEntry->EOS());
7861
7862 const Block* const pBlock = pEntry->GetBlock();
7863 assert(pBlock);
7864
7865 if (pBlock->GetTrackNumber() != pTrack->GetNumber())
7866 continue;
7867
7868 if (pBlock->IsKey())
7869 return pEntry;
7870 }
7871
7872 return pTrack->GetEOS(); //no satisfactory block found
7873 }
7874 #endif
7875
BlockEntry(Cluster * p,long idx)7876 BlockEntry::BlockEntry(Cluster* p, long idx) : m_pCluster(p), m_index(idx) {}
7877
~BlockEntry()7878 BlockEntry::~BlockEntry() {}
7879
EOS() const7880 bool BlockEntry::EOS() const { return (GetKind() == kBlockEOS); }
7881
GetCluster() const7882 const Cluster* BlockEntry::GetCluster() const { return m_pCluster; }
7883
GetIndex() const7884 long BlockEntry::GetIndex() const { return m_index; }
7885
SimpleBlock(Cluster * pCluster,long idx,long long start,long long size)7886 SimpleBlock::SimpleBlock(Cluster* pCluster, long idx, long long start,
7887 long long size)
7888 : BlockEntry(pCluster, idx), m_block(start, size, 0) {}
7889
Parse()7890 long SimpleBlock::Parse() { return m_block.Parse(m_pCluster); }
7891
GetKind() const7892 BlockEntry::Kind SimpleBlock::GetKind() const { return kBlockSimple; }
7893
GetBlock() const7894 const Block* SimpleBlock::GetBlock() const { return &m_block; }
7895
BlockGroup(Cluster * pCluster,long idx,long long block_start,long long block_size,long long prev,long long next,long long duration,long long discard_padding)7896 BlockGroup::BlockGroup(Cluster* pCluster, long idx, long long block_start,
7897 long long block_size, long long prev, long long next,
7898 long long duration, long long discard_padding)
7899 : BlockEntry(pCluster, idx),
7900 m_block(block_start, block_size, discard_padding),
7901 m_prev(prev),
7902 m_next(next),
7903 m_duration(duration) {}
7904
Parse()7905 long BlockGroup::Parse() {
7906 const long status = m_block.Parse(m_pCluster);
7907
7908 if (status)
7909 return status;
7910
7911 m_block.SetKey((m_prev > 0) && (m_next <= 0));
7912
7913 return 0;
7914 }
7915
7916 #if 0
7917 void BlockGroup::ParseBlock(long long start, long long size)
7918 {
7919 IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader;
7920
7921 Block* const pBlock = new Block(start, size, pReader);
7922 assert(pBlock); //TODO
7923
7924 //TODO: the Matroska spec says you have multiple blocks within the
7925 //same block group, with blocks ranked by priority (the flag bits).
7926
7927 assert(m_pBlock == NULL);
7928 m_pBlock = pBlock;
7929 }
7930 #endif
7931
GetKind() const7932 BlockEntry::Kind BlockGroup::GetKind() const { return kBlockGroup; }
7933
GetBlock() const7934 const Block* BlockGroup::GetBlock() const { return &m_block; }
7935
GetPrevTimeCode() const7936 long long BlockGroup::GetPrevTimeCode() const { return m_prev; }
7937
GetNextTimeCode() const7938 long long BlockGroup::GetNextTimeCode() const { return m_next; }
7939
GetDurationTimeCode() const7940 long long BlockGroup::GetDurationTimeCode() const { return m_duration; }
7941
Block(long long start,long long size_,long long discard_padding)7942 Block::Block(long long start, long long size_, long long discard_padding)
7943 : m_start(start),
7944 m_size(size_),
7945 m_track(0),
7946 m_timecode(-1),
7947 m_flags(0),
7948 m_frames(NULL),
7949 m_frame_count(-1),
7950 m_discard_padding(discard_padding) {}
7951
~Block()7952 Block::~Block() { delete[] m_frames; }
7953
Parse(const Cluster * pCluster)7954 long Block::Parse(const Cluster* pCluster) {
7955 if (pCluster == NULL)
7956 return -1;
7957
7958 if (pCluster->m_pSegment == NULL)
7959 return -1;
7960
7961 assert(m_start >= 0);
7962 assert(m_size >= 0);
7963 assert(m_track <= 0);
7964 assert(m_frames == NULL);
7965 assert(m_frame_count <= 0);
7966
7967 long long pos = m_start;
7968 const long long stop = m_start + m_size;
7969
7970 long len;
7971
7972 IMkvReader* const pReader = pCluster->m_pSegment->m_pReader;
7973
7974 m_track = ReadUInt(pReader, pos, len);
7975
7976 if (m_track <= 0)
7977 return E_FILE_FORMAT_INVALID;
7978
7979 if ((pos + len) > stop)
7980 return E_FILE_FORMAT_INVALID;
7981
7982 pos += len; // consume track number
7983
7984 if ((stop - pos) < 2)
7985 return E_FILE_FORMAT_INVALID;
7986
7987 long status;
7988 long long value;
7989
7990 status = UnserializeInt(pReader, pos, 2, value);
7991
7992 if (status)
7993 return E_FILE_FORMAT_INVALID;
7994
7995 if (value < SHRT_MIN)
7996 return E_FILE_FORMAT_INVALID;
7997
7998 if (value > SHRT_MAX)
7999 return E_FILE_FORMAT_INVALID;
8000
8001 m_timecode = static_cast<short>(value);
8002
8003 pos += 2;
8004
8005 if ((stop - pos) <= 0)
8006 return E_FILE_FORMAT_INVALID;
8007
8008 status = pReader->Read(pos, 1, &m_flags);
8009
8010 if (status)
8011 return E_FILE_FORMAT_INVALID;
8012
8013 const int lacing = int(m_flags & 0x06) >> 1;
8014
8015 ++pos; // consume flags byte
8016
8017 if (lacing == 0) { // no lacing
8018 if (pos > stop)
8019 return E_FILE_FORMAT_INVALID;
8020
8021 m_frame_count = 1;
8022 m_frames = new Frame[m_frame_count];
8023
8024 Frame& f = m_frames[0];
8025 f.pos = pos;
8026
8027 const long long frame_size = stop - pos;
8028
8029 if (frame_size > LONG_MAX)
8030 return E_FILE_FORMAT_INVALID;
8031
8032 f.len = static_cast<long>(frame_size);
8033
8034 return 0; // success
8035 }
8036
8037 if (pos >= stop)
8038 return E_FILE_FORMAT_INVALID;
8039
8040 unsigned char biased_count;
8041
8042 status = pReader->Read(pos, 1, &biased_count);
8043
8044 if (status)
8045 return E_FILE_FORMAT_INVALID;
8046
8047 ++pos; // consume frame count
8048 assert(pos <= stop);
8049
8050 m_frame_count = int(biased_count) + 1;
8051
8052 m_frames = new Frame[m_frame_count];
8053 assert(m_frames);
8054
8055 if (lacing == 1) { // Xiph
8056 Frame* pf = m_frames;
8057 Frame* const pf_end = pf + m_frame_count;
8058
8059 long size = 0;
8060 int frame_count = m_frame_count;
8061
8062 while (frame_count > 1) {
8063 long frame_size = 0;
8064
8065 for (;;) {
8066 unsigned char val;
8067
8068 if (pos >= stop)
8069 return E_FILE_FORMAT_INVALID;
8070
8071 status = pReader->Read(pos, 1, &val);
8072
8073 if (status)
8074 return E_FILE_FORMAT_INVALID;
8075
8076 ++pos; // consume xiph size byte
8077
8078 frame_size += val;
8079
8080 if (val < 255)
8081 break;
8082 }
8083
8084 Frame& f = *pf++;
8085 assert(pf < pf_end);
8086
8087 f.pos = 0; // patch later
8088
8089 f.len = frame_size;
8090 size += frame_size; // contribution of this frame
8091
8092 --frame_count;
8093 }
8094
8095 assert(pf < pf_end);
8096 assert(pos <= stop);
8097
8098 {
8099 Frame& f = *pf++;
8100
8101 if (pf != pf_end)
8102 return E_FILE_FORMAT_INVALID;
8103
8104 f.pos = 0; // patch later
8105
8106 const long long total_size = stop - pos;
8107
8108 if (total_size < size)
8109 return E_FILE_FORMAT_INVALID;
8110
8111 const long long frame_size = total_size - size;
8112
8113 if (frame_size > LONG_MAX)
8114 return E_FILE_FORMAT_INVALID;
8115
8116 f.len = static_cast<long>(frame_size);
8117 }
8118
8119 pf = m_frames;
8120 while (pf != pf_end) {
8121 Frame& f = *pf++;
8122 assert((pos + f.len) <= stop);
8123
8124 f.pos = pos;
8125 pos += f.len;
8126 }
8127
8128 assert(pos == stop);
8129 } else if (lacing == 2) { // fixed-size lacing
8130 const long long total_size = stop - pos;
8131
8132 if ((total_size % m_frame_count) != 0)
8133 return E_FILE_FORMAT_INVALID;
8134
8135 const long long frame_size = total_size / m_frame_count;
8136
8137 if (frame_size > LONG_MAX)
8138 return E_FILE_FORMAT_INVALID;
8139
8140 Frame* pf = m_frames;
8141 Frame* const pf_end = pf + m_frame_count;
8142
8143 while (pf != pf_end) {
8144 assert((pos + frame_size) <= stop);
8145
8146 Frame& f = *pf++;
8147
8148 f.pos = pos;
8149 f.len = static_cast<long>(frame_size);
8150
8151 pos += frame_size;
8152 }
8153
8154 assert(pos == stop);
8155 } else {
8156 assert(lacing == 3); // EBML lacing
8157
8158 if (pos >= stop)
8159 return E_FILE_FORMAT_INVALID;
8160
8161 long size = 0;
8162 int frame_count = m_frame_count;
8163
8164 long long frame_size = ReadUInt(pReader, pos, len);
8165
8166 if (frame_size < 0)
8167 return E_FILE_FORMAT_INVALID;
8168
8169 if (frame_size > LONG_MAX)
8170 return E_FILE_FORMAT_INVALID;
8171
8172 if ((pos + len) > stop)
8173 return E_FILE_FORMAT_INVALID;
8174
8175 pos += len; // consume length of size of first frame
8176
8177 if ((pos + frame_size) > stop)
8178 return E_FILE_FORMAT_INVALID;
8179
8180 Frame* pf = m_frames;
8181 Frame* const pf_end = pf + m_frame_count;
8182
8183 {
8184 Frame& curr = *pf;
8185
8186 curr.pos = 0; // patch later
8187
8188 curr.len = static_cast<long>(frame_size);
8189 size += curr.len; // contribution of this frame
8190 }
8191
8192 --frame_count;
8193
8194 while (frame_count > 1) {
8195 if (pos >= stop)
8196 return E_FILE_FORMAT_INVALID;
8197
8198 assert(pf < pf_end);
8199
8200 const Frame& prev = *pf++;
8201 assert(prev.len == frame_size);
8202 if (prev.len != frame_size)
8203 return E_FILE_FORMAT_INVALID;
8204
8205 assert(pf < pf_end);
8206
8207 Frame& curr = *pf;
8208
8209 curr.pos = 0; // patch later
8210
8211 const long long delta_size_ = ReadUInt(pReader, pos, len);
8212
8213 if (delta_size_ < 0)
8214 return E_FILE_FORMAT_INVALID;
8215
8216 if ((pos + len) > stop)
8217 return E_FILE_FORMAT_INVALID;
8218
8219 pos += len; // consume length of (delta) size
8220 assert(pos <= stop);
8221
8222 const int exp = 7 * len - 1;
8223 const long long bias = (1LL << exp) - 1LL;
8224 const long long delta_size = delta_size_ - bias;
8225
8226 frame_size += delta_size;
8227
8228 if (frame_size < 0)
8229 return E_FILE_FORMAT_INVALID;
8230
8231 if (frame_size > LONG_MAX)
8232 return E_FILE_FORMAT_INVALID;
8233
8234 curr.len = static_cast<long>(frame_size);
8235 size += curr.len; // contribution of this frame
8236
8237 --frame_count;
8238 }
8239
8240 {
8241 assert(pos <= stop);
8242 assert(pf < pf_end);
8243
8244 const Frame& prev = *pf++;
8245 assert(prev.len == frame_size);
8246 if (prev.len != frame_size)
8247 return E_FILE_FORMAT_INVALID;
8248
8249 assert(pf < pf_end);
8250
8251 Frame& curr = *pf++;
8252 assert(pf == pf_end);
8253
8254 curr.pos = 0; // patch later
8255
8256 const long long total_size = stop - pos;
8257
8258 if (total_size < size)
8259 return E_FILE_FORMAT_INVALID;
8260
8261 frame_size = total_size - size;
8262
8263 if (frame_size > LONG_MAX)
8264 return E_FILE_FORMAT_INVALID;
8265
8266 curr.len = static_cast<long>(frame_size);
8267 }
8268
8269 pf = m_frames;
8270 while (pf != pf_end) {
8271 Frame& f = *pf++;
8272 assert((pos + f.len) <= stop);
8273
8274 f.pos = pos;
8275 pos += f.len;
8276 }
8277
8278 assert(pos == stop);
8279 }
8280
8281 return 0; // success
8282 }
8283
GetTimeCode(const Cluster * pCluster) const8284 long long Block::GetTimeCode(const Cluster* pCluster) const {
8285 if (pCluster == 0)
8286 return m_timecode;
8287
8288 const long long tc0 = pCluster->GetTimeCode();
8289 assert(tc0 >= 0);
8290
8291 const long long tc = tc0 + m_timecode;
8292
8293 return tc; // unscaled timecode units
8294 }
8295
GetTime(const Cluster * pCluster) const8296 long long Block::GetTime(const Cluster* pCluster) const {
8297 assert(pCluster);
8298
8299 const long long tc = GetTimeCode(pCluster);
8300
8301 const Segment* const pSegment = pCluster->m_pSegment;
8302 const SegmentInfo* const pInfo = pSegment->GetInfo();
8303 assert(pInfo);
8304
8305 const long long scale = pInfo->GetTimeCodeScale();
8306 assert(scale >= 1);
8307
8308 const long long ns = tc * scale;
8309
8310 return ns;
8311 }
8312
GetTrackNumber() const8313 long long Block::GetTrackNumber() const { return m_track; }
8314
IsKey() const8315 bool Block::IsKey() const {
8316 return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
8317 }
8318
SetKey(bool bKey)8319 void Block::SetKey(bool bKey) {
8320 if (bKey)
8321 m_flags |= static_cast<unsigned char>(1 << 7);
8322 else
8323 m_flags &= 0x7F;
8324 }
8325
IsInvisible() const8326 bool Block::IsInvisible() const { return bool(int(m_flags & 0x08) != 0); }
8327
GetLacing() const8328 Block::Lacing Block::GetLacing() const {
8329 const int value = int(m_flags & 0x06) >> 1;
8330 return static_cast<Lacing>(value);
8331 }
8332
GetFrameCount() const8333 int Block::GetFrameCount() const { return m_frame_count; }
8334
GetFrame(int idx) const8335 const Block::Frame& Block::GetFrame(int idx) const {
8336 assert(idx >= 0);
8337 assert(idx < m_frame_count);
8338
8339 const Frame& f = m_frames[idx];
8340 assert(f.pos > 0);
8341 assert(f.len > 0);
8342
8343 return f;
8344 }
8345
Read(IMkvReader * pReader,unsigned char * buf) const8346 long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const {
8347 assert(pReader);
8348 assert(buf);
8349
8350 const long status = pReader->Read(pos, len, buf);
8351 return status;
8352 }
8353
GetDiscardPadding() const8354 long long Block::GetDiscardPadding() const { return m_discard_padding; }
8355
8356 } // end namespace mkvparser
8357