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