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