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