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