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 //It's probably not correct to search for the cue point with this 2644 //time, and then search for a matching track. In principle, the 2645 //matching track could be on some earlier cue point. So we recheck 2646 //the earlier cue point if the track doesn't match. 2647 long index = pCP->GetIndex(); 2648 while (index >= 0) { 2649 pTP = pCP->Find(pTrack); 2650 if (pTP == NULL) 2651 pCP = m_cue_points[index--]; 2652 else 2653 break; 2654 } 2655 return (pTP != NULL); 2656 } 2657 2658 2659 #if 0 2660 bool Cues::FindNext( 2661 long long time_ns, 2662 const Track* pTrack, 2663 const CuePoint*& pCP, 2664 const CuePoint::TrackPosition*& pTP) const 2665 { 2666 pCP = 0; 2667 pTP = 0; 2668 2669 if (m_count == 0) 2670 return false; 2671 2672 assert(m_cue_points); 2673 2674 const CuePoint* const* const ii = m_cue_points; 2675 const CuePoint* const* i = ii; 2676 2677 const CuePoint* const* const jj = ii + m_count; 2678 const CuePoint* const* j = jj; 2679 2680 while (i < j) 2681 { 2682 //INVARIANT: 2683 //[ii, i) <= time_ns 2684 //[i, j) ? 2685 //[j, jj) > time_ns 2686 2687 const CuePoint* const* const k = i + (j - i) / 2; 2688 assert(k < jj); 2689 2690 pCP = *k; 2691 assert(pCP); 2692 2693 const long long t = pCP->GetTime(m_pSegment); 2694 2695 if (t <= time_ns) 2696 i = k + 1; 2697 else 2698 j = k; 2699 2700 assert(i <= j); 2701 } 2702 2703 assert(i == j); 2704 assert(i <= jj); 2705 2706 if (i >= jj) //time_ns is greater than max cue point 2707 return false; 2708 2709 pCP = *i; 2710 assert(pCP); 2711 assert(pCP->GetTime(m_pSegment) > time_ns); 2712 2713 pTP = pCP->Find(pTrack); 2714 return (pTP != NULL); 2715 } 2716 #endif 2717 2718 2719 const CuePoint* Cues::GetFirst() const 2720 { 2721 if (m_cue_points == NULL) 2722 return NULL; 2723 2724 if (m_count == 0) 2725 return NULL; 2726 2727 #if 0 2728 LoadCuePoint(); //init cues 2729 2730 const size_t count = m_count + m_preload_count; 2731 2732 if (count == 0) //weird 2733 return NULL; 2734 #endif 2735 2736 CuePoint* const* const pp = m_cue_points; 2737 assert(pp); 2738 2739 CuePoint* const pCP = pp[0]; 2740 assert(pCP); 2741 assert(pCP->GetTimeCode() >= 0); 2742 2743 return pCP; 2744 } 2745 2746 2747 const CuePoint* Cues::GetLast() const 2748 { 2749 if (m_cue_points == NULL) 2750 return NULL; 2751 2752 if (m_count <= 0) 2753 return NULL; 2754 2755 #if 0 2756 LoadCuePoint(); //init cues 2757 2758 const size_t count = m_count + m_preload_count; 2759 2760 if (count == 0) //weird 2761 return NULL; 2762 2763 const size_t index = count - 1; 2764 2765 CuePoint* const* const pp = m_cue_points; 2766 assert(pp); 2767 2768 CuePoint* const pCP = pp[index]; 2769 assert(pCP); 2770 2771 pCP->Load(m_pSegment->m_pReader); 2772 assert(pCP->GetTimeCode() >= 0); 2773 #else 2774 const long index = m_count - 1; 2775 2776 CuePoint* const* const pp = m_cue_points; 2777 assert(pp); 2778 2779 CuePoint* const pCP = pp[index]; 2780 assert(pCP); 2781 assert(pCP->GetTimeCode() >= 0); 2782 #endif 2783 2784 return pCP; 2785 } 2786 2787 2788 const CuePoint* Cues::GetNext(const CuePoint* pCurr) const 2789 { 2790 if (pCurr == NULL) 2791 return NULL; 2792 2793 assert(pCurr->GetTimeCode() >= 0); 2794 assert(m_cue_points); 2795 assert(m_count >= 1); 2796 2797 #if 0 2798 const size_t count = m_count + m_preload_count; 2799 2800 size_t index = pCurr->m_index; 2801 assert(index < count); 2802 2803 CuePoint* const* const pp = m_cue_points; 2804 assert(pp); 2805 assert(pp[index] == pCurr); 2806 2807 ++index; 2808 2809 if (index >= count) 2810 return NULL; 2811 2812 CuePoint* const pNext = pp[index]; 2813 assert(pNext); 2814 2815 pNext->Load(m_pSegment->m_pReader); 2816 #else 2817 long index = pCurr->m_index; 2818 assert(index < m_count); 2819 2820 CuePoint* const* const pp = m_cue_points; 2821 assert(pp); 2822 assert(pp[index] == pCurr); 2823 2824 ++index; 2825 2826 if (index >= m_count) 2827 return NULL; 2828 2829 CuePoint* const pNext = pp[index]; 2830 assert(pNext); 2831 assert(pNext->GetTimeCode() >= 0); 2832 #endif 2833 2834 return pNext; 2835 } 2836 2837 2838 const BlockEntry* Cues::GetBlock( 2839 const CuePoint* pCP, 2840 const CuePoint::TrackPosition* pTP) const 2841 { 2842 if (pCP == NULL) 2843 return NULL; 2844 2845 if (pTP == NULL) 2846 return NULL; 2847 2848 return m_pSegment->GetBlock(*pCP, *pTP); 2849 } 2850 2851 2852 const BlockEntry* Segment::GetBlock( 2853 const CuePoint& cp, 2854 const CuePoint::TrackPosition& tp) 2855 { 2856 Cluster** const ii = m_clusters; 2857 Cluster** i = ii; 2858 2859 const long count = m_clusterCount + m_clusterPreloadCount; 2860 2861 Cluster** const jj = ii + count; 2862 Cluster** j = jj; 2863 2864 while (i < j) 2865 { 2866 //INVARIANT: 2867 //[ii, i) < pTP->m_pos 2868 //[i, j) ? 2869 //[j, jj) > pTP->m_pos 2870 2871 Cluster** const k = i + (j - i) / 2; 2872 assert(k < jj); 2873 2874 Cluster* const pCluster = *k; 2875 assert(pCluster); 2876 2877 //const long long pos_ = pCluster->m_pos; 2878 //assert(pos_); 2879 //const long long pos = pos_ * ((pos_ < 0) ? -1 : 1); 2880 2881 const long long pos = pCluster->GetPosition(); 2882 assert(pos >= 0); 2883 2884 if (pos < tp.m_pos) 2885 i = k + 1; 2886 else if (pos > tp.m_pos) 2887 j = k; 2888 else 2889 return pCluster->GetEntry(cp, tp); 2890 } 2891 2892 assert(i == j); 2893 //assert(Cluster::HasBlockEntries(this, tp.m_pos)); 2894 2895 Cluster* const pCluster = Cluster::Create(this, -1, tp.m_pos); //, -1); 2896 assert(pCluster); 2897 2898 const ptrdiff_t idx = i - m_clusters; 2899 2900 PreloadCluster(pCluster, idx); 2901 assert(m_clusters); 2902 assert(m_clusterPreloadCount > 0); 2903 assert(m_clusters[idx] == pCluster); 2904 2905 return pCluster->GetEntry(cp, tp); 2906 } 2907 2908 2909 const Cluster* Segment::FindOrPreloadCluster(long long requested_pos) 2910 { 2911 if (requested_pos < 0) 2912 return 0; 2913 2914 Cluster** const ii = m_clusters; 2915 Cluster** i = ii; 2916 2917 const long count = m_clusterCount + m_clusterPreloadCount; 2918 2919 Cluster** const jj = ii + count; 2920 Cluster** j = jj; 2921 2922 while (i < j) 2923 { 2924 //INVARIANT: 2925 //[ii, i) < pTP->m_pos 2926 //[i, j) ? 2927 //[j, jj) > pTP->m_pos 2928 2929 Cluster** const k = i + (j - i) / 2; 2930 assert(k < jj); 2931 2932 Cluster* const pCluster = *k; 2933 assert(pCluster); 2934 2935 //const long long pos_ = pCluster->m_pos; 2936 //assert(pos_); 2937 //const long long pos = pos_ * ((pos_ < 0) ? -1 : 1); 2938 2939 const long long pos = pCluster->GetPosition(); 2940 assert(pos >= 0); 2941 2942 if (pos < requested_pos) 2943 i = k + 1; 2944 else if (pos > requested_pos) 2945 j = k; 2946 else 2947 return pCluster; 2948 } 2949 2950 assert(i == j); 2951 //assert(Cluster::HasBlockEntries(this, tp.m_pos)); 2952 2953 Cluster* const pCluster = Cluster::Create( 2954 this, 2955 -1, 2956 requested_pos); 2957 //-1); 2958 assert(pCluster); 2959 2960 const ptrdiff_t idx = i - m_clusters; 2961 2962 PreloadCluster(pCluster, idx); 2963 assert(m_clusters); 2964 assert(m_clusterPreloadCount > 0); 2965 assert(m_clusters[idx] == pCluster); 2966 2967 return pCluster; 2968 } 2969 2970 2971 CuePoint::CuePoint(long idx, long long pos) : 2972 m_element_start(0), 2973 m_element_size(0), 2974 m_index(idx), 2975 m_timecode(-1 * pos), 2976 m_track_positions(NULL), 2977 m_track_positions_count(0) 2978 { 2979 assert(pos > 0); 2980 } 2981 2982 2983 CuePoint::~CuePoint() 2984 { 2985 delete[] m_track_positions; 2986 } 2987 2988 2989 void CuePoint::Load(IMkvReader* pReader) 2990 { 2991 //odbgstream os; 2992 //os << "CuePoint::Load(begin): timecode=" << m_timecode << endl; 2993 2994 if (m_timecode >= 0) //already loaded 2995 return; 2996 2997 assert(m_track_positions == NULL); 2998 assert(m_track_positions_count == 0); 2999 3000 long long pos_ = -m_timecode; 3001 const long long element_start = pos_; 3002 3003 long long stop; 3004 3005 { 3006 long len; 3007 3008 const long long id = ReadUInt(pReader, pos_, len); 3009 assert(id == 0x3B); //CuePoint ID 3010 //assert((pos + len) <= stop); 3011 3012 pos_ += len; //consume ID 3013 3014 const long long size = ReadUInt(pReader, pos_, len); 3015 assert(size >= 0); 3016 //assert((pos + len) <= stop); 3017 3018 pos_ += len; //consume Size field 3019 //assert((pos + size) <= stop); 3020 3021 //pos_ now points to start of payload 3022 3023 stop = pos_ + size; 3024 } 3025 3026 const long long element_size = stop - element_start; 3027 3028 long long pos = pos_; 3029 3030 //First count number of track positions 3031 3032 while (pos < stop) 3033 { 3034 long len; 3035 3036 const long long id = ReadUInt(pReader, pos, len); 3037 assert(id >= 0); //TODO 3038 assert((pos + len) <= stop); 3039 3040 pos += len; //consume ID 3041 3042 const long long size = ReadUInt(pReader, pos, len); 3043 assert(size >= 0); 3044 assert((pos + len) <= stop); 3045 3046 pos += len; //consume Size field 3047 assert((pos + size) <= stop); 3048 3049 if (id == 0x33) //CueTime ID 3050 m_timecode = UnserializeUInt(pReader, pos, size); 3051 3052 else if (id == 0x37) //CueTrackPosition(s) ID 3053 ++m_track_positions_count; 3054 3055 pos += size; //consume payload 3056 assert(pos <= stop); 3057 } 3058 3059 assert(m_timecode >= 0); 3060 assert(m_track_positions_count > 0); 3061 3062 //os << "CuePoint::Load(cont'd): idpos=" << idpos 3063 // << " timecode=" << m_timecode 3064 // << endl; 3065 3066 m_track_positions = new TrackPosition[m_track_positions_count]; 3067 3068 //Now parse track positions 3069 3070 TrackPosition* p = m_track_positions; 3071 pos = pos_; 3072 3073 while (pos < stop) 3074 { 3075 long len; 3076 3077 const long long id = ReadUInt(pReader, pos, len); 3078 assert(id >= 0); //TODO 3079 assert((pos + len) <= stop); 3080 3081 pos += len; //consume ID 3082 3083 const long long size = ReadUInt(pReader, pos, len); 3084 assert(size >= 0); 3085 assert((pos + len) <= stop); 3086 3087 pos += len; //consume Size field 3088 assert((pos + size) <= stop); 3089 3090 if (id == 0x37) //CueTrackPosition(s) ID 3091 { 3092 TrackPosition& tp = *p++; 3093 tp.Parse(pReader, pos, size); 3094 } 3095 3096 pos += size; //consume payload 3097 assert(pos <= stop); 3098 } 3099 3100 assert(size_t(p - m_track_positions) == m_track_positions_count); 3101 3102 m_element_start = element_start; 3103 m_element_size = element_size; 3104 } 3105 3106 3107 3108 void CuePoint::TrackPosition::Parse( 3109 IMkvReader* pReader, 3110 long long start_, 3111 long long size_) 3112 { 3113 const long long stop = start_ + size_; 3114 long long pos = start_; 3115 3116 m_track = -1; 3117 m_pos = -1; 3118 m_block = 1; //default 3119 3120 while (pos < stop) 3121 { 3122 long len; 3123 3124 const long long id = ReadUInt(pReader, pos, len); 3125 assert(id >= 0); //TODO 3126 assert((pos + len) <= stop); 3127 3128 pos += len; //consume ID 3129 3130 const long long size = ReadUInt(pReader, pos, len); 3131 assert(size >= 0); 3132 assert((pos + len) <= stop); 3133 3134 pos += len; //consume Size field 3135 assert((pos + size) <= stop); 3136 3137 if (id == 0x77) //CueTrack ID 3138 m_track = UnserializeUInt(pReader, pos, size); 3139 3140 else if (id == 0x71) //CueClusterPos ID 3141 m_pos = UnserializeUInt(pReader, pos, size); 3142 3143 else if (id == 0x1378) //CueBlockNumber 3144 m_block = UnserializeUInt(pReader, pos, size); 3145 3146 pos += size; //consume payload 3147 assert(pos <= stop); 3148 } 3149 3150 assert(m_pos >= 0); 3151 assert(m_track > 0); 3152 //assert(m_block > 0); 3153 } 3154 3155 3156 const CuePoint::TrackPosition* CuePoint::Find(const Track* pTrack) const 3157 { 3158 assert(pTrack); 3159 3160 const long long n = pTrack->GetNumber(); 3161 3162 const TrackPosition* i = m_track_positions; 3163 const TrackPosition* const j = i + m_track_positions_count; 3164 3165 while (i != j) 3166 { 3167 const TrackPosition& p = *i++; 3168 3169 if (p.m_track == n) 3170 return &p; 3171 } 3172 3173 return NULL; //no matching track number found 3174 } 3175 3176 3177 long long CuePoint::GetTimeCode() const 3178 { 3179 return m_timecode; 3180 } 3181 3182 long long CuePoint::GetTime(const Segment* pSegment) const 3183 { 3184 assert(pSegment); 3185 assert(m_timecode >= 0); 3186 3187 const SegmentInfo* const pInfo = pSegment->GetInfo(); 3188 assert(pInfo); 3189 3190 const long long scale = pInfo->GetTimeCodeScale(); 3191 assert(scale >= 1); 3192 3193 const long long time = scale * m_timecode; 3194 3195 return time; 3196 } 3197 3198 long CuePoint::GetIndex() const 3199 { 3200 return m_index; 3201 } 3202 3203 #if 0 3204 long long Segment::Unparsed() const 3205 { 3206 if (m_size < 0) 3207 return LLONG_MAX; 3208 3209 const long long stop = m_start + m_size; 3210 3211 const long long result = stop - m_pos; 3212 assert(result >= 0); 3213 3214 return result; 3215 } 3216 #else 3217 bool Segment::DoneParsing() const 3218 { 3219 if (m_size < 0) 3220 { 3221 long long total, avail; 3222 3223 const int status = m_pReader->Length(&total, &avail); 3224 3225 if (status < 0) //error 3226 return true; //must assume done 3227 3228 if (total < 0) 3229 return false; //assume live stream 3230 3231 return (m_pos >= total); 3232 } 3233 3234 const long long stop = m_start + m_size; 3235 3236 return (m_pos >= stop); 3237 } 3238 #endif 3239 3240 3241 const Cluster* Segment::GetFirst() const 3242 { 3243 if ((m_clusters == NULL) || (m_clusterCount <= 0)) 3244 return &m_eos; 3245 3246 Cluster* const pCluster = m_clusters[0]; 3247 assert(pCluster); 3248 3249 return pCluster; 3250 } 3251 3252 3253 const Cluster* Segment::GetLast() const 3254 { 3255 if ((m_clusters == NULL) || (m_clusterCount <= 0)) 3256 return &m_eos; 3257 3258 const long idx = m_clusterCount - 1; 3259 3260 Cluster* const pCluster = m_clusters[idx]; 3261 assert(pCluster); 3262 3263 return pCluster; 3264 } 3265 3266 3267 unsigned long Segment::GetCount() const 3268 { 3269 return m_clusterCount; 3270 } 3271 3272 3273 const Cluster* Segment::GetNext(const Cluster* pCurr) 3274 { 3275 assert(pCurr); 3276 assert(pCurr != &m_eos); 3277 assert(m_clusters); 3278 3279 long idx = pCurr->m_index; 3280 3281 if (idx >= 0) 3282 { 3283 assert(m_clusterCount > 0); 3284 assert(idx < m_clusterCount); 3285 assert(pCurr == m_clusters[idx]); 3286 3287 ++idx; 3288 3289 if (idx >= m_clusterCount) 3290 return &m_eos; //caller will LoadCluster as desired 3291 3292 Cluster* const pNext = m_clusters[idx]; 3293 assert(pNext); 3294 assert(pNext->m_index >= 0); 3295 assert(pNext->m_index == idx); 3296 3297 return pNext; 3298 } 3299 3300 assert(m_clusterPreloadCount > 0); 3301 3302 //const long long off_ = pCurr->m_pos; 3303 //const long long off = off_ * ((off_ < 0) ? -1 : 1); 3304 //long long pos = m_start + off; 3305 3306 long long pos = pCurr->m_element_start; 3307 3308 assert(m_size >= 0); //TODO 3309 const long long stop = m_start + m_size; //end of segment 3310 3311 { 3312 long len; 3313 3314 long long result = GetUIntLength(m_pReader, pos, len); 3315 assert(result == 0); //TODO 3316 assert((pos + len) <= stop); //TODO 3317 3318 const long long id = ReadUInt(m_pReader, pos, len); 3319 assert(id == 0x0F43B675); //Cluster ID //TODO 3320 3321 pos += len; //consume ID 3322 3323 //Read Size 3324 result = GetUIntLength(m_pReader, pos, len); 3325 assert(result == 0); //TODO 3326 assert((pos + len) <= stop); //TODO 3327 3328 const long long size = ReadUInt(m_pReader, pos, len); 3329 assert(size > 0); //TODO 3330 //assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); 3331 3332 pos += len; //consume length of size of element 3333 assert((pos + size) <= stop); //TODO 3334 3335 //Pos now points to start of payload 3336 3337 pos += size; //consume payload 3338 } 3339 3340 long long off_next = 0; 3341 //long long element_start_next = 0; 3342 long long element_size_next = 0; 3343 3344 while (pos < stop) 3345 { 3346 long len; 3347 3348 long long result = GetUIntLength(m_pReader, pos, len); 3349 assert(result == 0); //TODO 3350 assert((pos + len) <= stop); //TODO 3351 3352 const long long idpos = pos; //pos of next (potential) cluster 3353 3354 const long long id = ReadUInt(m_pReader, idpos, len); 3355 assert(id > 0); //TODO 3356 3357 pos += len; //consume ID 3358 3359 //Read Size 3360 result = GetUIntLength(m_pReader, pos, len); 3361 assert(result == 0); //TODO 3362 assert((pos + len) <= stop); //TODO 3363 3364 const long long size = ReadUInt(m_pReader, pos, len); 3365 assert(size >= 0); //TODO 3366 3367 pos += len; //consume length of size of element 3368 assert((pos + size) <= stop); //TODO 3369 3370 const long long element_size = size + pos - idpos; 3371 3372 //Pos now points to start of payload 3373 3374 if (size == 0) //weird 3375 continue; 3376 3377 if (id == 0x0F43B675) //Cluster ID 3378 { 3379 const long long off_next_ = idpos - m_start; 3380 3381 long long pos_; 3382 long len_; 3383 3384 const long status = Cluster::HasBlockEntries( 3385 this, 3386 off_next_, 3387 pos_, 3388 len_); 3389 3390 assert(status >= 0); 3391 3392 if (status > 0) 3393 { 3394 off_next = off_next_; 3395 //element_start_next = idpos; 3396 element_size_next = element_size; 3397 break; 3398 } 3399 } 3400 3401 pos += size; //consume payload 3402 } 3403 3404 if (off_next <= 0) 3405 return 0; 3406 3407 Cluster** const ii = m_clusters + m_clusterCount; 3408 Cluster** i = ii; 3409 3410 Cluster** const jj = ii + m_clusterPreloadCount; 3411 Cluster** j = jj; 3412 3413 while (i < j) 3414 { 3415 //INVARIANT: 3416 //[0, i) < pos_next 3417 //[i, j) ? 3418 //[j, jj) > pos_next 3419 3420 Cluster** const k = i + (j - i) / 2; 3421 assert(k < jj); 3422 3423 Cluster* const pNext = *k; 3424 assert(pNext); 3425 assert(pNext->m_index < 0); 3426 3427 //const long long pos_ = pNext->m_pos; 3428 //assert(pos_); 3429 //pos = pos_ * ((pos_ < 0) ? -1 : 1); 3430 3431 pos = pNext->GetPosition(); 3432 3433 if (pos < off_next) 3434 i = k + 1; 3435 else if (pos > off_next) 3436 j = k; 3437 else 3438 return pNext; 3439 } 3440 3441 assert(i == j); 3442 3443 Cluster* const pNext = Cluster::Create(this, 3444 -1, 3445 off_next); 3446 //element_size_next); 3447 assert(pNext); 3448 3449 const ptrdiff_t idx_next = i - m_clusters; //insertion position 3450 3451 PreloadCluster(pNext, idx_next); 3452 assert(m_clusters); 3453 assert(idx_next < m_clusterSize); 3454 assert(m_clusters[idx_next] == pNext); 3455 3456 return pNext; 3457 } 3458 3459 3460 long Segment::ParseNext( 3461 const Cluster* pCurr, 3462 const Cluster*& pResult, 3463 long long& pos, 3464 long& len) 3465 { 3466 assert(pCurr); 3467 assert(!pCurr->EOS()); 3468 assert(m_clusters); 3469 3470 pResult = 0; 3471 3472 if (pCurr->m_index >= 0) //loaded (not merely preloaded) 3473 { 3474 assert(m_clusters[pCurr->m_index] == pCurr); 3475 3476 const long next_idx = pCurr->m_index + 1; 3477 3478 if (next_idx < m_clusterCount) 3479 { 3480 pResult = m_clusters[next_idx]; 3481 return 0; //success 3482 } 3483 3484 //curr cluster is last among loaded 3485 3486 const long result = LoadCluster(pos, len); 3487 3488 if (result < 0) //error or underflow 3489 return result; 3490 3491 if (result > 0) //no more clusters 3492 { 3493 //pResult = &m_eos; 3494 return 1; 3495 } 3496 3497 pResult = GetLast(); 3498 return 0; //success 3499 } 3500 3501 assert(m_pos > 0); 3502 3503 long long total, avail; 3504 3505 long status = m_pReader->Length(&total, &avail); 3506 3507 if (status < 0) //error 3508 return status; 3509 3510 assert((total < 0) || (avail <= total)); 3511 3512 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; 3513 3514 //interrogate curr cluster 3515 3516 pos = pCurr->m_element_start; 3517 3518 if (pCurr->m_element_size >= 0) 3519 pos += pCurr->m_element_size; 3520 else 3521 { 3522 if ((pos + 1) > avail) 3523 { 3524 len = 1; 3525 return E_BUFFER_NOT_FULL; 3526 } 3527 3528 long long result = GetUIntLength(m_pReader, pos, len); 3529 3530 if (result < 0) //error 3531 return static_cast<long>(result); 3532 3533 if (result > 0) //weird 3534 return E_BUFFER_NOT_FULL; 3535 3536 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 3537 return E_FILE_FORMAT_INVALID; 3538 3539 if ((pos + len) > avail) 3540 return E_BUFFER_NOT_FULL; 3541 3542 const long long id = ReadUInt(m_pReader, pos, len); 3543 3544 if (id != 0x0F43B675) //weird: not Cluster ID 3545 return -1; 3546 3547 pos += len; //consume ID 3548 3549 //Read Size 3550 3551 if ((pos + 1) > avail) 3552 { 3553 len = 1; 3554 return E_BUFFER_NOT_FULL; 3555 } 3556 3557 result = GetUIntLength(m_pReader, pos, len); 3558 3559 if (result < 0) //error 3560 return static_cast<long>(result); 3561 3562 if (result > 0) //weird 3563 return E_BUFFER_NOT_FULL; 3564 3565 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 3566 return E_FILE_FORMAT_INVALID; 3567 3568 if ((pos + len) > avail) 3569 return E_BUFFER_NOT_FULL; 3570 3571 const long long size = ReadUInt(m_pReader, pos, len); 3572 3573 if (size < 0) //error 3574 return static_cast<long>(size); 3575 3576 pos += len; //consume size field 3577 3578 const long long unknown_size = (1LL << (7 * len)) - 1; 3579 3580 if (size == unknown_size) //TODO: should never happen 3581 return E_FILE_FORMAT_INVALID; //TODO: resolve this 3582 3583 //assert((pCurr->m_size <= 0) || (pCurr->m_size == size)); 3584 3585 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) 3586 return E_FILE_FORMAT_INVALID; 3587 3588 //Pos now points to start of payload 3589 3590 pos += size; //consume payload (that is, the current cluster) 3591 assert((segment_stop < 0) || (pos <= segment_stop)); 3592 3593 //By consuming the payload, we are assuming that the curr 3594 //cluster isn't interesting. That is, we don't bother checking 3595 //whether the payload of the curr cluster is less than what 3596 //happens to be available (obtained via IMkvReader::Length). 3597 //Presumably the caller has already dispensed with the current 3598 //cluster, and really does want the next cluster. 3599 } 3600 3601 //pos now points to just beyond the last fully-loaded cluster 3602 3603 for (;;) 3604 { 3605 const long status = DoParseNext(pResult, pos, len); 3606 3607 if (status <= 1) 3608 return status; 3609 } 3610 } 3611 3612 3613 long Segment::DoParseNext( 3614 const Cluster*& pResult, 3615 long long& pos, 3616 long& len) 3617 { 3618 long long total, avail; 3619 3620 long status = m_pReader->Length(&total, &avail); 3621 3622 if (status < 0) //error 3623 return status; 3624 3625 assert((total < 0) || (avail <= total)); 3626 3627 const long long segment_stop = (m_size < 0) ? -1 : m_start + m_size; 3628 3629 //Parse next cluster. This is strictly a parsing activity. 3630 //Creation of a new cluster object happens later, after the 3631 //parsing is done. 3632 3633 long long off_next = 0; 3634 long long cluster_size = -1; 3635 3636 for (;;) 3637 { 3638 if ((total >= 0) && (pos >= total)) 3639 return 1; //EOF 3640 3641 if ((segment_stop >= 0) && (pos >= segment_stop)) 3642 return 1; //EOF 3643 3644 if ((pos + 1) > avail) 3645 { 3646 len = 1; 3647 return E_BUFFER_NOT_FULL; 3648 } 3649 3650 long long result = GetUIntLength(m_pReader, pos, len); 3651 3652 if (result < 0) //error 3653 return static_cast<long>(result); 3654 3655 if (result > 0) //weird 3656 return E_BUFFER_NOT_FULL; 3657 3658 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 3659 return E_FILE_FORMAT_INVALID; 3660 3661 if ((pos + len) > avail) 3662 return E_BUFFER_NOT_FULL; 3663 3664 const long long idpos = pos; //absolute 3665 const long long idoff = pos - m_start; //relative 3666 3667 const long long id = ReadUInt(m_pReader, idpos, len); //absolute 3668 3669 if (id < 0) //error 3670 return static_cast<long>(id); 3671 3672 if (id == 0) //weird 3673 return -1; //generic error 3674 3675 pos += len; //consume ID 3676 3677 //Read Size 3678 3679 if ((pos + 1) > avail) 3680 { 3681 len = 1; 3682 return E_BUFFER_NOT_FULL; 3683 } 3684 3685 result = GetUIntLength(m_pReader, pos, len); 3686 3687 if (result < 0) //error 3688 return static_cast<long>(result); 3689 3690 if (result > 0) //weird 3691 return E_BUFFER_NOT_FULL; 3692 3693 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 3694 return E_FILE_FORMAT_INVALID; 3695 3696 if ((pos + len) > avail) 3697 return E_BUFFER_NOT_FULL; 3698 3699 const long long size = ReadUInt(m_pReader, pos, len); 3700 3701 if (size < 0) //error 3702 return static_cast<long>(size); 3703 3704 pos += len; //consume length of size of element 3705 3706 //Pos now points to start of payload 3707 3708 if (size == 0) //weird 3709 continue; 3710 3711 const long long unknown_size = (1LL << (7 * len)) - 1; 3712 3713 if ((segment_stop >= 0) && 3714 (size != unknown_size) && 3715 ((pos + size) > segment_stop)) 3716 { 3717 return E_FILE_FORMAT_INVALID; 3718 } 3719 3720 if (id == 0x0C53BB6B) //Cues ID 3721 { 3722 if (size == unknown_size) 3723 return E_FILE_FORMAT_INVALID; 3724 3725 const long long element_stop = pos + size; 3726 3727 if ((segment_stop >= 0) && (element_stop > segment_stop)) 3728 return E_FILE_FORMAT_INVALID; 3729 3730 const long long element_start = idpos; 3731 const long long element_size = element_stop - element_start; 3732 3733 if (m_pCues == NULL) 3734 { 3735 m_pCues = new Cues(this, 3736 pos, 3737 size, 3738 element_start, 3739 element_size); 3740 assert(m_pCues); //TODO 3741 } 3742 3743 pos += size; //consume payload 3744 assert((segment_stop < 0) || (pos <= segment_stop)); 3745 3746 continue; 3747 } 3748 3749 if (id != 0x0F43B675) //not a Cluster ID 3750 { 3751 if (size == unknown_size) 3752 return E_FILE_FORMAT_INVALID; 3753 3754 pos += size; //consume payload 3755 assert((segment_stop < 0) || (pos <= segment_stop)); 3756 3757 continue; 3758 } 3759 3760 #if 0 //this is commented-out to support incremental cluster parsing 3761 len = static_cast<long>(size); 3762 3763 if (element_stop > avail) 3764 return E_BUFFER_NOT_FULL; 3765 #endif 3766 3767 //We have a cluster. 3768 3769 off_next = idoff; 3770 3771 if (size != unknown_size) 3772 cluster_size = size; 3773 3774 break; 3775 } 3776 3777 assert(off_next > 0); //have cluster 3778 3779 //We have parsed the next cluster. 3780 //We have not created a cluster object yet. What we need 3781 //to do now is determine whether it has already be preloaded 3782 //(in which case, an object for this cluster has already been 3783 //created), and if not, create a new cluster object. 3784 3785 Cluster** const ii = m_clusters + m_clusterCount; 3786 Cluster** i = ii; 3787 3788 Cluster** const jj = ii + m_clusterPreloadCount; 3789 Cluster** j = jj; 3790 3791 while (i < j) 3792 { 3793 //INVARIANT: 3794 //[0, i) < pos_next 3795 //[i, j) ? 3796 //[j, jj) > pos_next 3797 3798 Cluster** const k = i + (j - i) / 2; 3799 assert(k < jj); 3800 3801 const Cluster* const pNext = *k; 3802 assert(pNext); 3803 assert(pNext->m_index < 0); 3804 3805 pos = pNext->GetPosition(); 3806 assert(pos >= 0); 3807 3808 if (pos < off_next) 3809 i = k + 1; 3810 else if (pos > off_next) 3811 j = k; 3812 else 3813 { 3814 pResult = pNext; 3815 return 0; //success 3816 } 3817 } 3818 3819 assert(i == j); 3820 3821 long long pos_; 3822 long len_; 3823 3824 status = Cluster::HasBlockEntries(this, off_next, pos_, len_); 3825 3826 if (status < 0) //error or underflow 3827 { 3828 pos = pos_; 3829 len = len_; 3830 3831 return status; 3832 } 3833 3834 if (status > 0) //means "found at least one block entry" 3835 { 3836 Cluster* const pNext = Cluster::Create(this, 3837 -1, //preloaded 3838 off_next); 3839 //element_size); 3840 assert(pNext); 3841 3842 const ptrdiff_t idx_next = i - m_clusters; //insertion position 3843 3844 PreloadCluster(pNext, idx_next); 3845 assert(m_clusters); 3846 assert(idx_next < m_clusterSize); 3847 assert(m_clusters[idx_next] == pNext); 3848 3849 pResult = pNext; 3850 return 0; //success 3851 } 3852 3853 //status == 0 means "no block entries found" 3854 3855 if (cluster_size < 0) //unknown size 3856 { 3857 const long long payload_pos = pos; //absolute pos of cluster payload 3858 3859 for (;;) //determine cluster size 3860 { 3861 if ((total >= 0) && (pos >= total)) 3862 break; 3863 3864 if ((segment_stop >= 0) && (pos >= segment_stop)) 3865 break; //no more clusters 3866 3867 //Read ID 3868 3869 if ((pos + 1) > avail) 3870 { 3871 len = 1; 3872 return E_BUFFER_NOT_FULL; 3873 } 3874 3875 long long result = GetUIntLength(m_pReader, pos, len); 3876 3877 if (result < 0) //error 3878 return static_cast<long>(result); 3879 3880 if (result > 0) //weird 3881 return E_BUFFER_NOT_FULL; 3882 3883 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 3884 return E_FILE_FORMAT_INVALID; 3885 3886 if ((pos + len) > avail) 3887 return E_BUFFER_NOT_FULL; 3888 3889 const long long idpos = pos; 3890 const long long id = ReadUInt(m_pReader, idpos, len); 3891 3892 if (id < 0) //error (or underflow) 3893 return static_cast<long>(id); 3894 3895 //This is the distinguished set of ID's we use to determine 3896 //that we have exhausted the sub-element's inside the cluster 3897 //whose ID we parsed earlier. 3898 3899 if (id == 0x0F43B675) //Cluster ID 3900 break; 3901 3902 if (id == 0x0C53BB6B) //Cues ID 3903 break; 3904 3905 pos += len; //consume ID (of sub-element) 3906 3907 //Read Size 3908 3909 if ((pos + 1) > avail) 3910 { 3911 len = 1; 3912 return E_BUFFER_NOT_FULL; 3913 } 3914 3915 result = GetUIntLength(m_pReader, pos, len); 3916 3917 if (result < 0) //error 3918 return static_cast<long>(result); 3919 3920 if (result > 0) //weird 3921 return E_BUFFER_NOT_FULL; 3922 3923 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 3924 return E_FILE_FORMAT_INVALID; 3925 3926 if ((pos + len) > avail) 3927 return E_BUFFER_NOT_FULL; 3928 3929 const long long size = ReadUInt(m_pReader, pos, len); 3930 3931 if (size < 0) //error 3932 return static_cast<long>(size); 3933 3934 pos += len; //consume size field of element 3935 3936 //pos now points to start of sub-element's payload 3937 3938 if (size == 0) //weird 3939 continue; 3940 3941 const long long unknown_size = (1LL << (7 * len)) - 1; 3942 3943 if (size == unknown_size) 3944 return E_FILE_FORMAT_INVALID; //not allowed for sub-elements 3945 3946 if ((segment_stop >= 0) && ((pos + size) > segment_stop)) //weird 3947 return E_FILE_FORMAT_INVALID; 3948 3949 pos += size; //consume payload of sub-element 3950 assert((segment_stop < 0) || (pos <= segment_stop)); 3951 } //determine cluster size 3952 3953 cluster_size = pos - payload_pos; 3954 assert(cluster_size >= 0); //TODO: handle cluster_size = 0 3955 3956 pos = payload_pos; //reset and re-parse original cluster 3957 } 3958 3959 pos += cluster_size; //consume payload 3960 assert((segment_stop < 0) || (pos <= segment_stop)); 3961 3962 return 2; //try to find a cluster that follows next 3963 } 3964 3965 3966 const Cluster* Segment::FindCluster(long long time_ns) const 3967 { 3968 if ((m_clusters == NULL) || (m_clusterCount <= 0)) 3969 return &m_eos; 3970 3971 { 3972 Cluster* const pCluster = m_clusters[0]; 3973 assert(pCluster); 3974 assert(pCluster->m_index == 0); 3975 3976 if (time_ns <= pCluster->GetTime()) 3977 return pCluster; 3978 } 3979 3980 //Binary search of cluster array 3981 3982 long i = 0; 3983 long j = m_clusterCount; 3984 3985 while (i < j) 3986 { 3987 //INVARIANT: 3988 //[0, i) <= time_ns 3989 //[i, j) ? 3990 //[j, m_clusterCount) > time_ns 3991 3992 const long k = i + (j - i) / 2; 3993 assert(k < m_clusterCount); 3994 3995 Cluster* const pCluster = m_clusters[k]; 3996 assert(pCluster); 3997 assert(pCluster->m_index == k); 3998 3999 const long long t = pCluster->GetTime(); 4000 4001 if (t <= time_ns) 4002 i = k + 1; 4003 else 4004 j = k; 4005 4006 assert(i <= j); 4007 } 4008 4009 assert(i == j); 4010 assert(i > 0); 4011 assert(i <= m_clusterCount); 4012 4013 const long k = i - 1; 4014 4015 Cluster* const pCluster = m_clusters[k]; 4016 assert(pCluster); 4017 assert(pCluster->m_index == k); 4018 assert(pCluster->GetTime() <= time_ns); 4019 4020 return pCluster; 4021 } 4022 4023 4024 #if 0 4025 const BlockEntry* Segment::Seek( 4026 long long time_ns, 4027 const Track* pTrack) const 4028 { 4029 assert(pTrack); 4030 4031 if ((m_clusters == NULL) || (m_clusterCount <= 0)) 4032 return pTrack->GetEOS(); 4033 4034 Cluster** const i = m_clusters; 4035 assert(i); 4036 4037 { 4038 Cluster* const pCluster = *i; 4039 assert(pCluster); 4040 assert(pCluster->m_index == 0); //m_clusterCount > 0 4041 assert(pCluster->m_pSegment == this); 4042 4043 if (time_ns <= pCluster->GetTime()) 4044 return pCluster->GetEntry(pTrack); 4045 } 4046 4047 Cluster** const j = i + m_clusterCount; 4048 4049 if (pTrack->GetType() == 2) //audio 4050 { 4051 //TODO: we could decide to use cues for this, as we do for video. 4052 //But we only use it for video because looking around for a keyframe 4053 //can get expensive. Audio doesn't require anything special so a 4054 //straight cluster search is good enough (we assume). 4055 4056 Cluster** lo = i; 4057 Cluster** hi = j; 4058 4059 while (lo < hi) 4060 { 4061 //INVARIANT: 4062 //[i, lo) <= time_ns 4063 //[lo, hi) ? 4064 //[hi, j) > time_ns 4065 4066 Cluster** const mid = lo + (hi - lo) / 2; 4067 assert(mid < hi); 4068 4069 Cluster* const pCluster = *mid; 4070 assert(pCluster); 4071 assert(pCluster->m_index == long(mid - m_clusters)); 4072 assert(pCluster->m_pSegment == this); 4073 4074 const long long t = pCluster->GetTime(); 4075 4076 if (t <= time_ns) 4077 lo = mid + 1; 4078 else 4079 hi = mid; 4080 4081 assert(lo <= hi); 4082 } 4083 4084 assert(lo == hi); 4085 assert(lo > i); 4086 assert(lo <= j); 4087 4088 while (lo > i) 4089 { 4090 Cluster* const pCluster = *--lo; 4091 assert(pCluster); 4092 assert(pCluster->GetTime() <= time_ns); 4093 4094 const BlockEntry* const pBE = pCluster->GetEntry(pTrack); 4095 4096 if ((pBE != 0) && !pBE->EOS()) 4097 return pBE; 4098 4099 //landed on empty cluster (no entries) 4100 } 4101 4102 return pTrack->GetEOS(); //weird 4103 } 4104 4105 assert(pTrack->GetType() == 1); //video 4106 4107 Cluster** lo = i; 4108 Cluster** hi = j; 4109 4110 while (lo < hi) 4111 { 4112 //INVARIANT: 4113 //[i, lo) <= time_ns 4114 //[lo, hi) ? 4115 //[hi, j) > time_ns 4116 4117 Cluster** const mid = lo + (hi - lo) / 2; 4118 assert(mid < hi); 4119 4120 Cluster* const pCluster = *mid; 4121 assert(pCluster); 4122 4123 const long long t = pCluster->GetTime(); 4124 4125 if (t <= time_ns) 4126 lo = mid + 1; 4127 else 4128 hi = mid; 4129 4130 assert(lo <= hi); 4131 } 4132 4133 assert(lo == hi); 4134 assert(lo > i); 4135 assert(lo <= j); 4136 4137 Cluster* pCluster = *--lo; 4138 assert(pCluster); 4139 assert(pCluster->GetTime() <= time_ns); 4140 4141 { 4142 const BlockEntry* const pBE = pCluster->GetEntry(pTrack, time_ns); 4143 4144 if ((pBE != 0) && !pBE->EOS()) //found a keyframe 4145 return pBE; 4146 } 4147 4148 const VideoTrack* const pVideo = static_cast<const VideoTrack*>(pTrack); 4149 4150 while (lo != i) 4151 { 4152 pCluster = *--lo; 4153 assert(pCluster); 4154 assert(pCluster->GetTime() <= time_ns); 4155 4156 const BlockEntry* const pBlockEntry = pCluster->GetMaxKey(pVideo); 4157 4158 if ((pBlockEntry != 0) && !pBlockEntry->EOS()) 4159 return pBlockEntry; 4160 } 4161 4162 //weird: we're on the first cluster, but no keyframe found 4163 //should never happen but we must return something anyway 4164 4165 return pTrack->GetEOS(); 4166 } 4167 #endif 4168 4169 4170 #if 0 4171 bool Segment::SearchCues( 4172 long long time_ns, 4173 Track* pTrack, 4174 Cluster*& pCluster, 4175 const BlockEntry*& pBlockEntry, 4176 const CuePoint*& pCP, 4177 const CuePoint::TrackPosition*& pTP) 4178 { 4179 if (pTrack->GetType() != 1) //not video 4180 return false; //TODO: for now, just handle video stream 4181 4182 if (m_pCues == NULL) 4183 return false; 4184 4185 if (!m_pCues->Find(time_ns, pTrack, pCP, pTP)) 4186 return false; //weird 4187 4188 assert(pCP); 4189 assert(pTP); 4190 assert(pTP->m_track == pTrack->GetNumber()); 4191 4192 //We have the cue point and track position we want, 4193 //so we now need to search for the cluster having 4194 //the indicated position. 4195 4196 return GetCluster(pCP, pTP, pCluster, pBlockEntry); 4197 } 4198 #endif 4199 4200 4201 const Tracks* Segment::GetTracks() const 4202 { 4203 return m_pTracks; 4204 } 4205 4206 4207 const SegmentInfo* Segment::GetInfo() const 4208 { 4209 return m_pInfo; 4210 } 4211 4212 4213 const Cues* Segment::GetCues() const 4214 { 4215 return m_pCues; 4216 } 4217 4218 4219 const SeekHead* Segment::GetSeekHead() const 4220 { 4221 return m_pSeekHead; 4222 } 4223 4224 4225 long long Segment::GetDuration() const 4226 { 4227 assert(m_pInfo); 4228 return m_pInfo->GetDuration(); 4229 } 4230 4231 4232 SegmentInfo::SegmentInfo( 4233 Segment* pSegment, 4234 long long start, 4235 long long size_, 4236 long long element_start, 4237 long long element_size) : 4238 m_pSegment(pSegment), 4239 m_start(start), 4240 m_size(size_), 4241 m_element_start(element_start), 4242 m_element_size(element_size), 4243 m_pMuxingAppAsUTF8(NULL), 4244 m_pWritingAppAsUTF8(NULL), 4245 m_pTitleAsUTF8(NULL) 4246 { 4247 } 4248 4249 SegmentInfo::~SegmentInfo() 4250 { 4251 delete[] m_pMuxingAppAsUTF8; 4252 m_pMuxingAppAsUTF8 = NULL; 4253 4254 delete[] m_pWritingAppAsUTF8; 4255 m_pWritingAppAsUTF8 = NULL; 4256 4257 delete[] m_pTitleAsUTF8; 4258 m_pTitleAsUTF8 = NULL; 4259 } 4260 4261 4262 long SegmentInfo::Parse() 4263 { 4264 assert(m_pMuxingAppAsUTF8 == NULL); 4265 assert(m_pWritingAppAsUTF8 == NULL); 4266 assert(m_pTitleAsUTF8 == NULL); 4267 4268 IMkvReader* const pReader = m_pSegment->m_pReader; 4269 4270 long long pos = m_start; 4271 const long long stop = m_start + m_size; 4272 4273 m_timecodeScale = 1000000; 4274 m_duration = -1; 4275 4276 while (pos < stop) 4277 { 4278 long long id, size; 4279 4280 const long status = ParseElementHeader( 4281 pReader, 4282 pos, 4283 stop, 4284 id, 4285 size); 4286 4287 if (status < 0) //error 4288 return status; 4289 4290 if (id == 0x0AD7B1) //Timecode Scale 4291 { 4292 m_timecodeScale = UnserializeUInt(pReader, pos, size); 4293 4294 if (m_timecodeScale <= 0) 4295 return E_FILE_FORMAT_INVALID; 4296 } 4297 else if (id == 0x0489) //Segment duration 4298 { 4299 const long status = UnserializeFloat( 4300 pReader, 4301 pos, 4302 size, 4303 m_duration); 4304 4305 if (status < 0) 4306 return status; 4307 4308 if (m_duration < 0) 4309 return E_FILE_FORMAT_INVALID; 4310 } 4311 else if (id == 0x0D80) //MuxingApp 4312 { 4313 const long status = UnserializeString( 4314 pReader, 4315 pos, 4316 size, 4317 m_pMuxingAppAsUTF8); 4318 4319 if (status) 4320 return status; 4321 } 4322 else if (id == 0x1741) //WritingApp 4323 { 4324 const long status = UnserializeString( 4325 pReader, 4326 pos, 4327 size, 4328 m_pWritingAppAsUTF8); 4329 4330 if (status) 4331 return status; 4332 } 4333 else if (id == 0x3BA9) //Title 4334 { 4335 const long status = UnserializeString( 4336 pReader, 4337 pos, 4338 size, 4339 m_pTitleAsUTF8); 4340 4341 if (status) 4342 return status; 4343 } 4344 4345 pos += size; 4346 assert(pos <= stop); 4347 } 4348 4349 assert(pos == stop); 4350 4351 return 0; 4352 } 4353 4354 4355 long long SegmentInfo::GetTimeCodeScale() const 4356 { 4357 return m_timecodeScale; 4358 } 4359 4360 4361 long long SegmentInfo::GetDuration() const 4362 { 4363 if (m_duration < 0) 4364 return -1; 4365 4366 assert(m_timecodeScale >= 1); 4367 4368 const double dd = double(m_duration) * double(m_timecodeScale); 4369 const long long d = static_cast<long long>(dd); 4370 4371 return d; 4372 } 4373 4374 const char* SegmentInfo::GetMuxingAppAsUTF8() const 4375 { 4376 return m_pMuxingAppAsUTF8; 4377 } 4378 4379 4380 const char* SegmentInfo::GetWritingAppAsUTF8() const 4381 { 4382 return m_pWritingAppAsUTF8; 4383 } 4384 4385 const char* SegmentInfo::GetTitleAsUTF8() const 4386 { 4387 return m_pTitleAsUTF8; 4388 } 4389 4390 /////////////////////////////////////////////////////////////// 4391 // ContentEncoding element 4392 ContentEncoding::ContentCompression::ContentCompression() 4393 : algo(0), 4394 settings(NULL) { 4395 } 4396 4397 ContentEncoding::ContentCompression::~ContentCompression() { 4398 delete [] settings; 4399 } 4400 4401 ContentEncoding::ContentEncryption::ContentEncryption() 4402 : algo(0), 4403 key_id(NULL), 4404 key_id_len(0), 4405 signature(NULL), 4406 signature_len(0), 4407 sig_key_id(NULL), 4408 sig_key_id_len(0), 4409 sig_algo(0), 4410 sig_hash_algo(0) { 4411 } 4412 4413 ContentEncoding::ContentEncryption::~ContentEncryption() { 4414 delete [] key_id; 4415 delete [] signature; 4416 delete [] sig_key_id; 4417 } 4418 4419 ContentEncoding::ContentEncoding() 4420 : compression_entries_(NULL), 4421 compression_entries_end_(NULL), 4422 encryption_entries_(NULL), 4423 encryption_entries_end_(NULL), 4424 encoding_order_(0), 4425 encoding_scope_(1), 4426 encoding_type_(0) { 4427 } 4428 4429 ContentEncoding::~ContentEncoding() { 4430 ContentCompression** comp_i = compression_entries_; 4431 ContentCompression** const comp_j = compression_entries_end_; 4432 4433 while (comp_i != comp_j) { 4434 ContentCompression* const comp = *comp_i++; 4435 delete comp; 4436 } 4437 4438 delete [] compression_entries_; 4439 4440 ContentEncryption** enc_i = encryption_entries_; 4441 ContentEncryption** const enc_j = encryption_entries_end_; 4442 4443 while (enc_i != enc_j) { 4444 ContentEncryption* const enc = *enc_i++; 4445 delete enc; 4446 } 4447 4448 delete [] encryption_entries_; 4449 } 4450 4451 4452 const ContentEncoding::ContentCompression* 4453 ContentEncoding::GetCompressionByIndex(unsigned long idx) const { 4454 const ptrdiff_t count = compression_entries_end_ - compression_entries_; 4455 assert(count >= 0); 4456 4457 if (idx >= static_cast<unsigned long>(count)) 4458 return NULL; 4459 4460 return compression_entries_[idx]; 4461 } 4462 4463 unsigned long ContentEncoding::GetCompressionCount() const { 4464 const ptrdiff_t count = compression_entries_end_ - compression_entries_; 4465 assert(count >= 0); 4466 4467 return static_cast<unsigned long>(count); 4468 } 4469 4470 const ContentEncoding::ContentEncryption* 4471 ContentEncoding::GetEncryptionByIndex(unsigned long idx) const { 4472 const ptrdiff_t count = encryption_entries_end_ - encryption_entries_; 4473 assert(count >= 0); 4474 4475 if (idx >= static_cast<unsigned long>(count)) 4476 return NULL; 4477 4478 return encryption_entries_[idx]; 4479 } 4480 4481 unsigned long ContentEncoding::GetEncryptionCount() const { 4482 const ptrdiff_t count = encryption_entries_end_ - encryption_entries_; 4483 assert(count >= 0); 4484 4485 return static_cast<unsigned long>(count); 4486 } 4487 4488 void ContentEncoding::ParseEncryptionEntry( 4489 long long start, 4490 long long size, 4491 IMkvReader* const pReader, 4492 ContentEncryption* const encryption) { 4493 assert(pReader); 4494 assert(encryption); 4495 4496 long long pos = start; 4497 const long long stop = start + size; 4498 4499 while (pos < stop) { 4500 #ifdef _DEBUG 4501 long len; 4502 const long long id = ReadUInt(pReader, pos, len); 4503 assert(id >= 0); //TODO: handle error case 4504 assert((pos + len) <= stop); 4505 #endif 4506 4507 long long value; 4508 unsigned char* buf; 4509 size_t buf_len; 4510 4511 if (Match(pReader, pos, 0x7E1, value)) { 4512 // ContentEncAlgo 4513 encryption->algo = value; 4514 } else if (Match(pReader, pos, 0x7E2, buf, buf_len)) { 4515 // ContentEncKeyID 4516 encryption->key_id = buf; 4517 encryption->key_id_len = buf_len; 4518 } else if (Match(pReader, pos, 0x7E3, buf, buf_len)) { 4519 // ContentSignature 4520 encryption->signature = buf; 4521 encryption->signature_len = buf_len; 4522 } else if (Match(pReader, pos, 0x7E4, buf, buf_len)) { 4523 // ContentSigKeyID 4524 encryption->sig_key_id = buf; 4525 encryption->sig_key_id_len = buf_len; 4526 } else if (Match(pReader, pos, 0x7E5, value)) { 4527 // ContentSigAlgo 4528 encoding_type_ = value; 4529 } else if (Match(pReader, pos, 0x7E6, value)) { 4530 // ContentSigHashAlgo 4531 encoding_type_ = value; 4532 } else { 4533 long len; 4534 const long long id = ReadUInt(pReader, pos, len); 4535 assert(id >= 0); //TODO: handle error case 4536 assert((pos + len) <= stop); 4537 4538 pos += len; //consume id 4539 4540 const long long size = ReadUInt(pReader, pos, len); 4541 assert(size >= 0); //TODO: handle error case 4542 assert((pos + len) <= stop); 4543 4544 pos += len; //consume length of size 4545 assert((pos + size) <= stop); 4546 4547 pos += size; //consume payload 4548 assert(pos <= stop); 4549 } 4550 } 4551 } 4552 4553 bool ContentEncoding::ParseContentEncodingEntry(long long start, 4554 long long size, 4555 IMkvReader* const pReader) { 4556 assert(pReader); 4557 4558 long long pos = start; 4559 const long long stop = start + size; 4560 4561 // Count ContentCompression and ContentEncryption elements. 4562 long long pos1 = start; 4563 int compression_count = 0; 4564 int encryption_count = 0; 4565 4566 while (pos1 < stop) { 4567 long len; 4568 const long long id = ReadUInt(pReader, pos1, len); 4569 assert(id >= 0); 4570 assert((pos1 + len) <= stop); 4571 4572 pos1 += len; //consume id 4573 4574 const long long size = ReadUInt(pReader, pos1, len); 4575 assert(size >= 0); 4576 assert((pos1 + len) <= stop); 4577 4578 pos1 += len; //consume length of size 4579 4580 //pos now designates start of element 4581 if (id == 0x1034) // ContentCompression ID 4582 ++compression_count; 4583 4584 if (id == 0x1035) // ContentEncryption ID 4585 ++encryption_count; 4586 4587 pos1 += size; //consume payload 4588 assert(pos1 <= stop); 4589 } 4590 4591 if (compression_count <= 0 && encryption_count <= 0) 4592 return false; 4593 4594 if (compression_count > 0) { 4595 compression_entries_ = new ContentCompression*[compression_count]; 4596 compression_entries_end_ = compression_entries_; 4597 } 4598 4599 if (encryption_count > 0) { 4600 encryption_entries_ = new ContentEncryption*[encryption_count]; 4601 encryption_entries_end_ = encryption_entries_; 4602 } 4603 4604 while (pos < stop) { 4605 #ifdef _DEBUG 4606 long len; 4607 const long long id = ReadUInt(pReader, pos, len); 4608 assert(id >= 0); //TODO: handle error case 4609 assert((pos + len) <= stop); 4610 #endif 4611 4612 long long value; 4613 if (Match(pReader, pos, 0x1031, value)) { 4614 // ContentEncodingOrder 4615 encoding_order_ = value; 4616 } else if (Match(pReader, pos, 0x1032, value)) { 4617 // ContentEncodingScope 4618 encoding_scope_ = value; 4619 assert(encoding_scope_ > 0); 4620 } else if (Match(pReader, pos, 0x1033, value)) { 4621 // ContentEncodingType 4622 encoding_type_ = value; 4623 } else { 4624 long len; 4625 const long long id = ReadUInt(pReader, pos, len); 4626 assert(id >= 0); //TODO: handle error case 4627 assert((pos + len) <= stop); 4628 4629 pos += len; //consume id 4630 4631 const long long size = ReadUInt(pReader, pos, len); 4632 assert(size >= 0); //TODO: handle error case 4633 assert((pos + len) <= stop); 4634 4635 pos += len; //consume length of size 4636 assert((pos + size) <= stop); 4637 4638 //pos now designates start of payload 4639 4640 if (id == 0x1034) { 4641 // ContentCompression ID 4642 // TODO(fgaligan): Add code to parse ContentCompression elements. 4643 } else if (id == 0x1035) { 4644 // ContentEncryption ID 4645 ContentEncryption* const encryption = new ContentEncryption(); 4646 4647 ParseEncryptionEntry(pos, size, pReader, encryption); 4648 *encryption_entries_end_ = encryption; 4649 ++encryption_entries_end_; 4650 } 4651 4652 pos += size; //consume payload 4653 assert(pos <= stop); 4654 } 4655 } 4656 4657 assert(pos == stop); 4658 4659 return true; 4660 } 4661 4662 Track::Track( 4663 Segment* pSegment, 4664 long long element_start, 4665 long long element_size) : 4666 m_pSegment(pSegment), 4667 m_element_start(element_start), 4668 m_element_size(element_size), 4669 content_encoding_entries_(NULL), 4670 content_encoding_entries_end_(NULL) 4671 { 4672 } 4673 4674 Track::~Track() 4675 { 4676 Info& info = const_cast<Info&>(m_info); 4677 info.Clear(); 4678 4679 ContentEncoding** i = content_encoding_entries_; 4680 ContentEncoding** const j = content_encoding_entries_end_; 4681 4682 while (i != j) { 4683 ContentEncoding* const encoding = *i++; 4684 delete encoding; 4685 } 4686 4687 delete [] content_encoding_entries_; 4688 } 4689 4690 Track::Info::Info(): 4691 nameAsUTF8(NULL), 4692 codecId(NULL), 4693 codecNameAsUTF8(NULL), 4694 codecPrivate(NULL), 4695 codecPrivateSize(0) 4696 { 4697 } 4698 4699 Track::Info::~Info() 4700 { 4701 Clear(); 4702 } 4703 4704 void Track::Info::Clear() 4705 { 4706 delete[] nameAsUTF8; 4707 nameAsUTF8 = NULL; 4708 4709 delete[] codecId; 4710 codecId = NULL; 4711 4712 delete[] codecPrivate; 4713 codecPrivate = NULL; 4714 codecPrivateSize = 0; 4715 4716 delete[] codecNameAsUTF8; 4717 codecNameAsUTF8 = NULL; 4718 } 4719 4720 int Track::Info::CopyStr(char* Info::*str, Info& dst_) const 4721 { 4722 if (str == static_cast<char* Info::*>(NULL)) 4723 return -1; 4724 4725 char*& dst = dst_.*str; 4726 4727 if (dst) //should be NULL already 4728 return -1; 4729 4730 const char* const src = this->*str; 4731 4732 if (src == NULL) 4733 return 0; 4734 4735 const size_t len = strlen(src); 4736 4737 dst = new (std::nothrow) char[len+1]; 4738 4739 if (dst == NULL) 4740 return -1; 4741 4742 strcpy(dst, src); 4743 4744 return 0; 4745 } 4746 4747 4748 int Track::Info::Copy(Info& dst) const 4749 { 4750 if (&dst == this) 4751 return 0; 4752 4753 dst.type = type; 4754 dst.number = number; 4755 dst.uid = uid; 4756 dst.lacing = lacing; 4757 dst.settings = settings; 4758 4759 //We now copy the string member variables from src to dst. 4760 //This involves memory allocation so in principle the operation 4761 //can fail (indeed, that's why we have Info::Copy), so we must 4762 //report this to the caller. An error return from this function 4763 //therefore implies that the copy was only partially successful. 4764 4765 if (int status = CopyStr(&Info::nameAsUTF8, dst)) 4766 return status; 4767 4768 if (int status = CopyStr(&Info::codecId, dst)) 4769 return status; 4770 4771 if (int status = CopyStr(&Info::codecNameAsUTF8, dst)) 4772 return status; 4773 4774 if (codecPrivateSize > 0) 4775 { 4776 if (codecPrivate == NULL) 4777 return -1; 4778 4779 if (dst.codecPrivate) 4780 return -1; 4781 4782 if (dst.codecPrivateSize != 0) 4783 return -1; 4784 4785 dst.codecPrivate = new (std::nothrow) unsigned char[codecPrivateSize]; 4786 4787 if (dst.codecPrivate == NULL) 4788 return -1; 4789 4790 memcpy(dst.codecPrivate, codecPrivate, codecPrivateSize); 4791 dst.codecPrivateSize = codecPrivateSize; 4792 } 4793 4794 return 0; 4795 } 4796 4797 const BlockEntry* Track::GetEOS() const 4798 { 4799 return &m_eos; 4800 } 4801 4802 long Track::GetType() const 4803 { 4804 return m_info.type; 4805 } 4806 4807 long Track::GetNumber() const 4808 { 4809 return m_info.number; 4810 } 4811 4812 unsigned long long Track::GetUid() const 4813 { 4814 return m_info.uid; 4815 } 4816 4817 const char* Track::GetNameAsUTF8() const 4818 { 4819 return m_info.nameAsUTF8; 4820 } 4821 4822 const char* Track::GetCodecNameAsUTF8() const 4823 { 4824 return m_info.codecNameAsUTF8; 4825 } 4826 4827 4828 const char* Track::GetCodecId() const 4829 { 4830 return m_info.codecId; 4831 } 4832 4833 const unsigned char* Track::GetCodecPrivate(size_t& size) const 4834 { 4835 size = m_info.codecPrivateSize; 4836 return m_info.codecPrivate; 4837 } 4838 4839 4840 bool Track::GetLacing() const 4841 { 4842 return m_info.lacing; 4843 } 4844 4845 4846 long Track::GetFirst(const BlockEntry*& pBlockEntry) const 4847 { 4848 const Cluster* pCluster = m_pSegment->GetFirst(); 4849 4850 for (int i = 0; ; ) 4851 { 4852 if (pCluster == NULL) 4853 { 4854 pBlockEntry = GetEOS(); 4855 return 1; 4856 } 4857 4858 if (pCluster->EOS()) 4859 { 4860 #if 0 4861 if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded 4862 { 4863 pBlockEntry = GetEOS(); 4864 return 1; 4865 } 4866 #else 4867 if (m_pSegment->DoneParsing()) 4868 { 4869 pBlockEntry = GetEOS(); 4870 return 1; 4871 } 4872 #endif 4873 4874 pBlockEntry = 0; 4875 return E_BUFFER_NOT_FULL; 4876 } 4877 4878 long status = pCluster->GetFirst(pBlockEntry); 4879 4880 if (status < 0) //error 4881 return status; 4882 4883 if (pBlockEntry == 0) //empty cluster 4884 { 4885 pCluster = m_pSegment->GetNext(pCluster); 4886 continue; 4887 } 4888 4889 for (;;) 4890 { 4891 const Block* const pBlock = pBlockEntry->GetBlock(); 4892 assert(pBlock); 4893 4894 const long long tn = pBlock->GetTrackNumber(); 4895 4896 if ((tn == m_info.number) && VetEntry(pBlockEntry)) 4897 return 0; 4898 4899 const BlockEntry* pNextEntry; 4900 4901 status = pCluster->GetNext(pBlockEntry, pNextEntry); 4902 4903 if (status < 0) //error 4904 return status; 4905 4906 if (pNextEntry == 0) 4907 break; 4908 4909 pBlockEntry = pNextEntry; 4910 } 4911 4912 ++i; 4913 4914 if (i >= 100) 4915 break; 4916 4917 pCluster = m_pSegment->GetNext(pCluster); 4918 } 4919 4920 //NOTE: if we get here, it means that we didn't find a block with 4921 //a matching track number. We interpret that as an error (which 4922 //might be too conservative). 4923 4924 pBlockEntry = GetEOS(); //so we can return a non-NULL value 4925 return 1; 4926 } 4927 4928 4929 long Track::GetNext( 4930 const BlockEntry* pCurrEntry, 4931 const BlockEntry*& pNextEntry) const 4932 { 4933 assert(pCurrEntry); 4934 assert(!pCurrEntry->EOS()); //? 4935 4936 const Block* const pCurrBlock = pCurrEntry->GetBlock(); 4937 assert(pCurrBlock->GetTrackNumber() == m_info.number); 4938 4939 const Cluster* pCluster = pCurrEntry->GetCluster(); 4940 assert(pCluster); 4941 assert(!pCluster->EOS()); 4942 4943 long status = pCluster->GetNext(pCurrEntry, pNextEntry); 4944 4945 if (status < 0) //error 4946 return status; 4947 4948 for (int i = 0; ; ) 4949 { 4950 while (pNextEntry) 4951 { 4952 const Block* const pNextBlock = pNextEntry->GetBlock(); 4953 assert(pNextBlock); 4954 4955 if (pNextBlock->GetTrackNumber() == m_info.number) 4956 return 0; 4957 4958 pCurrEntry = pNextEntry; 4959 4960 status = pCluster->GetNext(pCurrEntry, pNextEntry); 4961 4962 if (status < 0) //error 4963 return status; 4964 } 4965 4966 pCluster = m_pSegment->GetNext(pCluster); 4967 4968 if (pCluster == NULL) 4969 { 4970 pNextEntry = GetEOS(); 4971 return 1; 4972 } 4973 4974 if (pCluster->EOS()) 4975 { 4976 #if 0 4977 if (m_pSegment->Unparsed() <= 0) //all clusters have been loaded 4978 { 4979 pNextEntry = GetEOS(); 4980 return 1; 4981 } 4982 #else 4983 if (m_pSegment->DoneParsing()) 4984 { 4985 pNextEntry = GetEOS(); 4986 return 1; 4987 } 4988 #endif 4989 4990 //TODO: there is a potential O(n^2) problem here: we tell the 4991 //caller to (pre)load another cluster, which he does, but then he 4992 //calls GetNext again, which repeats the same search. This is 4993 //a pathological case, since the only way it can happen is if 4994 //there exists a long sequence of clusters none of which contain a 4995 // block from this track. One way around this problem is for the 4996 //caller to be smarter when he loads another cluster: don't call 4997 //us back until you have a cluster that contains a block from this 4998 //track. (Of course, that's not cheap either, since our caller 4999 //would have to scan the each cluster as it's loaded, so that 5000 //would just push back the problem.) 5001 5002 pNextEntry = NULL; 5003 return E_BUFFER_NOT_FULL; 5004 } 5005 5006 status = pCluster->GetFirst(pNextEntry); 5007 5008 if (status < 0) //error 5009 return status; 5010 5011 if (pNextEntry == NULL) //empty cluster 5012 continue; 5013 5014 ++i; 5015 5016 if (i >= 100) 5017 break; 5018 } 5019 5020 //NOTE: if we get here, it means that we didn't find a block with 5021 //a matching track number after lots of searching, so we give 5022 //up trying. 5023 5024 pNextEntry = GetEOS(); //so we can return a non-NULL value 5025 return 1; 5026 } 5027 5028 const ContentEncoding* 5029 Track::GetContentEncodingByIndex(unsigned long idx) const { 5030 const ptrdiff_t count = 5031 content_encoding_entries_end_ - content_encoding_entries_; 5032 assert(count >= 0); 5033 5034 if (idx >= static_cast<unsigned long>(count)) 5035 return NULL; 5036 5037 return content_encoding_entries_[idx]; 5038 } 5039 5040 unsigned long Track::GetContentEncodingCount() const { 5041 const ptrdiff_t count = 5042 content_encoding_entries_end_ - content_encoding_entries_; 5043 assert(count >= 0); 5044 5045 return static_cast<unsigned long>(count); 5046 } 5047 5048 void Track::ParseContentEncodingsEntry(long long start, long long size) { 5049 IMkvReader* const pReader = m_pSegment->m_pReader; 5050 assert(pReader); 5051 5052 long long pos = start; 5053 const long long stop = start + size; 5054 5055 // Count ContentEncoding elements. 5056 long long pos1 = start; 5057 int count = 0; 5058 5059 while (pos1 < stop) { 5060 long len; 5061 const long long id = ReadUInt(pReader, pos1, len); 5062 assert(id >= 0); 5063 assert((pos1 + len) <= stop); 5064 5065 pos1 += len; //consume id 5066 5067 const long long size = ReadUInt(pReader, pos1, len); 5068 assert(size >= 0); 5069 assert((pos1 + len) <= stop); 5070 5071 pos1 += len; //consume length of size 5072 5073 //pos now designates start of element 5074 if (id == 0x2240) // ContentEncoding ID 5075 ++count; 5076 5077 pos1 += size; //consume payload 5078 assert(pos1 <= stop); 5079 } 5080 5081 if (count <= 0) 5082 return; 5083 5084 content_encoding_entries_ = new ContentEncoding*[count]; 5085 content_encoding_entries_end_ = content_encoding_entries_; 5086 5087 while (pos < stop) { 5088 long len; 5089 const long long id = ReadUInt(pReader, pos, len); 5090 assert(id >= 0); 5091 assert((pos + len) <= stop); 5092 5093 pos += len; //consume id 5094 5095 const long long size1 = ReadUInt(pReader, pos, len); 5096 assert(size1 >= 0); 5097 assert((pos + len) <= stop); 5098 5099 pos += len; //consume length of size 5100 5101 //pos now designates start of element 5102 if (id == 0x2240) { // ContentEncoding ID 5103 ContentEncoding* const content_encoding = new ContentEncoding(); 5104 5105 if (!content_encoding->ParseContentEncodingEntry(pos, size1, pReader)) { 5106 delete content_encoding; 5107 } else { 5108 *content_encoding_entries_end_ = content_encoding; 5109 ++content_encoding_entries_end_; 5110 } 5111 } 5112 5113 pos += size1; //consume payload 5114 assert(pos <= stop); 5115 } 5116 5117 assert(pos == stop); 5118 5119 return; 5120 } 5121 5122 Track::EOSBlock::EOSBlock() : 5123 BlockEntry(NULL, LONG_MIN) 5124 { 5125 } 5126 5127 BlockEntry::Kind Track::EOSBlock::GetKind() const 5128 { 5129 return kBlockEOS; 5130 } 5131 5132 5133 const Block* Track::EOSBlock::GetBlock() const 5134 { 5135 return NULL; 5136 } 5137 5138 5139 VideoTrack::VideoTrack( 5140 Segment* pSegment, 5141 long long element_start, 5142 long long element_size) : 5143 Track(pSegment, element_start, element_size) 5144 { 5145 } 5146 5147 5148 long VideoTrack::Parse( 5149 Segment* pSegment, 5150 const Info& i, 5151 long long elem_st, 5152 long long elem_sz, 5153 VideoTrack*& pTrack) 5154 { 5155 if (pTrack) 5156 return -1; 5157 5158 if (i.type != Track::kVideo) 5159 return -1; 5160 5161 long long width = 0; 5162 long long height = 0; 5163 double rate = 0.0; 5164 5165 IMkvReader* const pReader = pSegment->m_pReader; 5166 5167 const Settings& s = i.settings; 5168 assert(s.start >= 0); 5169 assert(s.size >= 0); 5170 5171 long long pos = s.start; 5172 assert(pos >= 0); 5173 5174 const long long stop = pos + s.size; 5175 5176 while (pos < stop) 5177 { 5178 long long id, size; 5179 5180 const long status = ParseElementHeader( 5181 pReader, 5182 pos, 5183 stop, 5184 id, 5185 size); 5186 5187 if (status < 0) //error 5188 return status; 5189 5190 if (id == 0x30) //pixel width 5191 { 5192 width = UnserializeUInt(pReader, pos, size); 5193 5194 if (width <= 0) 5195 return E_FILE_FORMAT_INVALID; 5196 } 5197 else if (id == 0x3A) //pixel height 5198 { 5199 height = UnserializeUInt(pReader, pos, size); 5200 5201 if (height <= 0) 5202 return E_FILE_FORMAT_INVALID; 5203 } 5204 else if (id == 0x0383E3) //frame rate 5205 { 5206 const long status = UnserializeFloat( 5207 pReader, 5208 pos, 5209 size, 5210 rate); 5211 5212 if (status < 0) 5213 return status; 5214 5215 if (rate <= 0) 5216 return E_FILE_FORMAT_INVALID; 5217 } 5218 5219 pos += size; //consume payload 5220 assert(pos <= stop); 5221 } 5222 5223 assert(pos == stop); 5224 5225 pTrack = new (std::nothrow) VideoTrack(pSegment, elem_st, elem_sz); 5226 5227 if (pTrack == NULL) 5228 return -1; //generic error 5229 5230 const int status = i.Copy(pTrack->m_info); 5231 5232 if (status) 5233 return status; 5234 5235 pTrack->m_width = width; 5236 pTrack->m_height = height; 5237 pTrack->m_rate = rate; 5238 5239 return 0; //success 5240 } 5241 5242 5243 bool VideoTrack::VetEntry(const BlockEntry* pBlockEntry) const 5244 { 5245 assert(pBlockEntry); 5246 5247 const Block* const pBlock = pBlockEntry->GetBlock(); 5248 assert(pBlock); 5249 assert(pBlock->GetTrackNumber() == m_info.number); 5250 5251 return pBlock->IsKey(); 5252 } 5253 5254 5255 long VideoTrack::Seek( 5256 long long time_ns, 5257 const BlockEntry*& pResult) const 5258 { 5259 const long status = GetFirst(pResult); 5260 5261 if (status < 0) //buffer underflow, etc 5262 return status; 5263 5264 assert(pResult); 5265 5266 if (pResult->EOS()) 5267 return 0; 5268 5269 const Cluster* pCluster = pResult->GetCluster(); 5270 assert(pCluster); 5271 assert(pCluster->GetIndex() >= 0); 5272 5273 if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) 5274 return 0; 5275 5276 Cluster** const clusters = m_pSegment->m_clusters; 5277 assert(clusters); 5278 5279 const long count = m_pSegment->GetCount(); //loaded only, not pre-loaded 5280 assert(count > 0); 5281 5282 Cluster** const i = clusters + pCluster->GetIndex(); 5283 assert(i); 5284 assert(*i == pCluster); 5285 assert(pCluster->GetTime() <= time_ns); 5286 5287 Cluster** const j = clusters + count; 5288 5289 Cluster** lo = i; 5290 Cluster** hi = j; 5291 5292 while (lo < hi) 5293 { 5294 //INVARIANT: 5295 //[i, lo) <= time_ns 5296 //[lo, hi) ? 5297 //[hi, j) > time_ns 5298 5299 Cluster** const mid = lo + (hi - lo) / 2; 5300 assert(mid < hi); 5301 5302 pCluster = *mid; 5303 assert(pCluster); 5304 assert(pCluster->GetIndex() >= 0); 5305 assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters)); 5306 5307 const long long t = pCluster->GetTime(); 5308 5309 if (t <= time_ns) 5310 lo = mid + 1; 5311 else 5312 hi = mid; 5313 5314 assert(lo <= hi); 5315 } 5316 5317 assert(lo == hi); 5318 assert(lo > i); 5319 assert(lo <= j); 5320 5321 pCluster = *--lo; 5322 assert(pCluster); 5323 assert(pCluster->GetTime() <= time_ns); 5324 5325 pResult = pCluster->GetEntry(this, time_ns); 5326 5327 if ((pResult != 0) && !pResult->EOS()) //found a keyframe 5328 return 0; 5329 5330 while (lo != i) 5331 { 5332 pCluster = *--lo; 5333 assert(pCluster); 5334 assert(pCluster->GetTime() <= time_ns); 5335 5336 #if 0 5337 //TODO: 5338 //We need to handle the case when a cluster 5339 //contains multiple keyframes. Simply returning 5340 //the largest keyframe on the cluster isn't 5341 //good enough. 5342 pResult = pCluster->GetMaxKey(this); 5343 #else 5344 pResult = pCluster->GetEntry(this, time_ns); 5345 #endif 5346 5347 if ((pResult != 0) && !pResult->EOS()) 5348 return 0; 5349 } 5350 5351 //weird: we're on the first cluster, but no keyframe found 5352 //should never happen but we must return something anyway 5353 5354 pResult = GetEOS(); 5355 return 0; 5356 } 5357 5358 5359 long long VideoTrack::GetWidth() const 5360 { 5361 return m_width; 5362 } 5363 5364 5365 long long VideoTrack::GetHeight() const 5366 { 5367 return m_height; 5368 } 5369 5370 5371 double VideoTrack::GetFrameRate() const 5372 { 5373 return m_rate; 5374 } 5375 5376 5377 AudioTrack::AudioTrack( 5378 Segment* pSegment, 5379 long long element_start, 5380 long long element_size) : 5381 Track(pSegment, element_start, element_size) 5382 { 5383 } 5384 5385 5386 long AudioTrack::Parse( 5387 Segment* pSegment, 5388 const Info& i, 5389 long long elem_st, 5390 long long elem_sz, 5391 AudioTrack*& pTrack) 5392 { 5393 if (pTrack) 5394 return -1; 5395 5396 if (i.type != Track::kAudio) 5397 return -1; 5398 5399 IMkvReader* const pReader = pSegment->m_pReader; 5400 5401 const Settings& s = i.settings; 5402 assert(s.start >= 0); 5403 assert(s.size >= 0); 5404 5405 long long pos = s.start; 5406 assert(pos >= 0); 5407 5408 const long long stop = pos + s.size; 5409 5410 double rate = 8000.0; 5411 long long channels = 1; 5412 long long bit_depth = 0; 5413 5414 while (pos < stop) 5415 { 5416 long long id, size; 5417 5418 long status = ParseElementHeader( 5419 pReader, 5420 pos, 5421 stop, 5422 id, 5423 size); 5424 5425 if (status < 0) //error 5426 return status; 5427 5428 if (id == 0x35) //Sample Rate 5429 { 5430 status = UnserializeFloat(pReader, pos, size, rate); 5431 5432 if (status < 0) 5433 return status; 5434 5435 if (rate <= 0) 5436 return E_FILE_FORMAT_INVALID; 5437 } 5438 else if (id == 0x1F) //Channel Count 5439 { 5440 channels = UnserializeUInt(pReader, pos, size); 5441 5442 if (channels <= 0) 5443 return E_FILE_FORMAT_INVALID; 5444 } 5445 else if (id == 0x2264) //Bit Depth 5446 { 5447 bit_depth = UnserializeUInt(pReader, pos, size); 5448 5449 if (bit_depth <= 0) 5450 return E_FILE_FORMAT_INVALID; 5451 } 5452 5453 pos += size; //consume payload 5454 assert(pos <= stop); 5455 } 5456 5457 assert(pos == stop); 5458 5459 pTrack = new (std::nothrow) AudioTrack(pSegment, elem_st, elem_sz); 5460 5461 if (pTrack == NULL) 5462 return -1; //generic error 5463 5464 const int status = i.Copy(pTrack->m_info); 5465 5466 if (status) 5467 return status; 5468 5469 pTrack->m_rate = rate; 5470 pTrack->m_channels = channels; 5471 pTrack->m_bitDepth = bit_depth; 5472 5473 return 0; //success 5474 } 5475 5476 5477 bool AudioTrack::VetEntry(const BlockEntry* pBlockEntry) const 5478 { 5479 assert(pBlockEntry); 5480 5481 const Block* const pBlock = pBlockEntry->GetBlock(); 5482 assert(pBlock); 5483 assert(pBlock->GetTrackNumber() == m_info.number); 5484 5485 return true; 5486 } 5487 5488 5489 long AudioTrack::Seek( 5490 long long time_ns, 5491 const BlockEntry*& pResult) const 5492 { 5493 const long status = GetFirst(pResult); 5494 5495 if (status < 0) //buffer underflow, etc 5496 return status; 5497 5498 assert(pResult); 5499 5500 if (pResult->EOS()) 5501 return 0; 5502 5503 const Cluster* pCluster = pResult->GetCluster(); 5504 assert(pCluster); 5505 assert(pCluster->GetIndex() >= 0); 5506 5507 if (time_ns <= pResult->GetBlock()->GetTime(pCluster)) 5508 return 0; 5509 5510 Cluster** const clusters = m_pSegment->m_clusters; 5511 assert(clusters); 5512 5513 const long count = m_pSegment->GetCount(); //loaded only, not preloaded 5514 assert(count > 0); 5515 5516 Cluster** const i = clusters + pCluster->GetIndex(); 5517 assert(i); 5518 assert(*i == pCluster); 5519 assert(pCluster->GetTime() <= time_ns); 5520 5521 Cluster** const j = clusters + count; 5522 5523 Cluster** lo = i; 5524 Cluster** hi = j; 5525 5526 while (lo < hi) 5527 { 5528 //INVARIANT: 5529 //[i, lo) <= time_ns 5530 //[lo, hi) ? 5531 //[hi, j) > time_ns 5532 5533 Cluster** const mid = lo + (hi - lo) / 2; 5534 assert(mid < hi); 5535 5536 pCluster = *mid; 5537 assert(pCluster); 5538 assert(pCluster->GetIndex() >= 0); 5539 assert(pCluster->GetIndex() == long(mid - m_pSegment->m_clusters)); 5540 5541 const long long t = pCluster->GetTime(); 5542 5543 if (t <= time_ns) 5544 lo = mid + 1; 5545 else 5546 hi = mid; 5547 5548 assert(lo <= hi); 5549 } 5550 5551 assert(lo == hi); 5552 assert(lo > i); 5553 assert(lo <= j); 5554 5555 while (lo > i) 5556 { 5557 pCluster = *--lo; 5558 assert(pCluster); 5559 assert(pCluster->GetTime() <= time_ns); 5560 5561 pResult = pCluster->GetEntry(this); 5562 5563 if ((pResult != 0) && !pResult->EOS()) 5564 return 0; 5565 5566 //landed on empty cluster (no entries) 5567 } 5568 5569 pResult = GetEOS(); //weird 5570 return 0; 5571 } 5572 5573 5574 double AudioTrack::GetSamplingRate() const 5575 { 5576 return m_rate; 5577 } 5578 5579 5580 long long AudioTrack::GetChannels() const 5581 { 5582 return m_channels; 5583 } 5584 5585 long long AudioTrack::GetBitDepth() const 5586 { 5587 return m_bitDepth; 5588 } 5589 5590 Tracks::Tracks( 5591 Segment* pSegment, 5592 long long start, 5593 long long size_, 5594 long long element_start, 5595 long long element_size) : 5596 m_pSegment(pSegment), 5597 m_start(start), 5598 m_size(size_), 5599 m_element_start(element_start), 5600 m_element_size(element_size), 5601 m_trackEntries(NULL), 5602 m_trackEntriesEnd(NULL) 5603 { 5604 } 5605 5606 5607 long Tracks::Parse() 5608 { 5609 assert(m_trackEntries == NULL); 5610 assert(m_trackEntriesEnd == NULL); 5611 5612 const long long stop = m_start + m_size; 5613 IMkvReader* const pReader = m_pSegment->m_pReader; 5614 5615 int count = 0; 5616 long long pos = m_start; 5617 5618 while (pos < stop) 5619 { 5620 long long id, size; 5621 5622 const long status = ParseElementHeader( 5623 pReader, 5624 pos, 5625 stop, 5626 id, 5627 size); 5628 5629 if (status < 0) //error 5630 return status; 5631 5632 if (size == 0) //weird 5633 continue; 5634 5635 if (id == 0x2E) //TrackEntry ID 5636 ++count; 5637 5638 pos += size; //consume payload 5639 assert(pos <= stop); 5640 } 5641 5642 assert(pos == stop); 5643 5644 if (count <= 0) 5645 return 0; //success 5646 5647 m_trackEntries = new (std::nothrow) Track*[count]; 5648 5649 if (m_trackEntries == NULL) 5650 return -1; 5651 5652 m_trackEntriesEnd = m_trackEntries; 5653 5654 pos = m_start; 5655 5656 while (pos < stop) 5657 { 5658 const long long element_start = pos; 5659 5660 long long id, payload_size; 5661 5662 const long status = ParseElementHeader( 5663 pReader, 5664 pos, 5665 stop, 5666 id, 5667 payload_size); 5668 5669 if (status < 0) //error 5670 return status; 5671 5672 if (payload_size == 0) //weird 5673 continue; 5674 5675 const long long payload_stop = pos + payload_size; 5676 assert(payload_stop <= stop); //checked in ParseElement 5677 5678 const long long element_size = payload_stop - element_start; 5679 5680 if (id == 0x2E) //TrackEntry ID 5681 { 5682 Track*& pTrack = *m_trackEntriesEnd; 5683 pTrack = NULL; 5684 5685 const long status = ParseTrackEntry( 5686 pos, 5687 payload_size, 5688 element_start, 5689 element_size, 5690 pTrack); 5691 5692 if (status) 5693 return status; 5694 5695 if (pTrack) 5696 ++m_trackEntriesEnd; 5697 } 5698 5699 pos = payload_stop; 5700 assert(pos <= stop); 5701 } 5702 5703 assert(pos == stop); 5704 5705 return 0; //success 5706 } 5707 5708 5709 unsigned long Tracks::GetTracksCount() const 5710 { 5711 const ptrdiff_t result = m_trackEntriesEnd - m_trackEntries; 5712 assert(result >= 0); 5713 5714 return static_cast<unsigned long>(result); 5715 } 5716 5717 long Tracks::ParseTrackEntry( 5718 long long track_start, 5719 long long track_size, 5720 long long elem_st, 5721 long long elem_sz, 5722 Track*& pTrack) const 5723 { 5724 if (pTrack) 5725 return -1; 5726 5727 IMkvReader* const pReader = m_pSegment->m_pReader; 5728 5729 long long pos = track_start; 5730 const long long track_stop = track_start + track_size; 5731 5732 Track::Info i; 5733 5734 i.type = 0; 5735 i.number = 0; 5736 i.uid = 0; 5737 5738 Track::Settings v; 5739 v.start = -1; 5740 v.size = -1; 5741 5742 Track::Settings a; 5743 a.start = -1; 5744 a.size = -1; 5745 5746 Track::Settings e; //content_encodings_settings; 5747 e.start = -1; 5748 e.size = -1; 5749 5750 long long lacing = 1; //default is true 5751 5752 while (pos < track_stop) 5753 { 5754 long long id, size; 5755 5756 const long status = ParseElementHeader( 5757 pReader, 5758 pos, 5759 track_stop, 5760 id, 5761 size); 5762 5763 if (status < 0) //error 5764 return status; 5765 5766 const long long start = pos; 5767 5768 if (id == 0x60) // VideoSettings ID 5769 { 5770 if (size < 0) 5771 return E_FILE_FORMAT_INVALID; 5772 5773 v.start = start; 5774 v.size = size; 5775 } 5776 else if (id == 0x61) // AudioSettings ID 5777 { 5778 if (size < 0) 5779 return E_FILE_FORMAT_INVALID; 5780 5781 a.start = start; 5782 a.size = size; 5783 } 5784 else if (id == 0x2D80) // ContentEncodings ID 5785 { 5786 if (size < 0) 5787 return E_FILE_FORMAT_INVALID; 5788 5789 e.start = start; 5790 e.size = size; 5791 } 5792 else if (id == 0x33C5) //Track UID 5793 { 5794 if ((size <= 0) || (size > 8)) 5795 return E_FILE_FORMAT_INVALID; 5796 5797 i.uid = 0; 5798 5799 long long pos_ = start; 5800 const long long pos_end = start + size; 5801 5802 while (pos_ != pos_end) 5803 { 5804 unsigned char b; 5805 5806 const int status = pReader->Read(pos_, 1, &b); 5807 5808 if (status) 5809 return status; 5810 5811 i.uid <<= 8; 5812 i.uid |= b; 5813 5814 ++pos_; 5815 } 5816 } 5817 else if (id == 0x57) //Track Number 5818 { 5819 const long long num = UnserializeUInt(pReader, pos, size); 5820 5821 if ((num <= 0) || (num > 127)) 5822 return E_FILE_FORMAT_INVALID; 5823 5824 i.number = static_cast<long>(num); 5825 } 5826 else if (id == 0x03) //Track Type 5827 { 5828 const long long type = UnserializeUInt(pReader, pos, size); 5829 5830 if ((type <= 0) || (type > 254)) 5831 return E_FILE_FORMAT_INVALID; 5832 5833 i.type = static_cast<long>(type); 5834 } 5835 else if (id == 0x136E) //Track Name 5836 { 5837 const long status = UnserializeString( 5838 pReader, 5839 pos, 5840 size, 5841 i.nameAsUTF8); 5842 5843 if (status) 5844 return status; 5845 } 5846 else if (id == 0x06) //CodecID 5847 { 5848 const long status = UnserializeString( 5849 pReader, 5850 pos, 5851 size, 5852 i.codecId); 5853 5854 if (status) 5855 return status; 5856 } 5857 else if (id == 0x1C) //lacing 5858 { 5859 lacing = UnserializeUInt(pReader, pos, size); 5860 5861 if ((lacing < 0) || (lacing > 1)) 5862 return E_FILE_FORMAT_INVALID; 5863 } 5864 else if (id == 0x23A2) //Codec Private 5865 { 5866 delete[] i.codecPrivate; 5867 i.codecPrivate = NULL; 5868 i.codecPrivateSize = 0; 5869 5870 if (size <= 0) 5871 return E_FILE_FORMAT_INVALID; 5872 5873 const size_t buflen = static_cast<size_t>(size); 5874 5875 typedef unsigned char* buf_t; 5876 5877 const buf_t buf = new (std::nothrow) unsigned char[buflen]; 5878 5879 if (buf == NULL) 5880 return -1; 5881 5882 const int status = pReader->Read(pos, buflen, buf); 5883 5884 if (status) 5885 { 5886 delete[] buf; 5887 return status; 5888 } 5889 5890 i.codecPrivate = buf; 5891 i.codecPrivateSize = buflen; 5892 } 5893 else if (id == 0x058688) //Codec Name 5894 { 5895 const long status = UnserializeString( 5896 pReader, 5897 pos, 5898 size, 5899 i.codecNameAsUTF8); 5900 5901 if (status) 5902 return status; 5903 } 5904 5905 pos += size; //consume payload 5906 assert(pos <= track_stop); 5907 } 5908 5909 assert(pos == track_stop); 5910 5911 if (i.number <= 0) //not specified 5912 return E_FILE_FORMAT_INVALID; 5913 5914 if (GetTrackByNumber(i.number)) 5915 return E_FILE_FORMAT_INVALID; 5916 5917 if (i.type <= 0) //not specified 5918 return E_FILE_FORMAT_INVALID; 5919 5920 if ((i.type != Track::kVideo) && (i.type != Track::kAudio)) 5921 { 5922 //TODO(matthewjheaney): go ahead and create a "generic" track 5923 //object, so that GetTrackByXXX always returns something, even 5924 //if the object it returns has a type that is not kVideo or kAudio. 5925 5926 return 0; //no error 5927 } 5928 5929 i.lacing = (lacing > 0) ? true : false; 5930 5931 long status; 5932 5933 if (i.type == Track::kVideo) 5934 { 5935 if (v.start < 0) 5936 return E_FILE_FORMAT_INVALID; 5937 5938 if (a.start >= 0) 5939 return E_FILE_FORMAT_INVALID; 5940 5941 i.settings = v; 5942 5943 VideoTrack* p = NULL; 5944 5945 status = VideoTrack::Parse(m_pSegment, i, elem_st, elem_sz, p); 5946 pTrack = p; 5947 } 5948 else 5949 { 5950 assert(i.type == Track::kAudio); 5951 5952 if (a.start < 0) 5953 return E_FILE_FORMAT_INVALID; 5954 5955 if (v.start >= 0) 5956 return E_FILE_FORMAT_INVALID; 5957 5958 i.settings = a; 5959 5960 AudioTrack* p = NULL; 5961 5962 status = AudioTrack::Parse(m_pSegment, i, elem_st, elem_sz, p); 5963 pTrack = p; 5964 } 5965 5966 if (status) 5967 return status; 5968 5969 assert(pTrack); 5970 5971 if (e.start >= 0) 5972 pTrack->ParseContentEncodingsEntry(e.start, e.size); 5973 5974 return 0; //success 5975 } 5976 5977 5978 Tracks::~Tracks() 5979 { 5980 Track** i = m_trackEntries; 5981 Track** const j = m_trackEntriesEnd; 5982 5983 while (i != j) 5984 { 5985 Track* const pTrack = *i++; 5986 delete pTrack; 5987 } 5988 5989 delete[] m_trackEntries; 5990 } 5991 5992 const Track* Tracks::GetTrackByNumber(long tn) const 5993 { 5994 if (tn < 0) 5995 return NULL; 5996 5997 Track** i = m_trackEntries; 5998 Track** const j = m_trackEntriesEnd; 5999 6000 while (i != j) 6001 { 6002 Track* const pTrack = *i++; 6003 6004 if (pTrack == NULL) 6005 continue; 6006 6007 if (tn == pTrack->GetNumber()) 6008 return pTrack; 6009 } 6010 6011 return NULL; //not found 6012 } 6013 6014 6015 const Track* Tracks::GetTrackByIndex(unsigned long idx) const 6016 { 6017 const ptrdiff_t count = m_trackEntriesEnd - m_trackEntries; 6018 6019 if (idx >= static_cast<unsigned long>(count)) 6020 return NULL; 6021 6022 return m_trackEntries[idx]; 6023 } 6024 6025 #if 0 6026 long long Cluster::Unparsed() const 6027 { 6028 if (m_timecode < 0) //not even partially loaded 6029 return LLONG_MAX; 6030 6031 assert(m_pos >= m_element_start); 6032 //assert(m_element_size > m_size); 6033 6034 const long long element_stop = m_element_start + m_element_size; 6035 assert(m_pos <= element_stop); 6036 6037 const long long result = element_stop - m_pos; 6038 assert(result >= 0); 6039 6040 return result; 6041 } 6042 #endif 6043 6044 6045 long Cluster::Load(long long& pos, long& len) const 6046 { 6047 assert(m_pSegment); 6048 assert(m_pos >= m_element_start); 6049 6050 if (m_timecode >= 0) //at least partially loaded 6051 return 0; 6052 6053 assert(m_pos == m_element_start); 6054 assert(m_element_size < 0); 6055 6056 IMkvReader* const pReader = m_pSegment->m_pReader; 6057 6058 long long total, avail; 6059 6060 const int status = pReader->Length(&total, &avail); 6061 6062 if (status < 0) //error 6063 return status; 6064 6065 assert((total < 0) || (avail <= total)); 6066 assert((total < 0) || (m_pos <= total)); //TODO: verify this 6067 6068 pos = m_pos; 6069 6070 long long cluster_size = -1; 6071 6072 { 6073 if ((pos + 1) > avail) 6074 { 6075 len = 1; 6076 return E_BUFFER_NOT_FULL; 6077 } 6078 6079 long long result = GetUIntLength(pReader, pos, len); 6080 6081 if (result < 0) //error or underflow 6082 return static_cast<long>(result); 6083 6084 if (result > 0) //underflow (weird) 6085 return E_BUFFER_NOT_FULL; 6086 6087 //if ((pos + len) > segment_stop) 6088 // return E_FILE_FORMAT_INVALID; 6089 6090 if ((pos + len) > avail) 6091 return E_BUFFER_NOT_FULL; 6092 6093 const long long id_ = ReadUInt(pReader, pos, len); 6094 6095 if (id_ < 0) //error 6096 return static_cast<long>(id_); 6097 6098 if (id_ != 0x0F43B675) //Cluster ID 6099 return E_FILE_FORMAT_INVALID; 6100 6101 pos += len; //consume id 6102 6103 //read cluster size 6104 6105 if ((pos + 1) > avail) 6106 { 6107 len = 1; 6108 return E_BUFFER_NOT_FULL; 6109 } 6110 6111 result = GetUIntLength(pReader, pos, len); 6112 6113 if (result < 0) //error 6114 return static_cast<long>(result); 6115 6116 if (result > 0) //weird 6117 return E_BUFFER_NOT_FULL; 6118 6119 //if ((pos + len) > segment_stop) 6120 // return E_FILE_FORMAT_INVALID; 6121 6122 if ((pos + len) > avail) 6123 return E_BUFFER_NOT_FULL; 6124 6125 const long long size = ReadUInt(pReader, pos, len); 6126 6127 if (size < 0) //error 6128 return static_cast<long>(cluster_size); 6129 6130 if (size == 0) 6131 return E_FILE_FORMAT_INVALID; //TODO: verify this 6132 6133 pos += len; //consume length of size of element 6134 6135 const long long unknown_size = (1LL << (7 * len)) - 1; 6136 6137 if (size != unknown_size) 6138 cluster_size = size; 6139 } 6140 6141 //pos points to start of payload 6142 6143 #if 0 6144 len = static_cast<long>(size_); 6145 6146 if (cluster_stop > avail) 6147 return E_BUFFER_NOT_FULL; 6148 #endif 6149 6150 long long timecode = -1; 6151 long long new_pos = -1; 6152 bool bBlock = false; 6153 6154 long long cluster_stop = (cluster_size < 0) ? -1 : pos + cluster_size; 6155 6156 for (;;) 6157 { 6158 if ((cluster_stop >= 0) && (pos >= cluster_stop)) 6159 break; 6160 6161 //Parse ID 6162 6163 if ((pos + 1) > avail) 6164 { 6165 len = 1; 6166 return E_BUFFER_NOT_FULL; 6167 } 6168 6169 long long result = GetUIntLength(pReader, pos, len); 6170 6171 if (result < 0) //error 6172 return static_cast<long>(result); 6173 6174 if (result > 0) //weird 6175 return E_BUFFER_NOT_FULL; 6176 6177 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) 6178 return E_FILE_FORMAT_INVALID; 6179 6180 if ((pos + len) > avail) 6181 return E_BUFFER_NOT_FULL; 6182 6183 const long long id = ReadUInt(pReader, pos, len); 6184 6185 if (id < 0) //error 6186 return static_cast<long>(id); 6187 6188 if (id == 0) 6189 return E_FILE_FORMAT_INVALID; 6190 6191 //This is the distinguished set of ID's we use to determine 6192 //that we have exhausted the sub-element's inside the cluster 6193 //whose ID we parsed earlier. 6194 6195 if (id == 0x0F43B675) //Cluster ID 6196 break; 6197 6198 if (id == 0x0C53BB6B) //Cues ID 6199 break; 6200 6201 pos += len; //consume ID field 6202 6203 //Parse Size 6204 6205 if ((pos + 1) > avail) 6206 { 6207 len = 1; 6208 return E_BUFFER_NOT_FULL; 6209 } 6210 6211 result = GetUIntLength(pReader, pos, len); 6212 6213 if (result < 0) //error 6214 return static_cast<long>(result); 6215 6216 if (result > 0) //weird 6217 return E_BUFFER_NOT_FULL; 6218 6219 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) 6220 return E_FILE_FORMAT_INVALID; 6221 6222 if ((pos + len) > avail) 6223 return E_BUFFER_NOT_FULL; 6224 6225 const long long size = ReadUInt(pReader, pos, len); 6226 6227 if (size < 0) //error 6228 return static_cast<long>(size); 6229 6230 const long long unknown_size = (1LL << (7 * len)) - 1; 6231 6232 if (size == unknown_size) 6233 return E_FILE_FORMAT_INVALID; 6234 6235 pos += len; //consume size field 6236 6237 if ((cluster_stop >= 0) && (pos > cluster_stop)) 6238 return E_FILE_FORMAT_INVALID; 6239 6240 //pos now points to start of payload 6241 6242 if (size == 0) //weird 6243 continue; 6244 6245 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) 6246 return E_FILE_FORMAT_INVALID; 6247 6248 if (id == 0x67) //TimeCode ID 6249 { 6250 len = static_cast<long>(size); 6251 6252 if ((pos + size) > avail) 6253 return E_BUFFER_NOT_FULL; 6254 6255 timecode = UnserializeUInt(pReader, pos, size); 6256 6257 if (timecode < 0) //error (or underflow) 6258 return static_cast<long>(timecode); 6259 6260 new_pos = pos + size; 6261 6262 if (bBlock) 6263 break; 6264 } 6265 else if (id == 0x20) //BlockGroup ID 6266 { 6267 bBlock = true; 6268 break; 6269 } 6270 else if (id == 0x23) //SimpleBlock ID 6271 { 6272 bBlock = true; 6273 break; 6274 } 6275 6276 pos += size; //consume payload 6277 assert((cluster_stop < 0) || (pos <= cluster_stop)); 6278 } 6279 6280 assert((cluster_stop < 0) || (pos <= cluster_stop)); 6281 6282 if (timecode < 0) //no timecode found 6283 return E_FILE_FORMAT_INVALID; 6284 6285 if (!bBlock) 6286 return E_FILE_FORMAT_INVALID; 6287 6288 m_pos = new_pos; //designates position just beyond timecode payload 6289 m_timecode = timecode; // m_timecode >= 0 means we're partially loaded 6290 6291 if (cluster_size >= 0) 6292 m_element_size = cluster_stop - m_element_start; 6293 6294 return 0; 6295 } 6296 6297 6298 long Cluster::Parse(long long& pos, long& len) const 6299 { 6300 long status = Load(pos, len); 6301 6302 if (status < 0) 6303 return status; 6304 6305 assert(m_pos >= m_element_start); 6306 assert(m_timecode >= 0); 6307 //assert(m_size > 0); 6308 //assert(m_element_size > m_size); 6309 6310 const long long cluster_stop = 6311 (m_element_size < 0) ? -1 : m_element_start + m_element_size; 6312 6313 if ((cluster_stop >= 0) && (m_pos >= cluster_stop)) 6314 return 1; //nothing else to do 6315 6316 IMkvReader* const pReader = m_pSegment->m_pReader; 6317 6318 long long total, avail; 6319 6320 status = pReader->Length(&total, &avail); 6321 6322 if (status < 0) //error 6323 return status; 6324 6325 assert((total < 0) || (avail <= total)); 6326 6327 pos = m_pos; 6328 6329 for (;;) 6330 { 6331 if ((cluster_stop >= 0) && (pos >= cluster_stop)) 6332 break; 6333 6334 if ((total >= 0) && (pos >= total)) 6335 { 6336 if (m_element_size < 0) 6337 m_element_size = pos - m_element_start; 6338 6339 break; 6340 } 6341 6342 //Parse ID 6343 6344 if ((pos + 1) > avail) 6345 { 6346 len = 1; 6347 return E_BUFFER_NOT_FULL; 6348 } 6349 6350 long long result = GetUIntLength(pReader, pos, len); 6351 6352 if (result < 0) //error 6353 return static_cast<long>(result); 6354 6355 if (result > 0) //weird 6356 return E_BUFFER_NOT_FULL; 6357 6358 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) 6359 return E_FILE_FORMAT_INVALID; 6360 6361 if ((pos + len) > avail) 6362 return E_BUFFER_NOT_FULL; 6363 6364 const long long id = ReadUInt(pReader, pos, len); 6365 6366 if (id < 0) //error 6367 return static_cast<long>(id); 6368 6369 if (id == 0) //weird 6370 return E_FILE_FORMAT_INVALID; 6371 6372 //This is the distinguished set of ID's we use to determine 6373 //that we have exhausted the sub-element's inside the cluster 6374 //whose ID we parsed earlier. 6375 6376 if ((id == 0x0F43B675) || (id == 0x0C53BB6B)) //Cluster or Cues ID 6377 { 6378 if (m_element_size < 0) 6379 m_element_size = pos - m_element_start; 6380 6381 break; 6382 } 6383 6384 pos += len; //consume ID field 6385 6386 //Parse Size 6387 6388 if ((pos + 1) > avail) 6389 { 6390 len = 1; 6391 return E_BUFFER_NOT_FULL; 6392 } 6393 6394 result = GetUIntLength(pReader, pos, len); 6395 6396 if (result < 0) //error 6397 return static_cast<long>(result); 6398 6399 if (result > 0) //weird 6400 return E_BUFFER_NOT_FULL; 6401 6402 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) 6403 return E_FILE_FORMAT_INVALID; 6404 6405 if ((pos + len) > avail) 6406 return E_BUFFER_NOT_FULL; 6407 6408 const long long size = ReadUInt(pReader, pos, len); 6409 6410 if (size < 0) //error 6411 return static_cast<long>(size); 6412 6413 const long long unknown_size = (1LL << (7 * len)) - 1; 6414 6415 if (size == unknown_size) 6416 return E_FILE_FORMAT_INVALID; 6417 6418 pos += len; //consume size field 6419 6420 if ((cluster_stop >= 0) && (pos > cluster_stop)) 6421 return E_FILE_FORMAT_INVALID; 6422 6423 //pos now points to start of payload 6424 6425 if (size == 0) //weird 6426 continue; 6427 6428 //const long long block_start = pos; 6429 const long long block_stop = pos + size; 6430 6431 if (cluster_stop >= 0) 6432 { 6433 if (block_stop > cluster_stop) 6434 return E_FILE_FORMAT_INVALID; 6435 } 6436 else if ((total >= 0) && (block_stop > total)) 6437 { 6438 m_element_size = total - m_element_start; 6439 pos = total; 6440 break; 6441 } 6442 else if (block_stop > avail) 6443 { 6444 len = static_cast<long>(size); 6445 return E_BUFFER_NOT_FULL; 6446 } 6447 6448 Cluster* const this_ = const_cast<Cluster*>(this); 6449 6450 if (id == 0x20) //BlockGroup 6451 return this_->ParseBlockGroup(size, pos, len); 6452 6453 if (id == 0x23) //SimpleBlock 6454 return this_->ParseSimpleBlock(size, pos, len); 6455 6456 pos += size; //consume payload 6457 assert((cluster_stop < 0) || (pos <= cluster_stop)); 6458 } 6459 6460 assert(m_element_size > 0); 6461 6462 m_pos = pos; 6463 assert((cluster_stop < 0) || (m_pos <= cluster_stop)); 6464 6465 if (m_entries_count > 0) 6466 { 6467 const long idx = m_entries_count - 1; 6468 6469 const BlockEntry* const pLast = m_entries[idx]; 6470 assert(pLast); 6471 6472 const Block* const pBlock = pLast->GetBlock(); 6473 assert(pBlock); 6474 6475 const long long start = pBlock->m_start; 6476 6477 if ((total >= 0) && (start > total)) 6478 return -1; //defend against trucated stream 6479 6480 const long long size = pBlock->m_size; 6481 6482 const long long stop = start + size; 6483 assert((cluster_stop < 0) || (stop <= cluster_stop)); 6484 6485 if ((total >= 0) && (stop > total)) 6486 return -1; //defend against trucated stream 6487 } 6488 6489 return 1; //no more entries 6490 } 6491 6492 6493 long Cluster::ParseSimpleBlock( 6494 long long block_size, 6495 long long& pos, 6496 long& len) 6497 { 6498 const long long block_start = pos; 6499 const long long block_stop = pos + block_size; 6500 6501 IMkvReader* const pReader = m_pSegment->m_pReader; 6502 6503 long long total, avail; 6504 6505 long status = pReader->Length(&total, &avail); 6506 6507 if (status < 0) //error 6508 return status; 6509 6510 assert((total < 0) || (avail <= total)); 6511 6512 //parse track number 6513 6514 if ((pos + 1) > avail) 6515 { 6516 len = 1; 6517 return E_BUFFER_NOT_FULL; 6518 } 6519 6520 long long result = GetUIntLength(pReader, pos, len); 6521 6522 if (result < 0) //error 6523 return static_cast<long>(result); 6524 6525 if (result > 0) //weird 6526 return E_BUFFER_NOT_FULL; 6527 6528 if ((pos + len) > block_stop) 6529 return E_FILE_FORMAT_INVALID; 6530 6531 if ((pos + len) > avail) 6532 return E_BUFFER_NOT_FULL; 6533 6534 const long long track = ReadUInt(pReader, pos, len); 6535 6536 if (track < 0) //error 6537 return static_cast<long>(track); 6538 6539 if (track == 0) 6540 return E_FILE_FORMAT_INVALID; 6541 6542 #if 0 6543 //TODO(matthewjheaney) 6544 //This turned out to be too conservative. The problem is that 6545 //if we see a track header in the tracks element with an unsupported 6546 //track type, we throw that track header away, so it is not present 6547 //in the track map. But even though we don't understand the track 6548 //header, there are still blocks in the cluster with that track 6549 //number. It was our decision to ignore that track header, so it's 6550 //up to us to deal with blocks associated with that track -- we 6551 //cannot simply report an error since technically there's nothing 6552 //wrong with the file. 6553 // 6554 //For now we go ahead and finish the parse, creating a block entry 6555 //for this block. This is somewhat wasteful, because without a 6556 //track header there's nothing you can do with the block. What 6557 //we really need here is a special return value that indicates to 6558 //the caller that he should ignore this particular block, and 6559 //continue parsing. 6560 6561 const Tracks* const pTracks = m_pSegment->GetTracks(); 6562 assert(pTracks); 6563 6564 const long tn = static_cast<long>(track); 6565 6566 const Track* const pTrack = pTracks->GetTrackByNumber(tn); 6567 6568 if (pTrack == NULL) 6569 return E_FILE_FORMAT_INVALID; 6570 #endif 6571 6572 pos += len; //consume track number 6573 6574 if ((pos + 2) > block_stop) 6575 return E_FILE_FORMAT_INVALID; 6576 6577 if ((pos + 2) > avail) 6578 { 6579 len = 2; 6580 return E_BUFFER_NOT_FULL; 6581 } 6582 6583 pos += 2; //consume timecode 6584 6585 if ((pos + 1) > block_stop) 6586 return E_FILE_FORMAT_INVALID; 6587 6588 if ((pos + 1) > avail) 6589 { 6590 len = 1; 6591 return E_BUFFER_NOT_FULL; 6592 } 6593 6594 unsigned char flags; 6595 6596 status = pReader->Read(pos, 1, &flags); 6597 6598 if (status < 0) //error or underflow 6599 { 6600 len = 1; 6601 return status; 6602 } 6603 6604 ++pos; //consume flags byte 6605 assert(pos <= avail); 6606 6607 if (pos >= block_stop) 6608 return E_FILE_FORMAT_INVALID; 6609 6610 const int lacing = int(flags & 0x06) >> 1; 6611 6612 if ((lacing != 0) && (block_stop > avail)) 6613 { 6614 len = static_cast<long>(block_stop - pos); 6615 return E_BUFFER_NOT_FULL; 6616 } 6617 6618 status = CreateBlock(0x23, block_start, block_size); //simple block id 6619 6620 if (status != 0) 6621 return status; 6622 6623 m_pos = block_stop; 6624 6625 return 0; //success 6626 } 6627 6628 6629 long Cluster::ParseBlockGroup( 6630 long long payload_size, 6631 long long& pos, 6632 long& len) 6633 { 6634 const long long payload_start = pos; 6635 const long long payload_stop = pos + payload_size; 6636 6637 IMkvReader* const pReader = m_pSegment->m_pReader; 6638 6639 long long total, avail; 6640 6641 long status = pReader->Length(&total, &avail); 6642 6643 if (status < 0) //error 6644 return status; 6645 6646 assert((total < 0) || (avail <= total)); 6647 6648 if ((total >= 0) && (payload_stop > total)) 6649 return E_FILE_FORMAT_INVALID; 6650 6651 if (payload_stop > avail) 6652 { 6653 len = static_cast<long>(payload_size); 6654 return E_BUFFER_NOT_FULL; 6655 } 6656 6657 while (pos < payload_stop) 6658 { 6659 //parse sub-block element ID 6660 6661 if ((pos + 1) > avail) 6662 { 6663 len = 1; 6664 return E_BUFFER_NOT_FULL; 6665 } 6666 6667 long long result = GetUIntLength(pReader, pos, len); 6668 6669 if (result < 0) //error 6670 return static_cast<long>(result); 6671 6672 if (result > 0) //weird 6673 return E_BUFFER_NOT_FULL; 6674 6675 if ((pos + len) > payload_stop) 6676 return E_FILE_FORMAT_INVALID; 6677 6678 if ((pos + len) > avail) 6679 return E_BUFFER_NOT_FULL; 6680 6681 const long long id = ReadUInt(pReader, pos, len); 6682 6683 if (id < 0) //error 6684 return static_cast<long>(id); 6685 6686 if (id == 0) //not a value ID 6687 return E_FILE_FORMAT_INVALID; 6688 6689 pos += len; //consume ID field 6690 6691 //Parse Size 6692 6693 if ((pos + 1) > avail) 6694 { 6695 len = 1; 6696 return E_BUFFER_NOT_FULL; 6697 } 6698 6699 result = GetUIntLength(pReader, pos, len); 6700 6701 if (result < 0) //error 6702 return static_cast<long>(result); 6703 6704 if (result > 0) //weird 6705 return E_BUFFER_NOT_FULL; 6706 6707 if ((pos + len) > payload_stop) 6708 return E_FILE_FORMAT_INVALID; 6709 6710 if ((pos + len) > avail) 6711 return E_BUFFER_NOT_FULL; 6712 6713 const long long size = ReadUInt(pReader, pos, len); 6714 6715 if (size < 0) //error 6716 return static_cast<long>(size); 6717 6718 pos += len; //consume size field 6719 6720 //pos now points to start of sub-block group payload 6721 6722 if (pos > payload_stop) 6723 return E_FILE_FORMAT_INVALID; 6724 6725 if (size == 0) //weird 6726 continue; 6727 6728 const long long unknown_size = (1LL << (7 * len)) - 1; 6729 6730 if (size == unknown_size) 6731 return E_FILE_FORMAT_INVALID; 6732 6733 if (id != 0x21) //sub-part of BlockGroup is not a Block 6734 { 6735 pos += size; //consume sub-part of block group 6736 6737 if (pos > payload_stop) 6738 return E_FILE_FORMAT_INVALID; 6739 6740 continue; 6741 } 6742 6743 const long long block_stop = pos + size; 6744 6745 if (block_stop > payload_stop) 6746 return E_FILE_FORMAT_INVALID; 6747 6748 //parse track number 6749 6750 if ((pos + 1) > avail) 6751 { 6752 len = 1; 6753 return E_BUFFER_NOT_FULL; 6754 } 6755 6756 result = GetUIntLength(pReader, pos, len); 6757 6758 if (result < 0) //error 6759 return static_cast<long>(result); 6760 6761 if (result > 0) //weird 6762 return E_BUFFER_NOT_FULL; 6763 6764 if ((pos + len) > block_stop) 6765 return E_FILE_FORMAT_INVALID; 6766 6767 if ((pos + len) > avail) 6768 return E_BUFFER_NOT_FULL; 6769 6770 const long long track = ReadUInt(pReader, pos, len); 6771 6772 if (track < 0) //error 6773 return static_cast<long>(track); 6774 6775 if (track == 0) 6776 return E_FILE_FORMAT_INVALID; 6777 6778 #if 0 6779 //TODO(matthewjheaney) 6780 //This turned out to be too conservative. The problem is that 6781 //if we see a track header in the tracks element with an unsupported 6782 //track type, we throw that track header away, so it is not present 6783 //in the track map. But even though we don't understand the track 6784 //header, there are still blocks in the cluster with that track 6785 //number. It was our decision to ignore that track header, so it's 6786 //up to us to deal with blocks associated with that track -- we 6787 //cannot simply report an error since technically there's nothing 6788 //wrong with the file. 6789 // 6790 //For now we go ahead and finish the parse, creating a block entry 6791 //for this block. This is somewhat wasteful, because without a 6792 //track header there's nothing you can do with the block. What 6793 //we really need here is a special return value that indicates to 6794 //the caller that he should ignore this particular block, and 6795 //continue parsing. 6796 6797 const Tracks* const pTracks = m_pSegment->GetTracks(); 6798 assert(pTracks); 6799 6800 const long tn = static_cast<long>(track); 6801 6802 const Track* const pTrack = pTracks->GetTrackByNumber(tn); 6803 6804 if (pTrack == NULL) 6805 return E_FILE_FORMAT_INVALID; 6806 #endif 6807 6808 pos += len; //consume track number 6809 6810 if ((pos + 2) > block_stop) 6811 return E_FILE_FORMAT_INVALID; 6812 6813 if ((pos + 2) > avail) 6814 { 6815 len = 2; 6816 return E_BUFFER_NOT_FULL; 6817 } 6818 6819 pos += 2; //consume timecode 6820 6821 if ((pos + 1) > block_stop) 6822 return E_FILE_FORMAT_INVALID; 6823 6824 if ((pos + 1) > avail) 6825 { 6826 len = 1; 6827 return E_BUFFER_NOT_FULL; 6828 } 6829 6830 unsigned char flags; 6831 6832 status = pReader->Read(pos, 1, &flags); 6833 6834 if (status < 0) //error or underflow 6835 { 6836 len = 1; 6837 return status; 6838 } 6839 6840 ++pos; //consume flags byte 6841 assert(pos <= avail); 6842 6843 if (pos >= block_stop) 6844 return E_FILE_FORMAT_INVALID; 6845 6846 const int lacing = int(flags & 0x06) >> 1; 6847 6848 if ((lacing != 0) && (block_stop > avail)) 6849 { 6850 len = static_cast<long>(block_stop - pos); 6851 return E_BUFFER_NOT_FULL; 6852 } 6853 6854 pos = block_stop; //consume block-part of block group 6855 assert(pos <= payload_stop); 6856 } 6857 6858 assert(pos == payload_stop); 6859 6860 status = CreateBlock(0x20, payload_start, payload_size); //BlockGroup ID 6861 6862 if (status != 0) 6863 return status; 6864 6865 m_pos = payload_stop; 6866 6867 return 0; //success 6868 } 6869 6870 6871 long Cluster::GetEntry(long index, const mkvparser::BlockEntry*& pEntry) const 6872 { 6873 assert(m_pos >= m_element_start); 6874 6875 pEntry = NULL; 6876 6877 if (index < 0) 6878 return -1; //generic error 6879 6880 if (m_entries_count < 0) 6881 return E_BUFFER_NOT_FULL; 6882 6883 assert(m_entries); 6884 assert(m_entries_size > 0); 6885 assert(m_entries_count <= m_entries_size); 6886 6887 if (index < m_entries_count) 6888 { 6889 pEntry = m_entries[index]; 6890 assert(pEntry); 6891 6892 return 1; //found entry 6893 } 6894 6895 if (m_element_size < 0) //we don't know cluster end yet 6896 return E_BUFFER_NOT_FULL; //underflow 6897 6898 const long long element_stop = m_element_start + m_element_size; 6899 6900 if (m_pos >= element_stop) 6901 return 0; //nothing left to parse 6902 6903 return E_BUFFER_NOT_FULL; //underflow, since more remains to be parsed 6904 } 6905 6906 6907 Cluster* Cluster::Create( 6908 Segment* pSegment, 6909 long idx, 6910 long long off) 6911 //long long element_size) 6912 { 6913 assert(pSegment); 6914 assert(off >= 0); 6915 6916 const long long element_start = pSegment->m_start + off; 6917 6918 Cluster* const pCluster = new Cluster(pSegment, 6919 idx, 6920 element_start); 6921 //element_size); 6922 assert(pCluster); 6923 6924 return pCluster; 6925 } 6926 6927 6928 Cluster::Cluster() : 6929 m_pSegment(NULL), 6930 m_element_start(0), 6931 m_index(0), 6932 m_pos(0), 6933 m_element_size(0), 6934 m_timecode(0), 6935 m_entries(NULL), 6936 m_entries_size(0), 6937 m_entries_count(0) //means "no entries" 6938 { 6939 } 6940 6941 6942 Cluster::Cluster( 6943 Segment* pSegment, 6944 long idx, 6945 long long element_start 6946 /* long long element_size */ ) : 6947 m_pSegment(pSegment), 6948 m_element_start(element_start), 6949 m_index(idx), 6950 m_pos(element_start), 6951 m_element_size(-1 /* element_size */ ), 6952 m_timecode(-1), 6953 m_entries(NULL), 6954 m_entries_size(0), 6955 m_entries_count(-1) //means "has not been parsed yet" 6956 { 6957 } 6958 6959 6960 Cluster::~Cluster() 6961 { 6962 if (m_entries_count <= 0) 6963 return; 6964 6965 BlockEntry** i = m_entries; 6966 BlockEntry** const j = m_entries + m_entries_count; 6967 6968 while (i != j) 6969 { 6970 BlockEntry* p = *i++; 6971 assert(p); 6972 6973 delete p; 6974 } 6975 6976 delete[] m_entries; 6977 } 6978 6979 6980 bool Cluster::EOS() const 6981 { 6982 return (m_pSegment == NULL); 6983 } 6984 6985 6986 long Cluster::GetIndex() const 6987 { 6988 return m_index; 6989 } 6990 6991 6992 long long Cluster::GetPosition() const 6993 { 6994 const long long pos = m_element_start - m_pSegment->m_start; 6995 assert(pos >= 0); 6996 6997 return pos; 6998 } 6999 7000 7001 long long Cluster::GetElementSize() const 7002 { 7003 return m_element_size; 7004 } 7005 7006 7007 #if 0 7008 bool Cluster::HasBlockEntries( 7009 const Segment* pSegment, 7010 long long off) //relative to start of segment payload 7011 { 7012 assert(pSegment); 7013 assert(off >= 0); //relative to segment 7014 7015 IMkvReader* const pReader = pSegment->m_pReader; 7016 7017 long long pos = pSegment->m_start + off; //absolute 7018 long long size; 7019 7020 { 7021 long len; 7022 7023 const long long id = ReadUInt(pReader, pos, len); 7024 (void)id; 7025 assert(id >= 0); 7026 assert(id == 0x0F43B675); //Cluster ID 7027 7028 pos += len; //consume id 7029 7030 size = ReadUInt(pReader, pos, len); 7031 assert(size > 0); 7032 7033 pos += len; //consume size 7034 7035 //pos now points to start of payload 7036 } 7037 7038 const long long stop = pos + size; 7039 7040 while (pos < stop) 7041 { 7042 long len; 7043 7044 const long long id = ReadUInt(pReader, pos, len); 7045 assert(id >= 0); //TODO 7046 assert((pos + len) <= stop); 7047 7048 pos += len; //consume id 7049 7050 const long long size = ReadUInt(pReader, pos, len); 7051 assert(size >= 0); //TODO 7052 assert((pos + len) <= stop); 7053 7054 pos += len; //consume size 7055 7056 if (id == 0x20) //BlockGroup ID 7057 return true; 7058 7059 if (id == 0x23) //SimpleBlock ID 7060 return true; 7061 7062 pos += size; //consume payload 7063 assert(pos <= stop); 7064 } 7065 7066 return false; 7067 } 7068 #endif 7069 7070 7071 long Cluster::HasBlockEntries( 7072 const Segment* pSegment, 7073 long long off, //relative to start of segment payload 7074 long long& pos, 7075 long& len) 7076 { 7077 assert(pSegment); 7078 assert(off >= 0); //relative to segment 7079 7080 IMkvReader* const pReader = pSegment->m_pReader; 7081 7082 long long total, avail; 7083 7084 long status = pReader->Length(&total, &avail); 7085 7086 if (status < 0) //error 7087 return status; 7088 7089 assert((total < 0) || (avail <= total)); 7090 7091 pos = pSegment->m_start + off; //absolute 7092 7093 if ((total >= 0) && (pos >= total)) 7094 return 0; //we don't even have a complete cluster 7095 7096 const long long segment_stop = 7097 (pSegment->m_size < 0) ? -1 : pSegment->m_start + pSegment->m_size; 7098 7099 long long cluster_stop = -1; //interpreted later to mean "unknown size" 7100 7101 { 7102 if ((pos + 1) > avail) 7103 { 7104 len = 1; 7105 return E_BUFFER_NOT_FULL; 7106 } 7107 7108 long long result = GetUIntLength(pReader, pos, len); 7109 7110 if (result < 0) //error 7111 return static_cast<long>(result); 7112 7113 if (result > 0) //need more data 7114 return E_BUFFER_NOT_FULL; 7115 7116 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 7117 return E_FILE_FORMAT_INVALID; 7118 7119 if ((total >= 0) && ((pos + len) > total)) 7120 return 0; 7121 7122 if ((pos + len) > avail) 7123 return E_BUFFER_NOT_FULL; 7124 7125 const long long id = ReadUInt(pReader, pos, len); 7126 7127 if (id < 0) //error 7128 return static_cast<long>(id); 7129 7130 if (id != 0x0F43B675) //weird: not cluster ID 7131 return -1; //generic error 7132 7133 pos += len; //consume Cluster ID field 7134 7135 //read size field 7136 7137 if ((pos + 1) > avail) 7138 { 7139 len = 1; 7140 return E_BUFFER_NOT_FULL; 7141 } 7142 7143 result = GetUIntLength(pReader, pos, len); 7144 7145 if (result < 0) //error 7146 return static_cast<long>(result); 7147 7148 if (result > 0) //weird 7149 return E_BUFFER_NOT_FULL; 7150 7151 if ((segment_stop >= 0) && ((pos + len) > segment_stop)) 7152 return E_FILE_FORMAT_INVALID; 7153 7154 if ((total >= 0) && ((pos + len) > total)) 7155 return 0; 7156 7157 if ((pos + len) > avail) 7158 return E_BUFFER_NOT_FULL; 7159 7160 const long long size = ReadUInt(pReader, pos, len); 7161 7162 if (size < 0) //error 7163 return static_cast<long>(size); 7164 7165 if (size == 0) 7166 return 0; //cluster does not have entries 7167 7168 pos += len; //consume size field 7169 7170 //pos now points to start of payload 7171 7172 const long long unknown_size = (1LL << (7 * len)) - 1; 7173 7174 if (size != unknown_size) 7175 { 7176 cluster_stop = pos + size; 7177 assert(cluster_stop >= 0); 7178 7179 if ((segment_stop >= 0) && (cluster_stop > segment_stop)) 7180 return E_FILE_FORMAT_INVALID; 7181 7182 if ((total >= 0) && (cluster_stop > total)) 7183 //return E_FILE_FORMAT_INVALID; //too conservative 7184 return 0; //cluster does not have any entries 7185 } 7186 } 7187 7188 for (;;) 7189 { 7190 if ((cluster_stop >= 0) && (pos >= cluster_stop)) 7191 return 0; //no entries detected 7192 7193 if ((pos + 1) > avail) 7194 { 7195 len = 1; 7196 return E_BUFFER_NOT_FULL; 7197 } 7198 7199 long long result = GetUIntLength(pReader, pos, len); 7200 7201 if (result < 0) //error 7202 return static_cast<long>(result); 7203 7204 if (result > 0) //need more data 7205 return E_BUFFER_NOT_FULL; 7206 7207 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) 7208 return E_FILE_FORMAT_INVALID; 7209 7210 if ((pos + len) > avail) 7211 return E_BUFFER_NOT_FULL; 7212 7213 const long long id = ReadUInt(pReader, pos, len); 7214 7215 if (id < 0) //error 7216 return static_cast<long>(id); 7217 7218 //This is the distinguished set of ID's we use to determine 7219 //that we have exhausted the sub-element's inside the cluster 7220 //whose ID we parsed earlier. 7221 7222 if (id == 0x0F43B675) //Cluster ID 7223 return 0; //no entries found 7224 7225 if (id == 0x0C53BB6B) //Cues ID 7226 return 0; //no entries found 7227 7228 pos += len; //consume id field 7229 7230 if ((cluster_stop >= 0) && (pos >= cluster_stop)) 7231 return E_FILE_FORMAT_INVALID; 7232 7233 //read size field 7234 7235 if ((pos + 1) > avail) 7236 { 7237 len = 1; 7238 return E_BUFFER_NOT_FULL; 7239 } 7240 7241 result = GetUIntLength(pReader, pos, len); 7242 7243 if (result < 0) //error 7244 return static_cast<long>(result); 7245 7246 if (result > 0) //underflow 7247 return E_BUFFER_NOT_FULL; 7248 7249 if ((cluster_stop >= 0) && ((pos + len) > cluster_stop)) 7250 return E_FILE_FORMAT_INVALID; 7251 7252 if ((pos + len) > avail) 7253 return E_BUFFER_NOT_FULL; 7254 7255 const long long size = ReadUInt(pReader, pos, len); 7256 7257 if (size < 0) //error 7258 return static_cast<long>(size); 7259 7260 pos += len; //consume size field 7261 7262 //pos now points to start of payload 7263 7264 if ((cluster_stop >= 0) && (pos > cluster_stop)) 7265 return E_FILE_FORMAT_INVALID; 7266 7267 if (size == 0) //weird 7268 continue; 7269 7270 const long long unknown_size = (1LL << (7 * len)) - 1; 7271 7272 if (size == unknown_size) 7273 return E_FILE_FORMAT_INVALID; //not supported inside cluster 7274 7275 if ((cluster_stop >= 0) && ((pos + size) > cluster_stop)) 7276 return E_FILE_FORMAT_INVALID; 7277 7278 if (id == 0x20) //BlockGroup ID 7279 return 1; //have at least one entry 7280 7281 if (id == 0x23) //SimpleBlock ID 7282 return 1; //have at least one entry 7283 7284 pos += size; //consume payload 7285 assert((cluster_stop < 0) || (pos <= cluster_stop)); 7286 } 7287 } 7288 7289 7290 long long Cluster::GetTimeCode() const 7291 { 7292 long long pos; 7293 long len; 7294 7295 const long status = Load(pos, len); 7296 7297 if (status < 0) //error 7298 return status; 7299 7300 return m_timecode; 7301 } 7302 7303 7304 long long Cluster::GetTime() const 7305 { 7306 const long long tc = GetTimeCode(); 7307 7308 if (tc < 0) 7309 return tc; 7310 7311 const SegmentInfo* const pInfo = m_pSegment->GetInfo(); 7312 assert(pInfo); 7313 7314 const long long scale = pInfo->GetTimeCodeScale(); 7315 assert(scale >= 1); 7316 7317 const long long t = m_timecode * scale; 7318 7319 return t; 7320 } 7321 7322 7323 long long Cluster::GetFirstTime() const 7324 { 7325 const BlockEntry* pEntry; 7326 7327 const long status = GetFirst(pEntry); 7328 7329 if (status < 0) //error 7330 return status; 7331 7332 if (pEntry == NULL) //empty cluster 7333 return GetTime(); 7334 7335 const Block* const pBlock = pEntry->GetBlock(); 7336 assert(pBlock); 7337 7338 return pBlock->GetTime(this); 7339 } 7340 7341 7342 long long Cluster::GetLastTime() const 7343 { 7344 const BlockEntry* pEntry; 7345 7346 const long status = GetLast(pEntry); 7347 7348 if (status < 0) //error 7349 return status; 7350 7351 if (pEntry == NULL) //empty cluster 7352 return GetTime(); 7353 7354 const Block* const pBlock = pEntry->GetBlock(); 7355 assert(pBlock); 7356 7357 return pBlock->GetTime(this); 7358 } 7359 7360 7361 long Cluster::CreateBlock( 7362 long long id, 7363 long long pos, //absolute pos of payload 7364 long long size) 7365 { 7366 assert((id == 0x20) || (id == 0x23)); //BlockGroup or SimpleBlock 7367 7368 if (m_entries_count < 0) //haven't parsed anything yet 7369 { 7370 assert(m_entries == NULL); 7371 assert(m_entries_size == 0); 7372 7373 m_entries_size = 1024; 7374 m_entries = new BlockEntry*[m_entries_size]; 7375 7376 m_entries_count = 0; 7377 } 7378 else 7379 { 7380 assert(m_entries); 7381 assert(m_entries_size > 0); 7382 assert(m_entries_count <= m_entries_size); 7383 7384 if (m_entries_count >= m_entries_size) 7385 { 7386 const long entries_size = 2 * m_entries_size; 7387 7388 BlockEntry** const entries = new BlockEntry*[entries_size]; 7389 assert(entries); 7390 7391 BlockEntry** src = m_entries; 7392 BlockEntry** const src_end = src + m_entries_count; 7393 7394 BlockEntry** dst = entries; 7395 7396 while (src != src_end) 7397 *dst++ = *src++; 7398 7399 delete[] m_entries; 7400 7401 m_entries = entries; 7402 m_entries_size = entries_size; 7403 } 7404 } 7405 7406 if (id == 0x20) //BlockGroup ID 7407 return CreateBlockGroup(pos, size); 7408 else //SimpleBlock ID 7409 return CreateSimpleBlock(pos, size); 7410 } 7411 7412 7413 long Cluster::CreateBlockGroup( 7414 long long st, 7415 long long sz) 7416 { 7417 assert(m_entries); 7418 assert(m_entries_size > 0); 7419 assert(m_entries_count >= 0); 7420 assert(m_entries_count < m_entries_size); 7421 7422 IMkvReader* const pReader = m_pSegment->m_pReader; 7423 7424 long long pos = st; 7425 const long long stop = st + sz; 7426 7427 //For WebM files, there is a bias towards previous reference times 7428 //(in order to support alt-ref frames, which refer back to the previous 7429 //keyframe). Normally a 0 value is not possible, but here we tenatively 7430 //allow 0 as the value of a reference frame, with the interpretation 7431 //that this is a "previous" reference time. 7432 7433 long long prev = 1; //nonce 7434 long long next = 0; //nonce 7435 long long duration = -1; //really, this is unsigned 7436 7437 long long bpos = -1; 7438 long long bsize = -1; 7439 7440 while (pos < stop) 7441 { 7442 long len; 7443 const long long id = ReadUInt(pReader, pos, len); 7444 assert(id >= 0); //TODO 7445 assert((pos + len) <= stop); 7446 7447 pos += len; //consume ID 7448 7449 const long long size = ReadUInt(pReader, pos, len); 7450 assert(size >= 0); //TODO 7451 assert((pos + len) <= stop); 7452 7453 pos += len; //consume size 7454 7455 if (id == 0x21) //Block ID 7456 { 7457 if (bpos < 0) //Block ID 7458 { 7459 bpos = pos; 7460 bsize = size; 7461 } 7462 } 7463 else if (id == 0x1B) //Duration ID 7464 { 7465 assert(size <= 8); 7466 7467 duration = UnserializeUInt(pReader, pos, size); 7468 assert(duration >= 0); //TODO 7469 } 7470 else if (id == 0x7B) //ReferenceBlock 7471 { 7472 assert(size <= 8); 7473 const long size_ = static_cast<long>(size); 7474 7475 long long time; 7476 7477 long status = UnserializeInt(pReader, pos, size_, time); 7478 assert(status == 0); //TODO 7479 7480 if (time <= 0) //see note above 7481 prev = time; 7482 else //weird 7483 next = time; 7484 } 7485 7486 pos += size; //consume payload 7487 assert(pos <= stop); 7488 } 7489 7490 assert(pos == stop); 7491 assert(bpos >= 0); 7492 assert(bsize >= 0); 7493 7494 const long idx = m_entries_count; 7495 7496 BlockEntry** const ppEntry = m_entries + idx; 7497 BlockEntry*& pEntry = *ppEntry; 7498 7499 pEntry = new (std::nothrow) BlockGroup( 7500 this, 7501 idx, 7502 bpos, 7503 bsize, 7504 prev, 7505 next, 7506 duration); 7507 7508 if (pEntry == NULL) 7509 return -1; //generic error 7510 7511 BlockGroup* const p = static_cast<BlockGroup*>(pEntry); 7512 7513 const long status = p->Parse(); 7514 7515 if (status == 0) //success 7516 { 7517 ++m_entries_count; 7518 return 0; 7519 } 7520 7521 delete pEntry; 7522 pEntry = 0; 7523 7524 return status; 7525 } 7526 7527 7528 7529 long Cluster::CreateSimpleBlock( 7530 long long st, 7531 long long sz) 7532 { 7533 assert(m_entries); 7534 assert(m_entries_size > 0); 7535 assert(m_entries_count >= 0); 7536 assert(m_entries_count < m_entries_size); 7537 7538 const long idx = m_entries_count; 7539 7540 BlockEntry** const ppEntry = m_entries + idx; 7541 BlockEntry*& pEntry = *ppEntry; 7542 7543 pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz); 7544 7545 if (pEntry == NULL) 7546 return -1; //generic error 7547 7548 SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry); 7549 7550 const long status = p->Parse(); 7551 7552 if (status == 0) 7553 { 7554 ++m_entries_count; 7555 return 0; 7556 } 7557 7558 delete pEntry; 7559 pEntry = 0; 7560 7561 return status; 7562 } 7563 7564 7565 long Cluster::GetFirst(const BlockEntry*& pFirst) const 7566 { 7567 if (m_entries_count <= 0) 7568 { 7569 long long pos; 7570 long len; 7571 7572 const long status = Parse(pos, len); 7573 7574 if (status < 0) //error 7575 { 7576 pFirst = NULL; 7577 return status; 7578 } 7579 7580 if (m_entries_count <= 0) //empty cluster 7581 { 7582 pFirst = NULL; 7583 return 0; 7584 } 7585 } 7586 7587 assert(m_entries); 7588 7589 pFirst = m_entries[0]; 7590 assert(pFirst); 7591 7592 return 0; //success 7593 } 7594 7595 long Cluster::GetLast(const BlockEntry*& pLast) const 7596 { 7597 for (;;) 7598 { 7599 long long pos; 7600 long len; 7601 7602 const long status = Parse(pos, len); 7603 7604 if (status < 0) //error 7605 { 7606 pLast = NULL; 7607 return status; 7608 } 7609 7610 if (status > 0) //no new block 7611 break; 7612 } 7613 7614 if (m_entries_count <= 0) 7615 { 7616 pLast = NULL; 7617 return 0; 7618 } 7619 7620 assert(m_entries); 7621 7622 const long idx = m_entries_count - 1; 7623 7624 pLast = m_entries[idx]; 7625 assert(pLast); 7626 7627 return 0; 7628 } 7629 7630 7631 long Cluster::GetNext( 7632 const BlockEntry* pCurr, 7633 const BlockEntry*& pNext) const 7634 { 7635 assert(pCurr); 7636 assert(m_entries); 7637 assert(m_entries_count > 0); 7638 7639 size_t idx = pCurr->GetIndex(); 7640 assert(idx < size_t(m_entries_count)); 7641 assert(m_entries[idx] == pCurr); 7642 7643 ++idx; 7644 7645 if (idx >= size_t(m_entries_count)) 7646 { 7647 long long pos; 7648 long len; 7649 7650 const long status = Parse(pos, len); 7651 7652 if (status < 0) //error 7653 { 7654 pNext = NULL; 7655 return status; 7656 } 7657 7658 if (status > 0) 7659 { 7660 pNext = NULL; 7661 return 0; 7662 } 7663 7664 assert(m_entries); 7665 assert(m_entries_count > 0); 7666 assert(idx < size_t(m_entries_count)); 7667 } 7668 7669 pNext = m_entries[idx]; 7670 assert(pNext); 7671 7672 return 0; 7673 } 7674 7675 7676 long Cluster::GetEntryCount() const 7677 { 7678 return m_entries_count; 7679 } 7680 7681 7682 const BlockEntry* Cluster::GetEntry( 7683 const Track* pTrack, 7684 long long time_ns) const 7685 { 7686 assert(pTrack); 7687 7688 if (m_pSegment == NULL) //this is the special EOS cluster 7689 return pTrack->GetEOS(); 7690 7691 #if 0 7692 7693 LoadBlockEntries(); 7694 7695 if ((m_entries == NULL) || (m_entries_count <= 0)) 7696 return NULL; //return EOS here? 7697 7698 const BlockEntry* pResult = pTrack->GetEOS(); 7699 7700 BlockEntry** i = m_entries; 7701 assert(i); 7702 7703 BlockEntry** const j = i + m_entries_count; 7704 7705 while (i != j) 7706 { 7707 const BlockEntry* const pEntry = *i++; 7708 assert(pEntry); 7709 assert(!pEntry->EOS()); 7710 7711 const Block* const pBlock = pEntry->GetBlock(); 7712 assert(pBlock); 7713 7714 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) 7715 continue; 7716 7717 if (pTrack->VetEntry(pEntry)) 7718 { 7719 if (time_ns < 0) //just want first candidate block 7720 return pEntry; 7721 7722 const long long ns = pBlock->GetTime(this); 7723 7724 if (ns > time_ns) 7725 break; 7726 7727 pResult = pEntry; 7728 } 7729 else if (time_ns >= 0) 7730 { 7731 const long long ns = pBlock->GetTime(this); 7732 7733 if (ns > time_ns) 7734 break; 7735 } 7736 } 7737 7738 return pResult; 7739 7740 #else 7741 7742 const BlockEntry* pResult = pTrack->GetEOS(); 7743 7744 long index = 0; 7745 7746 for (;;) 7747 { 7748 if (index >= m_entries_count) 7749 { 7750 long long pos; 7751 long len; 7752 7753 const long status = Parse(pos, len); 7754 assert(status >= 0); 7755 7756 if (status > 0) //completely parsed, and no more entries 7757 return pResult; 7758 7759 if (status < 0) //should never happen 7760 return 0; 7761 7762 assert(m_entries); 7763 assert(index < m_entries_count); 7764 } 7765 7766 const BlockEntry* const pEntry = m_entries[index]; 7767 assert(pEntry); 7768 assert(!pEntry->EOS()); 7769 7770 const Block* const pBlock = pEntry->GetBlock(); 7771 assert(pBlock); 7772 7773 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) 7774 { 7775 ++index; 7776 continue; 7777 } 7778 7779 if (pTrack->VetEntry(pEntry)) 7780 { 7781 if (time_ns < 0) //just want first candidate block 7782 return pEntry; 7783 7784 const long long ns = pBlock->GetTime(this); 7785 7786 if (ns > time_ns) 7787 return pResult; 7788 7789 pResult = pEntry; //have a candidate 7790 } 7791 else if (time_ns >= 0) 7792 { 7793 const long long ns = pBlock->GetTime(this); 7794 7795 if (ns > time_ns) 7796 return pResult; 7797 } 7798 7799 ++index; 7800 } 7801 7802 #endif 7803 } 7804 7805 7806 const BlockEntry* 7807 Cluster::GetEntry( 7808 const CuePoint& cp, 7809 const CuePoint::TrackPosition& tp) const 7810 { 7811 assert(m_pSegment); 7812 7813 #if 0 7814 7815 LoadBlockEntries(); 7816 7817 if (m_entries == NULL) 7818 return NULL; 7819 7820 const long long count = m_entries_count; 7821 7822 if (count <= 0) 7823 return NULL; 7824 7825 const long long tc = cp.GetTimeCode(); 7826 7827 if ((tp.m_block > 0) && (tp.m_block <= count)) 7828 { 7829 const size_t block = static_cast<size_t>(tp.m_block); 7830 const size_t index = block - 1; 7831 7832 const BlockEntry* const pEntry = m_entries[index]; 7833 assert(pEntry); 7834 assert(!pEntry->EOS()); 7835 7836 const Block* const pBlock = pEntry->GetBlock(); 7837 assert(pBlock); 7838 7839 if ((pBlock->GetTrackNumber() == tp.m_track) && 7840 (pBlock->GetTimeCode(this) == tc)) 7841 { 7842 return pEntry; 7843 } 7844 } 7845 7846 const BlockEntry* const* i = m_entries; 7847 const BlockEntry* const* const j = i + count; 7848 7849 while (i != j) 7850 { 7851 #ifdef _DEBUG 7852 const ptrdiff_t idx = i - m_entries; 7853 idx; 7854 #endif 7855 7856 const BlockEntry* const pEntry = *i++; 7857 assert(pEntry); 7858 assert(!pEntry->EOS()); 7859 7860 const Block* const pBlock = pEntry->GetBlock(); 7861 assert(pBlock); 7862 7863 if (pBlock->GetTrackNumber() != tp.m_track) 7864 continue; 7865 7866 const long long tc_ = pBlock->GetTimeCode(this); 7867 assert(tc_ >= 0); 7868 7869 if (tc_ < tc) 7870 continue; 7871 7872 if (tc_ > tc) 7873 return NULL; 7874 7875 const Tracks* const pTracks = m_pSegment->GetTracks(); 7876 assert(pTracks); 7877 7878 const long tn = static_cast<long>(tp.m_track); 7879 const Track* const pTrack = pTracks->GetTrackByNumber(tn); 7880 7881 if (pTrack == NULL) 7882 return NULL; 7883 7884 const long long type = pTrack->GetType(); 7885 7886 if (type == 2) //audio 7887 return pEntry; 7888 7889 if (type != 1) //not video 7890 return NULL; 7891 7892 if (!pBlock->IsKey()) 7893 return NULL; 7894 7895 return pEntry; 7896 } 7897 7898 return NULL; 7899 7900 #else 7901 7902 const long long tc = cp.GetTimeCode(); 7903 7904 if (tp.m_block > 0) 7905 { 7906 const long block = static_cast<long>(tp.m_block); 7907 const long index = block - 1; 7908 7909 while (index >= m_entries_count) 7910 { 7911 long long pos; 7912 long len; 7913 7914 const long status = Parse(pos, len); 7915 7916 if (status < 0) //TODO: can this happen? 7917 return NULL; 7918 7919 if (status > 0) //nothing remains to be parsed 7920 return NULL; 7921 } 7922 7923 const BlockEntry* const pEntry = m_entries[index]; 7924 assert(pEntry); 7925 assert(!pEntry->EOS()); 7926 7927 const Block* const pBlock = pEntry->GetBlock(); 7928 assert(pBlock); 7929 7930 if ((pBlock->GetTrackNumber() == tp.m_track) && 7931 (pBlock->GetTimeCode(this) == tc)) 7932 { 7933 return pEntry; 7934 } 7935 } 7936 7937 long index = 0; 7938 7939 for (;;) 7940 { 7941 if (index >= m_entries_count) 7942 { 7943 long long pos; 7944 long len; 7945 7946 const long status = Parse(pos, len); 7947 7948 if (status < 0) //TODO: can this happen? 7949 return NULL; 7950 7951 if (status > 0) //nothing remains to be parsed 7952 return NULL; 7953 7954 assert(m_entries); 7955 assert(index < m_entries_count); 7956 } 7957 7958 const BlockEntry* const pEntry = m_entries[index]; 7959 assert(pEntry); 7960 assert(!pEntry->EOS()); 7961 7962 const Block* const pBlock = pEntry->GetBlock(); 7963 assert(pBlock); 7964 7965 if (pBlock->GetTrackNumber() != tp.m_track) 7966 { 7967 ++index; 7968 continue; 7969 } 7970 7971 const long long tc_ = pBlock->GetTimeCode(this); 7972 assert(tc_ >= 0); 7973 7974 if (tc_ < tc) 7975 { 7976 ++index; 7977 continue; 7978 } 7979 7980 if (tc_ > tc) 7981 return NULL; 7982 7983 const Tracks* const pTracks = m_pSegment->GetTracks(); 7984 assert(pTracks); 7985 7986 const long tn = static_cast<long>(tp.m_track); 7987 const Track* const pTrack = pTracks->GetTrackByNumber(tn); 7988 7989 if (pTrack == NULL) 7990 return NULL; 7991 7992 const long long type = pTrack->GetType(); 7993 7994 if (type == 2) //audio 7995 return pEntry; 7996 7997 if (type != 1) //not video 7998 return NULL; 7999 8000 if (!pBlock->IsKey()) 8001 return NULL; 8002 8003 return pEntry; 8004 } 8005 8006 #endif 8007 8008 } 8009 8010 8011 #if 0 8012 const BlockEntry* Cluster::GetMaxKey(const VideoTrack* pTrack) const 8013 { 8014 assert(pTrack); 8015 8016 if (m_pSegment == NULL) //EOS 8017 return pTrack->GetEOS(); 8018 8019 LoadBlockEntries(); 8020 8021 if ((m_entries == NULL) || (m_entries_count <= 0)) 8022 return pTrack->GetEOS(); 8023 8024 BlockEntry** i = m_entries + m_entries_count; 8025 BlockEntry** const j = m_entries; 8026 8027 while (i != j) 8028 { 8029 const BlockEntry* const pEntry = *--i; 8030 assert(pEntry); 8031 assert(!pEntry->EOS()); 8032 8033 const Block* const pBlock = pEntry->GetBlock(); 8034 assert(pBlock); 8035 8036 if (pBlock->GetTrackNumber() != pTrack->GetNumber()) 8037 continue; 8038 8039 if (pBlock->IsKey()) 8040 return pEntry; 8041 } 8042 8043 return pTrack->GetEOS(); //no satisfactory block found 8044 } 8045 #endif 8046 8047 8048 BlockEntry::BlockEntry(Cluster* p, long idx) : 8049 m_pCluster(p), 8050 m_index(idx) 8051 { 8052 } 8053 8054 8055 BlockEntry::~BlockEntry() 8056 { 8057 } 8058 8059 8060 bool BlockEntry::EOS() const 8061 { 8062 return (GetKind() == kBlockEOS); 8063 } 8064 8065 8066 const Cluster* BlockEntry::GetCluster() const 8067 { 8068 return m_pCluster; 8069 } 8070 8071 8072 long BlockEntry::GetIndex() const 8073 { 8074 return m_index; 8075 } 8076 8077 8078 SimpleBlock::SimpleBlock( 8079 Cluster* pCluster, 8080 long idx, 8081 long long start, 8082 long long size) : 8083 BlockEntry(pCluster, idx), 8084 m_block(start, size) 8085 { 8086 } 8087 8088 8089 long SimpleBlock::Parse() 8090 { 8091 return m_block.Parse(m_pCluster->m_pSegment->m_pReader); 8092 } 8093 8094 8095 BlockEntry::Kind SimpleBlock::GetKind() const 8096 { 8097 return kBlockSimple; 8098 } 8099 8100 8101 const Block* SimpleBlock::GetBlock() const 8102 { 8103 return &m_block; 8104 } 8105 8106 8107 BlockGroup::BlockGroup( 8108 Cluster* pCluster, 8109 long idx, 8110 long long block_start, 8111 long long block_size, 8112 long long prev, 8113 long long next, 8114 long long duration) : 8115 BlockEntry(pCluster, idx), 8116 m_block(block_start, block_size), 8117 m_prev(prev), 8118 m_next(next), 8119 m_duration(duration) 8120 { 8121 } 8122 8123 8124 long BlockGroup::Parse() 8125 { 8126 const long status = m_block.Parse(m_pCluster->m_pSegment->m_pReader); 8127 8128 if (status) 8129 return status; 8130 8131 m_block.SetKey((m_prev > 0) && (m_next <= 0)); 8132 8133 return 0; 8134 } 8135 8136 8137 #if 0 8138 void BlockGroup::ParseBlock(long long start, long long size) 8139 { 8140 IMkvReader* const pReader = m_pCluster->m_pSegment->m_pReader; 8141 8142 Block* const pBlock = new Block(start, size, pReader); 8143 assert(pBlock); //TODO 8144 8145 //TODO: the Matroska spec says you have multiple blocks within the 8146 //same block group, with blocks ranked by priority (the flag bits). 8147 8148 assert(m_pBlock == NULL); 8149 m_pBlock = pBlock; 8150 } 8151 #endif 8152 8153 8154 BlockEntry::Kind BlockGroup::GetKind() const 8155 { 8156 return kBlockGroup; 8157 } 8158 8159 8160 const Block* BlockGroup::GetBlock() const 8161 { 8162 return &m_block; 8163 } 8164 8165 8166 long long BlockGroup::GetPrevTimeCode() const 8167 { 8168 return m_prev; 8169 } 8170 8171 8172 long long BlockGroup::GetNextTimeCode() const 8173 { 8174 return m_next; 8175 } 8176 8177 8178 Block::Block(long long start, long long size_) : 8179 m_start(start), 8180 m_size(size_), 8181 m_track(0), 8182 m_timecode(-1), 8183 m_flags(0), 8184 m_frames(NULL), 8185 m_frame_count(-1) 8186 { 8187 } 8188 8189 8190 Block::~Block() 8191 { 8192 delete[] m_frames; 8193 } 8194 8195 8196 long Block::Parse(IMkvReader* pReader) 8197 { 8198 assert(pReader); 8199 assert(m_start >= 0); 8200 assert(m_size >= 0); 8201 assert(m_track <= 0); 8202 assert(m_frames == NULL); 8203 assert(m_frame_count <= 0); 8204 8205 long long pos = m_start; 8206 const long long stop = m_start + m_size; 8207 8208 long len; 8209 8210 m_track = ReadUInt(pReader, pos, len); 8211 8212 if (m_track <= 0) 8213 return E_FILE_FORMAT_INVALID; 8214 8215 if ((pos + len) > stop) 8216 return E_FILE_FORMAT_INVALID; 8217 8218 pos += len; //consume track number 8219 8220 if ((stop - pos) < 2) 8221 return E_FILE_FORMAT_INVALID; 8222 8223 long status; 8224 long long value; 8225 8226 status = UnserializeInt(pReader, pos, 2, value); 8227 8228 if (status) 8229 return E_FILE_FORMAT_INVALID; 8230 8231 if (value < SHRT_MIN) 8232 return E_FILE_FORMAT_INVALID; 8233 8234 if (value > SHRT_MAX) 8235 return E_FILE_FORMAT_INVALID; 8236 8237 m_timecode = static_cast<short>(value); 8238 8239 pos += 2; 8240 8241 if ((stop - pos) <= 0) 8242 return E_FILE_FORMAT_INVALID; 8243 8244 status = pReader->Read(pos, 1, &m_flags); 8245 8246 if (status) 8247 return E_FILE_FORMAT_INVALID; 8248 8249 const int lacing = int(m_flags & 0x06) >> 1; 8250 8251 ++pos; //consume flags byte 8252 8253 if (lacing == 0) //no lacing 8254 { 8255 if (pos > stop) 8256 return E_FILE_FORMAT_INVALID; 8257 8258 m_frame_count = 1; 8259 m_frames = new Frame[m_frame_count]; 8260 8261 Frame& f = m_frames[0]; 8262 f.pos = pos; 8263 8264 const long long frame_size = stop - pos; 8265 8266 if (frame_size > LONG_MAX) 8267 return E_FILE_FORMAT_INVALID; 8268 8269 f.len = static_cast<long>(frame_size); 8270 8271 return 0; //success 8272 } 8273 8274 if (pos >= stop) 8275 return E_FILE_FORMAT_INVALID; 8276 8277 unsigned char biased_count; 8278 8279 status = pReader->Read(pos, 1, &biased_count); 8280 8281 if (status) 8282 return E_FILE_FORMAT_INVALID; 8283 8284 ++pos; //consume frame count 8285 assert(pos <= stop); 8286 8287 m_frame_count = int(biased_count) + 1; 8288 8289 m_frames = new Frame[m_frame_count]; 8290 assert(m_frames); 8291 8292 if (lacing == 1) //Xiph 8293 { 8294 Frame* pf = m_frames; 8295 Frame* const pf_end = pf + m_frame_count; 8296 8297 long size = 0; 8298 int frame_count = m_frame_count; 8299 8300 while (frame_count > 1) 8301 { 8302 long frame_size = 0; 8303 8304 for (;;) 8305 { 8306 unsigned char val; 8307 8308 if (pos >= stop) 8309 return E_FILE_FORMAT_INVALID; 8310 8311 status = pReader->Read(pos, 1, &val); 8312 8313 if (status) 8314 return E_FILE_FORMAT_INVALID; 8315 8316 ++pos; //consume xiph size byte 8317 8318 frame_size += val; 8319 8320 if (val < 255) 8321 break; 8322 } 8323 8324 Frame& f = *pf++; 8325 assert(pf < pf_end); 8326 8327 f.pos = 0; //patch later 8328 8329 f.len = frame_size; 8330 size += frame_size; //contribution of this frame 8331 8332 --frame_count; 8333 } 8334 8335 assert(pf < pf_end); 8336 assert(pos <= stop); 8337 8338 { 8339 Frame& f = *pf++; 8340 8341 if (pf != pf_end) 8342 return E_FILE_FORMAT_INVALID; 8343 8344 f.pos = 0; //patch later 8345 8346 const long long total_size = stop - pos; 8347 8348 if (total_size < size) 8349 return E_FILE_FORMAT_INVALID; 8350 8351 const long long frame_size = total_size - size; 8352 8353 if (frame_size > LONG_MAX) 8354 return E_FILE_FORMAT_INVALID; 8355 8356 f.len = static_cast<long>(frame_size); 8357 } 8358 8359 pf = m_frames; 8360 while (pf != pf_end) 8361 { 8362 Frame& f = *pf++; 8363 assert((pos + f.len) <= stop); 8364 8365 f.pos = pos; 8366 pos += f.len; 8367 } 8368 8369 assert(pos == stop); 8370 } 8371 else if (lacing == 2) //fixed-size lacing 8372 { 8373 const long long total_size = stop - pos; 8374 8375 if ((total_size % m_frame_count) != 0) 8376 return E_FILE_FORMAT_INVALID; 8377 8378 const long long frame_size = total_size / m_frame_count; 8379 8380 if (frame_size > LONG_MAX) 8381 return E_FILE_FORMAT_INVALID; 8382 8383 Frame* pf = m_frames; 8384 Frame* const pf_end = pf + m_frame_count; 8385 8386 while (pf != pf_end) 8387 { 8388 assert((pos + frame_size) <= stop); 8389 8390 Frame& f = *pf++; 8391 8392 f.pos = pos; 8393 f.len = static_cast<long>(frame_size); 8394 8395 pos += frame_size; 8396 } 8397 8398 assert(pos == stop); 8399 } 8400 else 8401 { 8402 assert(lacing == 3); //EBML lacing 8403 8404 if (pos >= stop) 8405 return E_FILE_FORMAT_INVALID; 8406 8407 long size = 0; 8408 int frame_count = m_frame_count; 8409 8410 long long frame_size = ReadUInt(pReader, pos, len); 8411 8412 if (frame_size < 0) 8413 return E_FILE_FORMAT_INVALID; 8414 8415 if (frame_size > LONG_MAX) 8416 return E_FILE_FORMAT_INVALID; 8417 8418 if ((pos + len) > stop) 8419 return E_FILE_FORMAT_INVALID; 8420 8421 pos += len; //consume length of size of first frame 8422 8423 if ((pos + frame_size) > stop) 8424 return E_FILE_FORMAT_INVALID; 8425 8426 Frame* pf = m_frames; 8427 Frame* const pf_end = pf + m_frame_count; 8428 8429 { 8430 Frame& curr = *pf; 8431 8432 curr.pos = 0; //patch later 8433 8434 curr.len = static_cast<long>(frame_size); 8435 size += curr.len; //contribution of this frame 8436 } 8437 8438 --frame_count; 8439 8440 while (frame_count > 1) 8441 { 8442 if (pos >= stop) 8443 return E_FILE_FORMAT_INVALID; 8444 8445 assert(pf < pf_end); 8446 8447 const Frame& prev = *pf++; 8448 assert(prev.len == frame_size); 8449 8450 assert(pf < pf_end); 8451 8452 Frame& curr = *pf; 8453 8454 curr.pos = 0; //patch later 8455 8456 const long long delta_size_ = ReadUInt(pReader, pos, len); 8457 8458 if (delta_size_ < 0) 8459 return E_FILE_FORMAT_INVALID; 8460 8461 if ((pos + len) > stop) 8462 return E_FILE_FORMAT_INVALID; 8463 8464 pos += len; //consume length of (delta) size 8465 assert(pos <= stop); 8466 8467 const int exp = 7*len - 1; 8468 const long long bias = (1LL << exp) - 1LL; 8469 const long long delta_size = delta_size_ - bias; 8470 8471 frame_size += delta_size; 8472 8473 if (frame_size < 0) 8474 return E_FILE_FORMAT_INVALID; 8475 8476 if (frame_size > LONG_MAX) 8477 return E_FILE_FORMAT_INVALID; 8478 8479 curr.len = static_cast<long>(frame_size); 8480 size += curr.len; //contribution of this frame 8481 8482 --frame_count; 8483 } 8484 8485 { 8486 assert(pos <= stop); 8487 assert(pf < pf_end); 8488 8489 const Frame& prev = *pf++; 8490 assert(prev.len == frame_size); 8491 8492 assert(pf < pf_end); 8493 8494 Frame& curr = *pf++; 8495 assert(pf == pf_end); 8496 8497 curr.pos = 0; //patch later 8498 8499 const long long total_size = stop - pos; 8500 8501 if (total_size < size) 8502 return E_FILE_FORMAT_INVALID; 8503 8504 frame_size = total_size - size; 8505 8506 if (frame_size > LONG_MAX) 8507 return E_FILE_FORMAT_INVALID; 8508 8509 curr.len = static_cast<long>(frame_size); 8510 } 8511 8512 pf = m_frames; 8513 while (pf != pf_end) 8514 { 8515 Frame& f = *pf++; 8516 assert((pos + f.len) <= stop); 8517 8518 f.pos = pos; 8519 pos += f.len; 8520 } 8521 8522 assert(pos == stop); 8523 } 8524 8525 return 0; //success 8526 } 8527 8528 8529 long long Block::GetTimeCode(const Cluster* pCluster) const 8530 { 8531 if (pCluster == 0) 8532 return m_timecode; 8533 8534 const long long tc0 = pCluster->GetTimeCode(); 8535 assert(tc0 >= 0); 8536 8537 const long long tc = tc0 + m_timecode; 8538 assert(tc >= 0); 8539 8540 return tc; //unscaled timecode units 8541 } 8542 8543 8544 long long Block::GetTime(const Cluster* pCluster) const 8545 { 8546 assert(pCluster); 8547 8548 const long long tc = GetTimeCode(pCluster); 8549 8550 const Segment* const pSegment = pCluster->m_pSegment; 8551 const SegmentInfo* const pInfo = pSegment->GetInfo(); 8552 assert(pInfo); 8553 8554 const long long scale = pInfo->GetTimeCodeScale(); 8555 assert(scale >= 1); 8556 8557 const long long ns = tc * scale; 8558 8559 return ns; 8560 } 8561 8562 8563 long long Block::GetTrackNumber() const 8564 { 8565 return m_track; 8566 } 8567 8568 8569 bool Block::IsKey() const 8570 { 8571 return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0); 8572 } 8573 8574 8575 void Block::SetKey(bool bKey) 8576 { 8577 if (bKey) 8578 m_flags |= static_cast<unsigned char>(1 << 7); 8579 else 8580 m_flags &= 0x7F; 8581 } 8582 8583 8584 bool Block::IsInvisible() const 8585 { 8586 return bool(int(m_flags & 0x08) != 0); 8587 } 8588 8589 8590 Block::Lacing Block::GetLacing() const 8591 { 8592 const int value = int(m_flags & 0x06) >> 1; 8593 return static_cast<Lacing>(value); 8594 } 8595 8596 8597 int Block::GetFrameCount() const 8598 { 8599 return m_frame_count; 8600 } 8601 8602 8603 const Block::Frame& Block::GetFrame(int idx) const 8604 { 8605 assert(idx >= 0); 8606 assert(idx < m_frame_count); 8607 8608 const Frame& f = m_frames[idx]; 8609 assert(f.pos > 0); 8610 assert(f.len > 0); 8611 8612 return f; 8613 } 8614 8615 8616 long Block::Frame::Read(IMkvReader* pReader, unsigned char* buf) const 8617 { 8618 assert(pReader); 8619 assert(buf); 8620 8621 const long status = pReader->Read(pos, len, buf); 8622 return status; 8623 } 8624 8625 8626 } //end namespace mkvparser 8627