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