Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: source/libvpx/third_party/libwebm/mkvparser.cpp

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

Powered by Google App Engine
This is Rietveld 408576698