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