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